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 580b54ee5b1b3b6fdabcf9f59e981356379d28b7 Author: Marcos Rico Peng <[email protected]> AuthorDate: Tue Mar 14 14:40:34 2023 -0400 TTL Node Lattice Implementation (#2401) TTL Node Lattice Implementation --- .../helix/metaclient/api/MetaClientInterface.java | 3 +- .../helix/metaclient/impl/zk/ZkMetaClient.java | 16 ++++++-- .../metaclient/impl/zk/util/ZkMetaClientUtil.java | 9 ++--- .../helix/metaclient/impl/zk/TestZkMetaClient.java | 47 ++++++++++++++++++---- .../metaclient/impl/zk/ZkMetaClientTestBase.java | 2 + 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java index 7445a0d33..375c0814c 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java @@ -82,6 +82,7 @@ public interface MetaClientInterface<T> { /** * Interface representing the metadata of an entry. It contains entry type and version number. * TODO: we will add session ID to entry stats in the future + * TODO: Add support for expiry time */ class Stat { private final int _version; @@ -202,7 +203,7 @@ public interface MetaClientInterface<T> { /** * API for transaction. The list of operation will be executed as an atomic operation. - * @param ops a list of operations. These operations will all be executed or non of them. + * @param ops a list of operations. These operations will all be executed or none of them. * @return Return a list of OpResult. */ List<OpResult> transactionOP(final Iterable<Op> ops); diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java index d3542e1fa..2a9262208 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java @@ -34,6 +34,7 @@ import org.apache.helix.metaclient.api.MetaClientInterface; import org.apache.helix.metaclient.api.Op; import org.apache.helix.metaclient.api.OpResult; import org.apache.helix.metaclient.exception.MetaClientException; +import org.apache.helix.metaclient.exception.MetaClientNoNodeException; import org.apache.helix.metaclient.impl.zk.adapter.DataListenerAdapter; import org.apache.helix.metaclient.impl.zk.adapter.DirectChildListenerAdapter; import org.apache.helix.metaclient.impl.zk.adapter.StateChangeListenerAdapter; @@ -94,12 +95,20 @@ public class ZkMetaClient<T> implements MetaClientInterface<T>, AutoCloseable { @Override public void createWithTTL(String key, T data, long ttl) { - throw new UnsupportedOperationException("TTL nodes aren't yet supported."); + try{ + _zkClient.createPersistentWithTTL(key, data, ttl); + } catch (ZkException e) { + throw translateZkExceptionToMetaclientException(e); + } } @Override public void renewTTLNode(String key) { - throw new UnsupportedOperationException("TTL nodes aren't yet supported."); + T oldData = get(key); + if (oldData == null) { + throw new MetaClientNoNodeException("Node at " + key + " does not exist."); + } + set(key, oldData, _zkClient.getStat(key).getVersion()); } @Override @@ -125,6 +134,7 @@ public class ZkMetaClient<T> implements MetaClientInterface<T>, AutoCloseable { } } + //TODO: Get Expiry Time in Stat @Override public Stat exists(String key) { org.apache.zookeeper.data.Stat zkStats; @@ -134,7 +144,7 @@ public class ZkMetaClient<T> implements MetaClientInterface<T>, AutoCloseable { return null; } return new Stat(convertZkEntryModeToMetaClientEntryMode(zkStats.getEphemeralOwner()), - zkStats.getVersion()); + zkStats.getVersion(), zkStats.getCtime(), zkStats.getMtime(), -1); } catch (ZkException e) { throw translateZkExceptionToMetaclientException(e); } diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java index a9bee4cbb..f21a883f3 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/util/ZkMetaClientUtil.java @@ -37,7 +37,7 @@ import org.apache.helix.metaclient.exception.MetaClientTimeoutException; import org.apache.helix.zookeeper.zkclient.exception.ZkBadVersionException; import org.apache.helix.zookeeper.zkclient.exception.ZkException; import org.apache.helix.zookeeper.zkclient.exception.ZkInterruptedException; -import org.apache.helix.zookeeper.zkclient.exception.ZkNodeExistsException; +import org.apache.helix.zookeeper.zkclient.exception.ZkNoNodeException; import org.apache.helix.zookeeper.zkclient.exception.ZkTimeoutException; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; @@ -219,16 +219,15 @@ public class ZkMetaClientUtil { return MetaClientInterface.EntryMode.CONTAINER; case NORMAL: return MetaClientInterface.EntryMode.EPHEMERAL; - // TODO: TTL is not supported now. - //case TTL: - // return EntryMode.TTL; + case TTL: + return MetaClientInterface.EntryMode.TTL; default: throw new IllegalArgumentException(zkEphemeralType + " is not supported."); } } public static MetaClientException translateZkExceptionToMetaclientException(ZkException e) { - if (e instanceof ZkNodeExistsException) { + if (e instanceof ZkNoNodeException) { return new MetaClientNoNodeException(e); } else if (e instanceof ZkBadVersionException) { return new MetaClientBadVersionException(e); diff --git a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClient.java b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClient.java index 49cbae1f3..cdb894b34 100644 --- a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClient.java +++ b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/TestZkMetaClient.java @@ -19,12 +19,17 @@ package org.apache.helix.metaclient.impl.zk; * under the License. */ +import org.apache.helix.metaclient.api.DataUpdater; +import org.apache.helix.metaclient.api.MetaClientInterface; +import org.apache.helix.metaclient.exception.MetaClientException; +import org.apache.helix.metaclient.api.DirectChildChangeListener; + import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; +import java.util.Map; +import java.util.HashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -33,12 +38,9 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.lang3.NotImplementedException; import org.apache.helix.metaclient.api.ConnectStateChangeListener; import org.apache.helix.metaclient.api.DataChangeListener; -import org.apache.helix.metaclient.api.DataUpdater; -import org.apache.helix.metaclient.api.DirectChildChangeListener; -import org.apache.helix.metaclient.api.MetaClientInterface; import org.apache.helix.metaclient.api.Op; import org.apache.helix.metaclient.api.OpResult; -import org.apache.helix.metaclient.exception.MetaClientException; +import org.apache.helix.metaclient.exception.MetaClientNoNodeException; import org.apache.helix.metaclient.impl.zk.factory.ZkMetaClientConfig; import org.apache.zookeeper.KeeperException; import org.testng.Assert; @@ -53,8 +55,8 @@ public class TestZkMetaClient extends ZkMetaClientTestBase{ private static final String ZK_ADDR = "localhost:2183"; private static final int DEFAULT_TIMEOUT_MS = 1000; private static final String ENTRY_STRING_VALUE = "test-value"; - private static String TRANSACTION_TEST_PARENT_PATH = "/transactionOpTestPath"; - private static final String TEST_INVALID_PATH = "_invalid/a/b/c"; + private static final String TRANSACTION_TEST_PARENT_PATH = "/transactionOpTestPath"; + private static final String TEST_INVALID_PATH = "/_invalid/a/b/c"; private final Object _syncObject = new Object(); @@ -84,6 +86,35 @@ public class TestZkMetaClient extends ZkMetaClientTestBase{ } } + @Test + public void testCreateTTL() { + final String key = "/TestZkMetaClient_testTTL"; + try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) { + zkMetaClient.connect(); + zkMetaClient.createWithTTL(key, ENTRY_STRING_VALUE, 1000); + Assert.assertNotNull(zkMetaClient.exists(key)); + } + } + + @Test + public void testRenewTTL() { + final String key = "/TestZkMetaClient_testRenewTTL_1"; + try (ZkMetaClient<String> zkMetaClient = createZkMetaClient()) { + zkMetaClient.connect(); + zkMetaClient.createWithTTL(key, ENTRY_STRING_VALUE, 10000); + Assert.assertNotNull(zkMetaClient.exists(key)); + MetaClientInterface.Stat stat = zkMetaClient.exists(key); + zkMetaClient.renewTTLNode(key); + // Renewing a ttl node changes the nodes modified_time. Should be different + // from the time the node was created. + Assert.assertNotSame(stat.getCreationTime(), stat.getModifiedTime()); + try { + zkMetaClient.renewTTLNode(TEST_INVALID_PATH); + } catch (MetaClientNoNodeException ignored) { + } + } + } + @Test public void testGet() { final String key = "/TestZkMetaClient_testGet"; diff --git a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientTestBase.java b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientTestBase.java index cbc9832e1..51c655602 100644 --- a/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientTestBase.java +++ b/meta-client/src/test/java/org/apache/helix/metaclient/impl/zk/ZkMetaClientTestBase.java @@ -49,6 +49,8 @@ public abstract class ZkMetaClientTestBase { */ @BeforeSuite public void prepare() { + // Enable extended types and create a ZkClient + System.setProperty("zookeeper.extendedTypesEnabled", "true"); // start local zookeeper server _zkServer = startZkServer(ZK_ADDR); }
