You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by xy...@apache.org on 2023/10/05 21:47:31 UTC

[helix] 01/04: MetaClientCache Part 1 - API's, configs, and builders (#2612)

This is an automated email from the ASF dual-hosted git repository.

xyuanlu pushed a commit to branch metaclient
in repository https://gitbox.apache.org/repos/asf/helix.git

commit a6252856b14c8e7164cd4d70da2ebfd72218472b
Author: Marcos Rico Peng <55...@users.noreply.github.com>
AuthorDate: Tue Sep 12 22:24:22 2023 +0200

    MetaClientCache Part 1 - API's, configs, and builders (#2612)
    
    MetaClientCache Part 1 - API's, configs, and builders
    
    ---------
    
    Co-authored-by: mapeng <ma...@linkedin.com>
---
 .../metaclient/api/MetaClientCacheInterface.java   | 61 ++++++++++++++
 .../MetaClientCacheConfig.java}                    | 43 ++++++----
 .../metaclient/factories/MetaClientFactory.java    | 17 ++++
 .../metaclient/impl/zk/ZkMetaClientCache.java      | 94 ++++++++++++++++++++++
 .../impl/zk/factory/ZkMetaClientFactory.java       | 15 ++++
 .../metaclient/impl/zk/TestZkMetaClientCache.java  | 57 +++++++++++++
 6 files changed, 272 insertions(+), 15 deletions(-)

diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientCacheInterface.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientCacheInterface.java
new file mode 100644
index 000000000..348bd0929
--- /dev/null
+++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientCacheInterface.java
@@ -0,0 +1,61 @@
+package org.apache.helix.metaclient.api;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+public interface MetaClientCacheInterface<T> extends MetaClientInterface<T> {
+
+    /**
+     * TrieNode class to store the children of the entries to be cached.
+     */
+    class TrieNode {
+        // A mapping between trie key and children nodes.
+        private Map<String, TrieNode> _children;
+
+        // the complete path/prefix leading to the current node.
+        private final String _path;
+
+        private final String _nodeKey;
+
+        TrieNode(String path, String nodeKey) {
+            _path = path;
+            _nodeKey = nodeKey;
+            _children = new HashMap<>();
+        }
+
+        public Map<String, TrieNode> getChildren() {
+            return _children;
+        }
+
+        public String getPath() {
+            return _path;
+        }
+
+        public String getNodeKey() {
+            return _nodeKey;
+        }
+
+        public void addChild(String key,  TrieNode node) {
+            _children.put(key, node);
+        }
+    }
+}
diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientCacheConfig.java
similarity index 50%
copy from meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java
copy to meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientCacheConfig.java
index 9eba28b91..9e0323601 100644
--- a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java
+++ b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientCacheConfig.java
@@ -1,4 +1,4 @@
-package org.apache.helix.metaclient.impl.zk.factory;
+package org.apache.helix.metaclient.factories;
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,21 +19,34 @@ package org.apache.helix.metaclient.impl.zk.factory;
  * under the License.
  */
 
-import org.apache.helix.metaclient.api.MetaClientInterface;
-import org.apache.helix.metaclient.factories.MetaClientConfig;
-import org.apache.helix.metaclient.factories.MetaClientFactory;
-import org.apache.helix.metaclient.impl.zk.ZkMetaClient;
 
