You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by hu...@apache.org on 2022/05/18 12:44:20 UTC

[helix] branch zookeeper-api-ttlcontainer updated: Add TTL and Container modes to sync create API in ZkClient and ZkConnection (#2090)

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

hulee pushed a commit to branch zookeeper-api-ttlcontainer
in repository https://gitbox.apache.org/repos/asf/helix.git


The following commit(s) were added to refs/heads/zookeeper-api-ttlcontainer by this push:
     new 450c47f77 Add TTL and Container modes to sync create API in ZkClient and ZkConnection (#2090)
450c47f77 is described below

commit 450c47f77020f35dfae06e85dab31809a71f37fb
Author: Ramin Bashizade <ra...@linkedin.com>
AuthorDate: Wed May 18 05:44:15 2022 -0700

    Add TTL and Container modes to sync create API in ZkClient and ZkConnection (#2090)
    
    This PR adds methods that support creating persistent nodes with Container and TTL modes synchronously to ZkClient and ZkConnection classes.
---
 .../helix/zookeeper/zkclient/IZkConnection.java    |   2 +
 .../apache/helix/zookeeper/zkclient/ZkClient.java  | 327 ++++++++++++++++++++-
 .../helix/zookeeper/zkclient/ZkConnection.java     |   6 +
 .../zookeeper/impl/client/TestRawZkClient.java     | 129 ++++++++
 4 files changed, 455 insertions(+), 9 deletions(-)

diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/IZkConnection.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/IZkConnection.java
index 6fc040fd8..e766bf7d9 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/IZkConnection.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/IZkConnection.java
@@ -40,6 +40,8 @@ public interface IZkConnection {
 
     public String create(String path, byte[] data, List<ACL> acl, CreateMode mode) throws KeeperException, InterruptedException;
 
+    public String create(String path, byte[] data, List<ACL> acl, CreateMode mode, long ttl) throws KeeperException, InterruptedException;
+
     public void delete(String path) throws InterruptedException, KeeperException;
 
     boolean exists(final String path, final boolean watch) throws KeeperException, InterruptedException;
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkClient.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkClient.java
index c6b74239b..e4832656b 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkClient.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkClient.java
@@ -438,6 +438,41 @@ public class ZkClient implements Watcher {
     createPersistent(path, false);
   }
 
+  /**
+   * Create a persistent node with TTL.
+   * @param path the path where you want the node to be created
+   * @param ttl TTL of the node in milliseconds
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createPersistentWithTTL(String path, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    createPersistentWithTTL(path, false, ttl);
+  }
+
+  /**
+   * Create a container node.
+   * @param path the path where you want the node to be created
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createContainer(String path)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    createContainer(path, false);
+  }
+
   /**
    * Create a persistent node and set its ACLs.
    * @param path
@@ -459,6 +494,45 @@ public class ZkClient implements Watcher {
     createPersistent(path, createParents, ZooDefs.Ids.OPEN_ACL_UNSAFE);
   }
 
+  /**
+   * Create a persistent node with TTL and set its ACLs.
+   * @param path the path where you want the node to be created
+   * @param createParents if true all parent dirs are created as well and no
+   *                      {@link ZkNodeExistsException} is thrown in case the path already exists
+   * @param ttl TTL of the node in milliseconds
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createPersistentWithTTL(String path, boolean createParents, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    createPersistentWithTTL(path, createParents, ZooDefs.Ids.OPEN_ACL_UNSAFE, ttl);
+  }
+
+  /**
+   * Create a container node and set its ACLs.
+   * @param path the path where you want the node to be created
+   * @param createParents if true all parent dirs are created as well and no
+   *                      {@link ZkNodeExistsException} is thrown in case the path already exists
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createContainer(String path, boolean createParents)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    createContainer(path, createParents, ZooDefs.Ids.OPEN_ACL_UNSAFE);
+  }
+
   /**
    * Create a persistent node and set its ACLs.
    * @param path
@@ -495,6 +569,73 @@ public class ZkClient implements Watcher {
     }
   }
 
+  /**
+   * Create a persistent node with TTL and set its ACLs.
+   * @param path the path where you want the node to be created
+   * @param createParents if true all parent dirs are created as well and no
+   *                      {@link ZkNodeExistsException} is thrown in case the path already exists
+   * @param acl List of ACL permissions to assign to the node
+   * @param ttl TTL of the node in milliseconds
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createPersistentWithTTL(String path, boolean createParents, List<ACL> acl, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    try {
+      create(path, null, acl, CreateMode.PERSISTENT_WITH_TTL, ttl);
+    } catch (ZkNodeExistsException e) {
+      if (!createParents) {
+        throw e;
+      }
+    } catch (ZkNoNodeException e) {
+      if (!createParents) {
+        throw e;
+      }
+      String parentDir = path.substring(0, path.lastIndexOf('/'));
+      createPersistentWithTTL(parentDir, createParents, acl, ttl);
+      createPersistentWithTTL(path, createParents, acl, ttl);
+    }
+  }
+
+  /**
+   * Create a container node and set its ACLs.
+   * @param path the path where you want the node to be created
+   * @param createParents if true all parent dirs are created as well and no
+   *                      {@link ZkNodeExistsException} is thrown in case the path already exists
+   * @param acl List of ACL permissions to assign to the node
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createContainer(String path, boolean createParents, List<ACL> acl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    try {
+      create(path, null, acl, CreateMode.CONTAINER);
+    } catch (ZkNodeExistsException e) {
+      if (!createParents) {
+        throw e;
+      }
+    } catch (ZkNoNodeException e) {
+      if (!createParents) {
+        throw e;
+      }
+      String parentDir = path.substring(0, path.lastIndexOf('/'));
+      createContainer(parentDir, createParents, acl);
+      createContainer(path, createParents, acl);
+    }
+  }
+
   /**
    * Create a persistent node.
    * @param path
@@ -513,6 +654,43 @@ public class ZkClient implements Watcher {
     create(path, data, CreateMode.PERSISTENT);
   }
 
+  /**
+   * Create a persistent node with TTL.
+   * @param path the path where you want the node to be created
+   * @param data data of the node
+   * @param ttl TTL of the node in milliseconds
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createPersistentWithTTL(String path, Object data, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    create(path, data, CreateMode.PERSISTENT_WITH_TTL, ttl);
+  }
+
+  /**
+   * Create a container node.
+   * @param path the path where you want the node to be created
+   * @param data data of the node
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createContainer(String path, Object data)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    create(path, data, CreateMode.CONTAINER);
+  }
+
   /**
    * Create a persistent node.
    * @param path
@@ -531,6 +709,43 @@ public class ZkClient implements Watcher {
     create(path, data, acl, CreateMode.PERSISTENT);
   }
 
+  /**
+   * Create a persistent node with TTL.
+   * @param path the path where you want the node to be created
+   * @param data data of the node
+   * @param acl list of ACL for the node
+   * @param ttl TTL of the node in milliseconds
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createPersistentWithTTL(String path, Object data, List<ACL> acl, long ttl) {
+    create(path, data, acl, CreateMode.PERSISTENT_WITH_TTL, ttl);
+  }
+
+  /**
+   * Create a container node.
+   * @param path the path where you want the node to be created
+   * @param data data of the node
+   * @param acl list of ACL for the node
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public void createContainer(String path, Object data, List<ACL> acl) {
+    create(path, data, acl, CreateMode.CONTAINER);
+  }
+
   /**
    * Create a persistent, sequental node.
    * @param path
@@ -550,6 +765,26 @@ public class ZkClient implements Watcher {
     return create(path, data, CreateMode.PERSISTENT_SEQUENTIAL);
   }
 
+  /**
+   * Create a persistent, sequential node.
+   * @param path the path where you want the node to be created
+   * @param data data of the node
+   * @param ttl TTL of the node in milliseconds
+   * @return create node's path
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public String createPersistentSequentialWithTTL(String path, Object data, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    return create(path, data, CreateMode.PERSISTENT_SEQUENTIAL_WITH_TTL, ttl);
+  }
+
   /**
    * Create a persistent, sequential node and set its ACL.
    * @param path
@@ -570,6 +805,27 @@ public class ZkClient implements Watcher {
     return create(path, data, acl, CreateMode.PERSISTENT_SEQUENTIAL);
   }
 
+  /**
+   * Create a persistent, sequential node and set its ACL.
+   * @param path the path where you want the node to be created
+   * @param acl list of ACL for the node
+   * @param data data of the node
+   * @param ttl TTL of the node in milliseconds
+   * @return create node's path
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public String createPersistentSequentialWithTTL(String path, Object data, List<ACL> acl, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    return create(path, data, acl, CreateMode.PERSISTENT_SEQUENTIAL_WITH_TTL, ttl);
+  }
+
   /**
    * Create an ephemeral node.
    * @param path
@@ -648,7 +904,7 @@ public class ZkClient implements Watcher {
    */
   public void createEphemeral(final String path, final List<ACL> acl, final String sessionId)
       throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
-    create(path, null, acl, CreateMode.EPHEMERAL, sessionId);
+    create(path, null, acl, CreateMode.EPHEMERAL, TTL_NOT_SET, sessionId);
   }
 
   /**
@@ -671,6 +927,28 @@ public class ZkClient implements Watcher {
     return create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, mode);
   }
 
+  /**
+   * Create a node.
+   * @param path the path where you want the node to be created
+   * @param data data of the node
+   * @param mode {@link CreateMode} of the node
+   * @param ttl TTL of the node in milliseconds, if mode is {@link CreateMode#PERSISTENT_WITH_TTL}
+   *            or {@link CreateMode#PERSISTENT_SEQUENTIAL_WITH_TTL}
+   * @return create node's path
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public String create(final String path, Object data, final CreateMode mode, long ttl)
+      throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
+    return create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, mode, ttl);
+  }
+
   /**
    * Create a node with ACL.
    * @param path
@@ -689,7 +967,30 @@ public class ZkClient implements Watcher {
    */
   public String create(final String path, Object datat, final List<ACL> acl, final CreateMode mode)
       throws IllegalArgumentException, ZkException {
-    return create(path, datat, acl, mode, null);
+    return create(path, datat, acl, mode, TTL_NOT_SET, null);
+  }
+
+  /**
+   * Create a node with ACL.
+   * @param path the path where you want the node to be created
+   * @param datat data of the node
+   * @param acl list of ACL for the node
+   * @param mode {@link CreateMode} of the node
+   * @param ttl TTL of the node in milliseconds, if mode is {@link CreateMode#PERSISTENT_WITH_TTL}
+   *            or {@link CreateMode#PERSISTENT_SEQUENTIAL_WITH_TTL}
+   * @return create node's path
+   * @throws ZkInterruptedException
+   *           if operation was interrupted, or a required reconnection got interrupted
+   * @throws IllegalArgumentException
+   *           if called from anything except the ZooKeeper event thread
+   * @throws ZkException
+   *           if any ZooKeeper exception occurred
+   * @throws RuntimeException
+   *           if any other exception occurs
+   */
+  public String create(final String path, Object datat, final List<ACL> acl, final CreateMode mode,
+      long ttl) throws IllegalArgumentException, ZkException {
+    return create(path, datat, acl, mode, ttl, null);
   }
 
   /**
@@ -705,6 +1006,8 @@ public class ZkClient implements Watcher {
    * @param dataObject data of the node
    * @param acl list of ACL for the node
    * @param mode {@link CreateMode} of the node
+   * @param ttl TTL of the node in milliseconds, if mode is {@link CreateMode#PERSISTENT_WITH_TTL}
+   *            or {@link CreateMode#PERSISTENT_SEQUENTIAL_WITH_TTL}
    * @param expectedSessionId the expected session ID of the ZK connection. It is not necessarily the
    *                  session ID of current ZK Connection. If the expected session ID is NOT null,
    *                  the node is guaranteed to be created in the expected session, or creation is
@@ -715,7 +1018,7 @@ public class ZkClient implements Watcher {
    * @throws ZkException if any zookeeper exception occurs
    */
   private String create(final String path, final Object dataObject, final List<ACL> acl,
-      final CreateMode mode, final String expectedSessionId)
+      final CreateMode mode, long ttl, final String expectedSessionId)
       throws IllegalArgumentException, ZkException {
     if (path == null) {
       throw new NullPointerException("Path must not be null.");
@@ -728,8 +1031,14 @@ public class ZkClient implements Watcher {
       final byte[] dataBytes = dataObject == null ? null : serialize(dataObject, path);
       checkDataSizeLimit(path, dataBytes);
 
-      final String actualPath = retryUntilConnected(
-          () -> getExpectedZookeeper(expectedSessionId).create(path, dataBytes, acl, mode));
+      final String actualPath;
+      if (mode.isTTL()) {
+        actualPath = retryUntilConnected(() -> getExpectedZookeeper(expectedSessionId)
+            .create(path, dataBytes, acl, mode, null, ttl));
+      } else {
+        actualPath = retryUntilConnected(() -> getExpectedZookeeper(expectedSessionId)
+            .create(path, dataBytes, acl, mode));
+      }
 
       record(path, dataBytes, startT, ZkClientMonitor.AccessType.WRITE);
       return actualPath;
@@ -786,7 +1095,7 @@ public class ZkClient implements Watcher {
    */
   public void createEphemeral(final String path, final Object data, final String sessionId)
       throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
-    create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, sessionId);
+    create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, TTL_NOT_SET, sessionId);
   }
 
   /**
@@ -836,7 +1145,7 @@ public class ZkClient implements Watcher {
   public void createEphemeral(final String path, final Object data, final List<ACL> acl,
       final String sessionId)
       throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
-    create(path, data, acl, CreateMode.EPHEMERAL, sessionId);
+    create(path, data, acl, CreateMode.EPHEMERAL, TTL_NOT_SET, sessionId);
   }
 
   /**
@@ -882,7 +1191,7 @@ public class ZkClient implements Watcher {
   public String createEphemeralSequential(final String path, final Object data, final List<ACL> acl,
       final String sessionId)
       throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
-    return create(path, data, acl, CreateMode.EPHEMERAL_SEQUENTIAL, sessionId);
+    return create(path, data, acl, CreateMode.EPHEMERAL_SEQUENTIAL, TTL_NOT_SET, sessionId);
   }
 
   /**
@@ -914,7 +1223,7 @@ public class ZkClient implements Watcher {
       final String sessionId)
       throws ZkInterruptedException, IllegalArgumentException, ZkException, RuntimeException {
     return create(path, data, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL,
-        sessionId);
+        TTL_NOT_SET, sessionId);
   }
 
   /**
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkConnection.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkConnection.java
index 08a2fb9aa..01935919c 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkConnection.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkConnection.java
@@ -133,6 +133,12 @@ public class ZkConnection implements IZkConnection {
     return _zk.create(path, data, acl, mode);
   }
 
+  @Override
+  public String create(String path, byte[] data, List<ACL> acl, CreateMode mode, long ttl)
+      throws KeeperException, InterruptedException {
+    return _zk.create(path, data, acl, mode, null, ttl);
+  }
+
   @Override
   public void delete(String path) throws InterruptedException, KeeperException {
     _zk.delete(path, -1);
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestRawZkClient.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestRawZkClient.java
index 20d070b52..9e8a75a73 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestRawZkClient.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestRawZkClient.java
@@ -89,6 +89,135 @@ public class TestRawZkClient extends ZkTestBase {
     _zkClient.close();
   }
 
+  @Test
+  void testUnimplementedTypes() {
+    // Make sure extended types are disabled
+    System.clearProperty("zookeeper.extendedTypesEnabled");
+
+    // Make sure the test path is clear
+    String parentPath = "/tmp";
+    String path = "/tmp/unimplemented";
+    _zkClient.deleteRecursively(parentPath);
+
+    try {
+      long ttl = 1L;
+      _zkClient.createPersistentWithTTL(path, true, ttl);
+    } catch (ZkException e) {
+      AssertJUnit.assertTrue(e.getCause() instanceof KeeperException.UnimplementedException);
+      return;
+    }
+
+    // Clean up
+    _zkClient.deleteRecursively(parentPath);
+    AssertJUnit.fail();
+  }
+
+  @Test
+  void testCreatePersistentWithTTL() {
+    // Enable extended types and create a ZkClient
+    System.setProperty("zookeeper.extendedTypesEnabled", "true");
+    ZkClient zkClient = new ZkClient(ZkTestBase.ZK_ADDR);
+    zkClient.setZkSerializer(new ZNRecordSerializer());
+
+    // Make sure the test path is clear
+    String parentPath = "/tmp";
+    String path = "/tmp/createTTL";
+    zkClient.deleteRecursively(parentPath);
+    AssertJUnit.assertFalse(zkClient.exists(parentPath));
+    AssertJUnit.assertFalse(zkClient.exists(path));
+
+    long ttl = 1L;
+    ZNRecord record = new ZNRecord("record");
+    String key = "key";
+    String value = "value";
+    record.setSimpleField(key, value);
+
+    // Create a ZNode with the above ZNRecord and read back its data
+    zkClient.createPersistentWithTTL(parentPath, record, ttl);
+    AssertJUnit.assertTrue(zkClient.exists(parentPath));
+    ZNRecord retrievedRecord = zkClient.readData(parentPath);
+    AssertJUnit.assertEquals(value, retrievedRecord.getSimpleField(key));
+
+    // Clear the path and test with createParents = true
+    AssertJUnit.assertTrue(zkClient.delete(parentPath));
+    zkClient.createPersistentWithTTL(path, true, ttl);
+    AssertJUnit.assertTrue(zkClient.exists(path));
+
+    // Clean up
+    zkClient.deleteRecursively(parentPath);
+    zkClient.close();
+    System.clearProperty("zookeeper.extendedTypesEnabled");
+  }
+
+  @Test
+  void testCreatePersistentSequentialWithTTL() {
+    // Enable extended types and create a ZkClient
+    System.setProperty("zookeeper.extendedTypesEnabled", "true");
+    ZkClient zkClient = new ZkClient(ZkTestBase.ZK_ADDR);
+    zkClient.setZkSerializer(new ZNRecordSerializer());
+
+    // Make sure the test path is clear
+    String parentPath = "/tmp";
+    String path = "/tmp/createSequentialTTL";
+    zkClient.deleteRecursively(parentPath);
+    AssertJUnit.assertFalse(zkClient.exists(parentPath));
+    AssertJUnit.assertFalse(zkClient.exists(path + "0000000000"));
+
+    long ttl = 1L;
+    ZNRecord record = new ZNRecord("record");
+    String key = "key";
+    String value = "value";
+    record.setSimpleField(key, value);
+
+    // Create a ZNode with the above ZNRecord and read back its data
+    zkClient.createPersistent(parentPath);
+    zkClient.createPersistentSequentialWithTTL(path, record, ttl);
+    AssertJUnit.assertTrue(zkClient.exists(path + "0000000000"));
+    ZNRecord retrievedRecord = zkClient.readData(path + "0000000000");
+    AssertJUnit.assertEquals(value, retrievedRecord.getSimpleField(key));
+
+    // Clean up
+    zkClient.deleteRecursively(parentPath);
+    zkClient.close();
+    System.clearProperty("zookeeper.extendedTypesEnabled");
+  }
+
+  @Test
+  void testCreateContainer() {
+    // Enable extended types and create a ZkClient
+    System.setProperty("zookeeper.extendedTypesEnabled", "true");
+    ZkClient zkClient = new ZkClient(ZkTestBase.ZK_ADDR);
+    zkClient.setZkSerializer(new ZNRecordSerializer());
+
+    // Make sure the test path is clear
+    String parentPath = "/tmp";
+    String path = "/tmp/createContainer";
+    zkClient.deleteRecursively(parentPath);
+    AssertJUnit.assertFalse(zkClient.exists(parentPath));
+    AssertJUnit.assertFalse(zkClient.exists(path));
+
+    ZNRecord record = new ZNRecord("record");
+    String key = "key";
+    String value = "value";
+    record.setSimpleField(key, value);
+
+    // Create a ZNode with the above ZNRecord and read back its data
+    zkClient.createContainer(parentPath, record);
+    AssertJUnit.assertTrue(zkClient.exists(parentPath));
+    ZNRecord retrievedRecord = zkClient.readData(parentPath);
+    AssertJUnit.assertEquals(value, retrievedRecord.getSimpleField(key));
+
+    // Clear the path and test with createParents = true
+    AssertJUnit.assertTrue(zkClient.delete(parentPath));
+    zkClient.createContainer(path, true);
+    AssertJUnit.assertTrue(zkClient.exists(path));
+
+    // Clean up
+    zkClient.deleteRecursively(parentPath);
+    zkClient.close();
+    System.clearProperty("zookeeper.extendedTypesEnabled");
+  }
+
   @Test()
   void testGetStat() {
     String path = "/tmp/getStatTest";