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/03/14 18:40:41 UTC

[helix] branch metaclient updated: TTL Node Lattice Implementation (#2401)

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


The following commit(s) were added to refs/heads/metaclient by this push:
     new 8151b2ffd TTL Node Lattice Implementation (#2401)
8151b2ffd is described below

commit 8151b2ffde27db8f84108691d30666a2fb8b7b5e
Author: Marcos Rico Peng <55...@users.noreply.github.com>
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);
   }