-public class ZkMetaClientFactory extends MetaClientFactory {
-  @Override
-  public MetaClientInterface getMetaClient(MetaClientConfig config) {
-    if (config == null) {
-      throw new IllegalArgumentException("MetaClientConfig cannot be null.");
+
+public class MetaClientCacheConfig {
+    private final String _rootEntry;
+    private boolean _cacheData = false;
+    private boolean _cacheChildren = false;
+    private boolean _lazyCaching = true;
+
+    public MetaClientCacheConfig(String rootEntry, boolean cacheData, boolean cacheChildren, boolean lazyCaching) {
+        _rootEntry = rootEntry;
+        _cacheData = cacheData;
+        _cacheChildren = cacheChildren;
+        _lazyCaching = lazyCaching;
     }
-    if (MetaClientConfig.StoreType.ZOOKEEPER.equals(config.getStoreType())
-        && config instanceof ZkMetaClientConfig) {
-      return new ZkMetaClient((ZkMetaClientConfig) config);
+
+    public String getRootEntry() {
+        return _rootEntry;
+    }
+
+    public boolean getCacheData() {
+        return _cacheData;
+    }
+
+    public boolean getCacheChildren() {
+        return _cacheChildren;
+    }
+
+    public boolean getLazyCaching() {
+        return _lazyCaching;
     }
-    throw new IllegalArgumentException("Invalid MetaClientConfig type.");
-  }
 }
diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java
index 045374332..ebb4549da 100644
--- a/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java
+++ b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java
@@ -20,6 +20,7 @@ package org.apache.helix.metaclient.factories;
  */
 
 
+import org.apache.helix.metaclient.api.MetaClientCacheInterface;
 import org.apache.helix.metaclient.api.MetaClientInterface;
 import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientConfig;
 import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientFactory;
@@ -49,4 +50,20 @@ public class MetaClientFactory {
     }
     return null;
   }
+
+  public MetaClientCacheInterface getMetaClientCache(MetaClientConfig config, MetaClientCacheConfig cacheConfig) {
+    if (config == null) {
+      throw new IllegalArgumentException("MetaClientConfig cannot be null.");
+    }
+    if (MetaClientConfig.StoreType.ZOOKEEPER.equals(config.getStoreType())) {
+      ZkMetaClientConfig zkMetaClientConfig = new ZkMetaClientConfig.ZkMetaClientConfigBuilder().
+              setConnectionAddress(config.getConnectionAddress())
+              .setMetaClientReconnectPolicy(config.getMetaClientReconnectPolicy())
+              .setConnectionInitTimeoutInMillis(config.getConnectionInitTimeoutInMillis())
+              .setSessionTimeoutInMillis(config.getSessionTimeoutInMillis())
+              .build();
+      return new ZkMetaClientFactory().getMetaClientCache(zkMetaClientConfig, cacheConfig);
+    }
+      return null;
+  }
 }
diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientCache.java b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientCache.java
new file mode 100644
index 000000000..af1c9d791
--- /dev/null
+++ b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientCache.java
@@ -0,0 +1,94 @@
+package org.apache.helix.metaclient.impl.zk;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import org.apache.helix.metaclient.api.ChildChangeListener;
+import org.apache.helix.metaclient.api.MetaClientCacheInterface;
+import org.apache.helix.metaclient.datamodel.DataRecord;
+import org.apache.helix.metaclient.exception.MetaClientException;
+import org.apache.helix.metaclient.factories.MetaClientCacheConfig;
+import org.apache.helix.metaclient.factories.MetaClientConfig;
+import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientConfig;
+import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientFactory;
+import org.apache.helix.metaclient.recipes.lock.LockInfoSerializer;
+import org.apache.helix.zookeeper.zkclient.ZkClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Map;
+
+public class ZkMetaClientCache<T> extends ZkMetaClient<T> implements MetaClientCacheInterface<T> {
+
+    private Map<String, DataRecord> _dataCacheMap;
+    private final String _rootEntry;
+    private TrieNode _childrenCacheTree;
+    private ChildChangeListener _eventListener;
+    private boolean _cacheData;
+    private boolean _cacheChildren;
+    private boolean _lazyCaching;
+    private static final Logger LOG = LoggerFactory.getLogger(ZkMetaClientCache.class);
+    private  ZkClient _cacheClient;
+
+    /**
+     * Constructor for ZkMetaClientCache.
+     * @param config ZkMetaClientConfig
+     * @param cacheConfig MetaClientCacheConfig
+     */
+    public ZkMetaClientCache(ZkMetaClientConfig config, MetaClientCacheConfig cacheConfig) {
+        super(config);
+        _cacheClient = getZkClient();
+        _rootEntry = cacheConfig.getRootEntry();
+        _lazyCaching = cacheConfig.getLazyCaching();
+        _cacheData = cacheConfig.getCacheData();
+        _cacheChildren = cacheConfig.getCacheChildren();
+    }
+
+    @Override
+    public Stat exists(String key) {
+        throw new MetaClientException("Not implemented yet.");
+    }
+
+    @Override
+    public T get(final String key) {
+        throw new MetaClientException("Not implemented yet.");
+    }
+
+    @Override
+    public List<String> getDirectChildrenKeys(final String key) {
+        throw new MetaClientException("Not implemented yet.");
+    }
+
+    @Override
+    public int countDirectChildren(final String key) {
+        throw new MetaClientException("Not implemented yet.");
+    }
+
+    @Override
+    public List<T> get(List<String> keys) {
+        throw new MetaClientException("Not implemented yet.");
+    }
+
+    @Override
+    public List<Stat> exists(List<String> keys) {
+        throw new MetaClientException("Not implemented yet.");
+    }
+
+}
diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java
index 9eba28b91..c4018eb2f 100644
--- a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java
+++ b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/factory/ZkMetaClientFactory.java
@@ -19,10 +19,13 @@ package org.apache.helix.metaclient.impl.zk.factory;
  * under the License.
  */
 
+import org.apache.helix.metaclient.api.MetaClientCacheInterface;
 import org.apache.helix.metaclient.api.MetaClientInterface;
+import org.apache.helix.metaclient.factories.MetaClientCacheConfig;
 import org.apache.helix.metaclient.factories.MetaClientConfig;
 import org.apache.helix.metaclient.factories.MetaClientFactory;
 import org.apache.helix.metaclient.impl.zk.ZkMetaClient;
+import org.apache.helix.metaclient.impl.zk.ZkMetaClientCache;
 
 public class ZkMetaClientFactory extends MetaClientFactory {
   @Override
@@ -36,4 +39,16 @@ public class ZkMetaClientFactory extends MetaClientFactory {
     }
     throw new IllegalArgumentException("Invalid MetaClientConfig type.");
   }
+
+  @Override
+  public MetaClientCacheInterface getMetaClientCache(MetaClientConfig config, MetaClientCacheConfig cacheConfig) {
+    if (config == null) {
+      throw new IllegalArgumentException("MetaClientConfig cannot be null.");
+    }
+    if (MetaClientConfig.StoreType.ZOOKEEPER.equals(config.getStoreType())
+            && config instanceof ZkMetaClientConfig) {
+      return new ZkMetaClientCache((ZkMetaClientConfig) config, cacheConfig);
+    }
+    throw new IllegalArgumentException("Invalid MetaClientConfig type.");
+  }
 }
diff --git a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClientCache.java b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClientCache.java
new file mode 100644
index 000000000..a3a5b4eee
--- /dev/null
+++ b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClientCache.java
@@ -0,0 +1,57 @@
+package org.apache.helix.metaclient.impl.zk;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+import org.apache.helix.metaclient.factories.MetaClientCacheConfig;
+import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientConfig;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+public class TestZkMetaClientCache extends ZkMetaClientTestBase {
+    private static final String PATH = "/Cache";
+
+    @Test
+    public void testCreateClient() {
+        final String key = "/TestZkMetaClientCache_testCreate";
+        try (ZkMetaClient<String> zkMetaClientCache = createZkMetaClientCache()) {
+            zkMetaClientCache.connect();
+            // Perform some random non-read operation
+            zkMetaClientCache.create(key, ENTRY_STRING_VALUE);
+
+            try {
+                //Perform some read operation - should fail.
+                // TODO: Remove this once implemented.
+                zkMetaClientCache.get(key);
+                Assert.fail("Should have failed with non implemented yet.");
+            } catch (Exception ignored) {
+            }
+        }
+    }
+
+    protected static ZkMetaClientCache<String> createZkMetaClientCache() {
+        ZkMetaClientConfig config =
+                new ZkMetaClientConfig.ZkMetaClientConfigBuilder().setConnectionAddress(ZK_ADDR)
+                        //.setZkSerializer(new TestStringSerializer())
+                        .build();
+        MetaClientCacheConfig cacheConfig = new MetaClientCacheConfig(PATH, true, true, true);
+        return new ZkMetaClientCache<>(config, cacheConfig);
+    }
+}