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 2020/04/08 22:54:02 UTC
[helix] 32/50: Make RealmAwareZkClient implementations use
HttpRoutingDataReader for routing data (#819)
This is an automated email from the ASF dual-hosted git repository.
hulee pushed a commit to branch zooscalability_merge
in repository https://gitbox.apache.org/repos/asf/helix.git
commit d5257235d6e9ce4414aecb6d33583d1f9cfc2150
Author: Hunter Lee <hu...@linkedin.com>
AuthorDate: Wed Mar 4 00:01:40 2020 -0800
Make RealmAwareZkClient implementations use HttpRoutingDataReader for routing data (#819)
We want all implementations of RealmAwareZkClient to do a one-time query to Metadata Store Directory Service for routing data and cache it in memory. In order to accomplish that, we have introduced HttpRoutingDataReader, which is a Singleton class that makes a REST call to read routing data and caches it in memory. This diff updates the initialization logic in RealmAwareZkClients accordingly.
Changelist:
1. Update all RealmAwareZkClient initialization logic
2. Fix tests
---
.../main/java/org/apache/helix/ConfigAccessor.java | 6 +-
.../mock/MockMetadataStoreDirectoryServer.java | 6 +-
.../helix/msdcommon/constant/TestConstants.java | 26 ++--
.../mock/TestMockMetadataStoreDirectoryServer.java | 19 ++-
.../api/factory/RealmAwareZkClientFactory.java | 26 ++--
.../zookeeper/impl/client/DedicatedZkClient.java | 55 +++++---
.../zookeeper/impl/client/FederatedZkClient.java | 25 +++-
.../zookeeper/impl/client/SharedZkClient.java | 32 +++--
.../impl/factory/DedicatedZkClientFactory.java | 10 +-
.../impl/factory/SharedZkClientFactory.java | 17 +--
.../zookeeper/util/HttpRoutingDataReader.java | 3 +-
zookeeper-api/src/test/conf/testng.xml | 4 +-
.../helix/zookeeper/constant/TestConstants.java | 45 +++++++
.../apache/helix/zookeeper/impl/ZkTestBase.java | 5 +-
...java => RealmAwareZkClientFactoryTestBase.java} | 100 ++++++++------
.../impl/client/RealmAwareZkClientTestBase.java | 150 ++++-----------------
.../impl/client/TestDedicatedZkClient.java | 8 +-
.../impl/client/TestFederatedZkClient.java | 53 ++------
.../zookeeper/impl/client/TestSharedZkClient.java | 8 +-
.../zookeeper/util/TestHttpRoutingDataReader.java | 35 ++---
20 files changed, 296 insertions(+), 337 deletions(-)
diff --git a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
index ad77b4e..031fbf1 100644
--- a/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
+++ b/helix-core/src/main/java/org/apache/helix/ConfigAccessor.java
@@ -90,10 +90,8 @@ public class ConfigAccessor {
private ConfigAccessor(Builder builder) throws IOException, InvalidRoutingDataException {
switch (builder._realmMode) {
case MULTI_REALM:
- // TODO: make sure FederatedZkClient is created correctly
- // TODO: pass in MSDS endpoint or pass in _realmAwareZkConnectionConfig
- String msdsEndpoint = builder._realmAwareZkConnectionConfig.getMsdsEndpoint();
- _zkClient = new FederatedZkClient();
+ _zkClient = new FederatedZkClient(builder._realmAwareZkConnectionConfig,
+ builder._realmAwareZkClientConfig);
break;
case SINGLE_REALM:
// Create a HelixZkClient: Use a SharedZkClient because ConfigAccessor does not need to do
diff --git a/metadata-store-directory-common/src/main/java/org/apache/helix/msdcommon/mock/MockMetadataStoreDirectoryServer.java b/metadata-store-directory-common/src/main/java/org/apache/helix/msdcommon/mock/MockMetadataStoreDirectoryServer.java
index f2a59d6..7253092 100644
--- a/metadata-store-directory-common/src/main/java/org/apache/helix/msdcommon/mock/MockMetadataStoreDirectoryServer.java
+++ b/metadata-store-directory-common/src/main/java/org/apache/helix/msdcommon/mock/MockMetadataStoreDirectoryServer.java
@@ -23,7 +23,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
@@ -68,7 +67,7 @@ public class MockMetadataStoreDirectoryServer {
/**
* Constructs a Mock MSDS.
* A sample GET might look like the following:
- * curl localhost:11000/admin/v2/namespaces/MY-HELIX-NAMESPACE/METADATA_STORE_ROUTING_DATA/zk-1
+ * curl localhost:11000/admin/v2/namespaces/MY-HELIX-NAMESPACE/metadata-store-realms/zk-1
* @param hostname hostname for the REST server. E.g.) "localhost"
* @param port port to use. E.g.) 11000
* @param namespace the Helix REST namespace to mock. E.g.) "MY-HELIX-NAMESPACE"
@@ -94,8 +93,7 @@ public class MockMetadataStoreDirectoryServer {
_routingDataMap = routingData;
}
- public void startServer()
- throws IOException {
+ public void startServer() throws IOException {
_server = HttpServer.create(new InetSocketAddress(_hostname, _mockServerPort), 0);
generateContexts();
_server.setExecutor(_executor);
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java b/metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/constant/TestConstants.java
similarity index 53%
copy from zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java
copy to metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/constant/TestConstants.java
index 8cf3f85..c471a1a 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java
+++ b/metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/constant/TestConstants.java
@@ -1,4 +1,4 @@
-package org.apache.helix.zookeeper.impl.client;
+package org.apache.helix.msdcommon.constant;
/*
* Licensed to the Apache Software Foundation (ASF) under one
@@ -9,7 +9,7 @@ package org.apache.helix.zookeeper.impl.client;
* "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
+ * 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
@@ -19,17 +19,19 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
-import org.apache.helix.zookeeper.impl.factory.DedicatedZkClientFactory;
-import org.testng.annotations.BeforeClass;
+import java.util.Collection;
+import java.util.Map;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
-public class TestDedicatedZkClient extends RealmAwareZkClientTestBase {
- @BeforeClass
- public void beforeClass()
- throws Exception {
- super.beforeClass();
- // Set the factory to DedicatedZkClientFactory
- _realmAwareZkClientFactory = DedicatedZkClientFactory.getInstance();
- }
+/**
+ * Constants to be used for testing.
+ */
+public class TestConstants {
+ public static final Map<String, Collection<String>> FAKE_ROUTING_DATA = ImmutableMap.of(
+ "zk-0", ImmutableList.of("/sharding-key-0", "/sharding-key-1", "/sharding-key-2"),
+ "zk-1", ImmutableList.of("/sharding-key-3", "/sharding-key-4", "/sharding-key-5"),
+ "zk-2", ImmutableList.of("/sharding-key-6", "/sharding-key-7", "/sharding-key-8"));
}
diff --git a/metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/mock/TestMockMetadataStoreDirectoryServer.java b/metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/mock/TestMockMetadataStoreDirectoryServer.java
index 1dc006a..015bc8c 100644
--- a/metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/mock/TestMockMetadataStoreDirectoryServer.java
+++ b/metadata-store-directory-common/src/test/java/org/apache/helix/msdcommon/mock/TestMockMetadataStoreDirectoryServer.java
@@ -22,12 +22,14 @@ package org.apache.helix.msdcommon.mock;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableList;
import org.apache.helix.msdcommon.constant.MetadataStoreRoutingConstants;
+import org.apache.helix.msdcommon.constant.TestConstants;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
@@ -40,12 +42,6 @@ import org.testng.Assert;
public class TestMockMetadataStoreDirectoryServer {
@Test
public void testMockMetadataStoreDirectoryServer() throws IOException {
- // Create fake routing data
- Map<String, Collection<String>> routingData = new HashMap<>();
- routingData.put("zk-0", ImmutableList.of("sharding-key-0", "sharding-key-1", "sharding-key-2"));
- routingData.put("zk-1", ImmutableList.of("sharding-key-3", "sharding-key-4", "sharding-key-5"));
- routingData.put("zk-2", ImmutableList.of("sharding-key-6", "sharding-key-7", "sharding-key-8"));
-
// Start MockMSDS
String host = "localhost";
int port = 11000;
@@ -53,7 +49,8 @@ public class TestMockMetadataStoreDirectoryServer {
String namespace = "MY-HELIX-NAMESPACE";
MockMetadataStoreDirectoryServer server =
- new MockMetadataStoreDirectoryServer(host, port, namespace, routingData);
+ new MockMetadataStoreDirectoryServer(host, port, namespace,
+ TestConstants.FAKE_ROUTING_DATA);
server.startServer();
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
// Send a GET request for all routing data
@@ -69,13 +66,13 @@ public class TestMockMetadataStoreDirectoryServer {
Collection<String> allRealms = routingDataList.stream().map(mapEntry -> (String) mapEntry
.get(MetadataStoreRoutingConstants.SINGLE_METADATA_STORE_REALM))
.collect(Collectors.toSet());
- Assert.assertEquals(allRealms, routingData.keySet());
+ Assert.assertEquals(new HashSet(allRealms), TestConstants.FAKE_ROUTING_DATA.keySet());
Map<String, List<String>> retrievedRoutingData = routingDataList.stream().collect(Collectors
.toMap(mapEntry -> (String) mapEntry
.get(MetadataStoreRoutingConstants.SINGLE_METADATA_STORE_REALM),
mapEntry -> (List<String>) mapEntry
.get(MetadataStoreRoutingConstants.SHARDING_KEYS)));
- Assert.assertEquals(retrievedRoutingData, routingData);
+ Assert.assertEquals(retrievedRoutingData, TestConstants.FAKE_ROUTING_DATA);
// Send a GET request for all realms
getRequest = new HttpGet(endpoint + MockMetadataStoreDirectoryServer.REST_PREFIX + namespace
@@ -86,7 +83,7 @@ public class TestMockMetadataStoreDirectoryServer {
Assert.assertTrue(
allRealmsMap.containsKey(MetadataStoreRoutingConstants.METADATA_STORE_REALMS));
allRealms = allRealmsMap.get(MetadataStoreRoutingConstants.METADATA_STORE_REALMS);
- Assert.assertEquals(allRealms, routingData.keySet());
+ Assert.assertEquals(allRealms, TestConstants.FAKE_ROUTING_DATA.keySet());
// Send a GET request for testZkRealm
String testZkRealm = "zk-0";
@@ -103,7 +100,7 @@ public class TestMockMetadataStoreDirectoryServer {
Collection<String> shardingKeyList =
(Collection) shardingKeysMap.get(MetadataStoreRoutingConstants.SHARDING_KEYS);
Assert.assertEquals(zkRealm, testZkRealm);
- Assert.assertEquals(shardingKeyList, routingData.get(testZkRealm));
+ Assert.assertEquals(shardingKeyList, TestConstants.FAKE_ROUTING_DATA.get(testZkRealm));
// Try sending a POST request (not supported)
HttpPost postRequest = new HttpPost(
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/factory/RealmAwareZkClientFactory.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/factory/RealmAwareZkClientFactory.java
index cdfa778..d8fa9a7 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/factory/RealmAwareZkClientFactory.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/factory/RealmAwareZkClientFactory.java
@@ -19,7 +19,9 @@ package org.apache.helix.zookeeper.api.factory;
* under the License.
*/
-import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
+import java.io.IOException;
+
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
@@ -31,26 +33,24 @@ public interface RealmAwareZkClientFactory {
* Build a RealmAwareZkClient using specified connection config and client config.
* @param connectionConfig
* @param clientConfig
- * @param metadataStoreRoutingData
- * @return HelixZkClient
+ * @return RealmAwareZkClient
+ * @throws IOException if Metadata Store Directory Service is unresponsive over HTTP
+ * @throws InvalidRoutingDataException if the routing data received is invalid or empty
*/
- // TODO: remove MetadataStoreRoutingData
RealmAwareZkClient buildZkClient(RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- RealmAwareZkClient.RealmAwareZkClientConfig clientConfig,
- MetadataStoreRoutingData metadataStoreRoutingData);
+ RealmAwareZkClient.RealmAwareZkClientConfig clientConfig)
+ throws IOException, InvalidRoutingDataException;
/**
* Builds a RealmAwareZkClient using specified connection config and default client config.
* @param connectionConfig
- * @param metadataStoreRoutingData
* @return RealmAwareZkClient
+ * @throws IOException if Metadata Store Directory Service is unresponsive over HTTP
+ * @throws InvalidRoutingDataException if the routing data received is invalid or empty
*/
-
- // TODO: remove MetadataStoreRoutingData
default RealmAwareZkClient buildZkClient(
- RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
- return buildZkClient(connectionConfig, new RealmAwareZkClient.RealmAwareZkClientConfig(),
- metadataStoreRoutingData);
+ RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig)
+ throws IOException, InvalidRoutingDataException {
+ return buildZkClient(connectionConfig, new RealmAwareZkClient.RealmAwareZkClientConfig());
}
}
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/DedicatedZkClient.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/DedicatedZkClient.java
index 8352b2b..beeb085 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/DedicatedZkClient.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/DedicatedZkClient.java
@@ -19,12 +19,15 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
+import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
+import org.apache.helix.zookeeper.util.HttpRoutingDataReader;
import org.apache.helix.zookeeper.zkclient.DataUpdater;
import org.apache.helix.zookeeper.zkclient.IZkChildListener;
import org.apache.helix.zookeeper.zkclient.IZkConnection;
@@ -56,24 +59,39 @@ public class DedicatedZkClient implements RealmAwareZkClient {
private final ZkClient _rawZkClient;
private final MetadataStoreRoutingData _metadataStoreRoutingData;
private final String _zkRealmShardingKey;
- private final String _zkRealmAddress;
- // TODO: Remove MetadataStoreRoutingData from constructor
+ /**
+ * DedicatedZkClient connects to a single ZK realm and supports full ZkClient functionalities
+ * such as CRUD, change callback, and ephemeral operations for a single ZkRealmShardingKey.
+ * @param connectionConfig
+ * @param clientConfig
+ * @throws IOException
+ * @throws InvalidRoutingDataException
+ */
public DedicatedZkClient(RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- RealmAwareZkClient.RealmAwareZkClientConfig clientConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
-
+ RealmAwareZkClient.RealmAwareZkClientConfig clientConfig)
+ throws IOException, InvalidRoutingDataException {
if (connectionConfig == null) {
throw new IllegalArgumentException("RealmAwareZkConnectionConfig cannot be null!");
}
- _zkRealmShardingKey = connectionConfig.getZkRealmShardingKey();
+ if (clientConfig == null) {
+ throw new IllegalArgumentException("RealmAwareZkClientConfig cannot be null!");
+ }
- if (metadataStoreRoutingData == null) {
- throw new IllegalArgumentException("MetadataStoreRoutingData cannot be null!");
+ // Get the routing data from a static Singleton HttpRoutingDataReader
+ String msdsEndpoint = connectionConfig.getMsdsEndpoint();
+ if (msdsEndpoint == null || msdsEndpoint.isEmpty()) {
+ _metadataStoreRoutingData = HttpRoutingDataReader.getMetadataStoreRoutingData();
+ } else {
+ _metadataStoreRoutingData = HttpRoutingDataReader.getMetadataStoreRoutingData(msdsEndpoint);
+ }
+
+ _zkRealmShardingKey = connectionConfig.getZkRealmShardingKey();
+ if (_zkRealmShardingKey == null || _zkRealmShardingKey.isEmpty()) {
+ throw new IllegalArgumentException(
+ "RealmAwareZkConnectionConfig's ZK realm sharding key cannot be null or empty for DedicatedZkClient!");
}
- _metadataStoreRoutingData = metadataStoreRoutingData;
- // TODO: Get it from static map/singleton (HttpRoutingDataReader)
// Get the ZkRealm address based on the ZK path sharding key
String zkRealmAddress = _metadataStoreRoutingData.getMetadataStoreRealm(_zkRealmShardingKey);
if (zkRealmAddress == null || zkRealmAddress.isEmpty()) {
@@ -81,7 +99,6 @@ public class DedicatedZkClient implements RealmAwareZkClient {
"ZK realm address for the given ZK realm sharding key is invalid! ZK realm address: "
+ zkRealmAddress + " ZK realm sharding key: " + _zkRealmShardingKey);
}
- _zkRealmAddress = zkRealmAddress;
// Create a ZK connection
IZkConnection zkConnection =
@@ -457,17 +474,17 @@ public class DedicatedZkClient implements RealmAwareZkClient {
* @return
*/
private void checkIfPathContainsShardingKey(String path) {
- // TODO: replace with the singleton MetadataStoreRoutingData
try {
- String zkRealmForPath = _metadataStoreRoutingData.getMetadataStoreRealm(path);
- if (!_zkRealmAddress.equals(zkRealmForPath)) {
- throw new IllegalArgumentException("Given path: " + path + "'s ZK realm: " + zkRealmForPath
- + " does not match the ZK realm: " + _zkRealmAddress + " and sharding key: "
- + _zkRealmShardingKey + " for this DedicatedZkClient!");
+ String targetShardingKey = _metadataStoreRoutingData.getShardingKeyInPath(path);
+ if (!_zkRealmShardingKey.equals(targetShardingKey)) {
+ throw new IllegalArgumentException(
+ "Given path: " + path + "'s ZK sharding key: " + targetShardingKey
+ + " does not match the ZK sharding key: " + _zkRealmShardingKey
+ + " for this DedicatedZkClient!");
}
} catch (NoSuchElementException e) {
- throw new IllegalArgumentException(
- "Given path: " + path + " does not have a valid sharding key!");
+ throw new IllegalArgumentException("Given path: " + path
+ + " does not have a valid sharding key or its ZK sharding key is not found in the cached routing data!");
}
}
}
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/FederatedZkClient.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/FederatedZkClient.java
index 5f63408..1bfff66 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/FederatedZkClient.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/FederatedZkClient.java
@@ -19,6 +19,7 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
+import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -27,14 +28,16 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.impl.factory.DedicatedZkClientFactory;
+import org.apache.helix.zookeeper.util.HttpRoutingDataReader;
import org.apache.helix.zookeeper.zkclient.DataUpdater;
import org.apache.helix.zookeeper.zkclient.IZkChildListener;
import org.apache.helix.zookeeper.zkclient.IZkDataListener;
+import org.apache.helix.zookeeper.zkclient.IZkStateListener;
import org.apache.helix.zookeeper.zkclient.ZkConnection;
import org.apache.helix.zookeeper.zkclient.callback.ZkAsyncCallbacks;
-import org.apache.helix.zookeeper.zkclient.IZkStateListener;
import org.apache.helix.zookeeper.zkclient.serialize.BasicZkSerializer;
import org.apache.helix.zookeeper.zkclient.serialize.PathBasedZkSerializer;
import org.apache.helix.zookeeper.zkclient.serialize.ZkSerializer;
@@ -80,19 +83,27 @@ public class FederatedZkClient implements RealmAwareZkClient {
private PathBasedZkSerializer _pathBasedZkSerializer;
// TODO: support capacity of ZkClient number in one FederatedZkClient and do garbage collection.
- public FederatedZkClient(RealmAwareZkClient.RealmAwareZkClientConfig clientConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
- if (metadataStoreRoutingData == null) {
- throw new IllegalArgumentException("MetadataStoreRoutingData cannot be null!");
+ public FederatedZkClient(RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
+ RealmAwareZkClient.RealmAwareZkClientConfig clientConfig)
+ throws IOException, InvalidRoutingDataException {
+ if (connectionConfig == null) {
+ throw new IllegalArgumentException("RealmAwareZkConnectionConfig cannot be null!");
}
if (clientConfig == null) {
- throw new IllegalArgumentException("Client config cannot be null!");
+ throw new IllegalArgumentException("RealmAwareZkClientConfig cannot be null!");
+ }
+
+ // Attempt to get MetadataStoreRoutingData
+ String msdsEndpoint = connectionConfig.getMsdsEndpoint();
+ if (msdsEndpoint == null || msdsEndpoint.isEmpty()) {
+ _metadataStoreRoutingData = HttpRoutingDataReader.getMetadataStoreRoutingData();
+ } else {
+ _metadataStoreRoutingData = HttpRoutingDataReader.getMetadataStoreRoutingData(msdsEndpoint);
}
_isClosed = false;
_clientConfig = clientConfig;
_pathBasedZkSerializer = clientConfig.getZkSerializer();
- _metadataStoreRoutingData = metadataStoreRoutingData;
_zkRealmToZkClientMap = new ConcurrentHashMap<>();
}
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/SharedZkClient.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/SharedZkClient.java
index f2d9416..dd78aba 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/SharedZkClient.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/SharedZkClient.java
@@ -19,26 +19,27 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
+import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.HelixZkClient;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.impl.factory.SharedZkClientFactory;
+import org.apache.helix.zookeeper.util.HttpRoutingDataReader;
import org.apache.helix.zookeeper.zkclient.DataUpdater;
import org.apache.helix.zookeeper.zkclient.IZkChildListener;
import org.apache.helix.zookeeper.zkclient.IZkDataListener;
import org.apache.helix.zookeeper.zkclient.callback.ZkAsyncCallbacks;
import org.apache.helix.zookeeper.zkclient.deprecated.IZkStateListener;
-import org.apache.helix.zookeeper.zkclient.exception.ZkNoNodeException;
import org.apache.helix.zookeeper.zkclient.serialize.PathBasedZkSerializer;
import org.apache.helix.zookeeper.zkclient.serialize.ZkSerializer;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Op;
import org.apache.zookeeper.OpResult;
-import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
@@ -55,25 +56,34 @@ public class SharedZkClient implements RealmAwareZkClient {
private static Logger LOG = LoggerFactory.getLogger(SharedZkClient.class);
private final HelixZkClient _innerSharedZkClient;
- private final String _zkRealmShardingKey;
private final MetadataStoreRoutingData _metadataStoreRoutingData;
+ private final String _zkRealmShardingKey;
private final String _zkRealmAddress;
public SharedZkClient(RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- RealmAwareZkClient.RealmAwareZkClientConfig clientConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
-
+ RealmAwareZkClient.RealmAwareZkClientConfig clientConfig)
+ throws IOException, InvalidRoutingDataException {
if (connectionConfig == null) {
throw new IllegalArgumentException("RealmAwareZkConnectionConfig cannot be null!");
}
- _zkRealmShardingKey = connectionConfig.getZkRealmShardingKey();
+ if (clientConfig == null) {
+ throw new IllegalArgumentException("RealmAwareZkClientConfig cannot be null!");
+ }
- if (metadataStoreRoutingData == null) {
- throw new IllegalArgumentException("MetadataStoreRoutingData cannot be null!");
+ // Get the routing data from a static Singleton HttpRoutingDataReader
+ String msdsEndpoint = connectionConfig.getMsdsEndpoint();
+ if (msdsEndpoint == null || msdsEndpoint.isEmpty()) {
+ _metadataStoreRoutingData = HttpRoutingDataReader.getMetadataStoreRoutingData();
+ } else {
+ _metadataStoreRoutingData = HttpRoutingDataReader.getMetadataStoreRoutingData(msdsEndpoint);
+ }
+
+ _zkRealmShardingKey = connectionConfig.getZkRealmShardingKey();
+ if (_zkRealmShardingKey == null || _zkRealmShardingKey.isEmpty()) {
+ throw new IllegalArgumentException(
+ "RealmAwareZkConnectionConfig's ZK realm sharding key cannot be null or empty for SharedZkClient!");
}
- _metadataStoreRoutingData = metadataStoreRoutingData;
- // TODO: use _zkRealmShardingKey to generate zkRealmAddress. This can done the same way of pull 765 once @hunter check it in.
// Get the ZkRealm address based on the ZK path sharding key
String zkRealmAddress = _metadataStoreRoutingData.getMetadataStoreRealm(_zkRealmShardingKey);
if (zkRealmAddress == null || zkRealmAddress.isEmpty()) {
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/DedicatedZkClientFactory.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/DedicatedZkClientFactory.java
index 6694497..92d628c 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/DedicatedZkClientFactory.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/DedicatedZkClientFactory.java
@@ -19,7 +19,9 @@ package org.apache.helix.zookeeper.impl.factory;
* under the License.
*/
-import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
+import java.io.IOException;
+
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.HelixZkClient;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.impl.client.DedicatedZkClient;
@@ -37,9 +39,9 @@ public class DedicatedZkClientFactory extends HelixZkClientFactory {
@Override
public RealmAwareZkClient buildZkClient(
RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- RealmAwareZkClient.RealmAwareZkClientConfig clientConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
- return new DedicatedZkClient(connectionConfig, clientConfig, metadataStoreRoutingData);
+ RealmAwareZkClient.RealmAwareZkClientConfig clientConfig)
+ throws IOException, InvalidRoutingDataException {
+ return new DedicatedZkClient(connectionConfig, clientConfig);
}
private static class SingletonHelper {
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/SharedZkClientFactory.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/SharedZkClientFactory.java
index 80c58bf..fb46ef2 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/SharedZkClientFactory.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/factory/SharedZkClientFactory.java
@@ -19,10 +19,11 @@ package org.apache.helix.zookeeper.impl.factory;
* under the License.
*/
+import java.io.IOException;
import java.util.HashMap;
import java.util.List;
-import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.HelixZkClient;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.exception.ZkClientException;
@@ -57,18 +58,10 @@ public class SharedZkClientFactory extends HelixZkClientFactory {
@Override
public RealmAwareZkClient buildZkClient(
RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- RealmAwareZkClient.RealmAwareZkClientConfig clientConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
+ RealmAwareZkClient.RealmAwareZkClientConfig clientConfig)
+ throws IOException, InvalidRoutingDataException {
// Note, the logic sharing connectionManager logic is inside SharedZkClient, similar to innerSharedZkClient.
- return new SharedZkClient(connectionConfig, clientConfig, metadataStoreRoutingData);
- }
-
- @Override
- public RealmAwareZkClient buildZkClient(
- RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig,
- MetadataStoreRoutingData metadataStoreRoutingData) {
- // TODO: Implement the logic
- return null;
+ return new SharedZkClient(connectionConfig, clientConfig);
}
private static class SingletonHelper {
diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/util/HttpRoutingDataReader.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/util/HttpRoutingDataReader.java
index 04f6c44..b4c1f9c 100644
--- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/util/HttpRoutingDataReader.java
+++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/util/HttpRoutingDataReader.java
@@ -141,7 +141,8 @@ public class HttpRoutingDataReader {
* @throws IOException
*/
private static String getAllRoutingData() throws IOException {
- // Note that MSDS_ENDPOINT should provide high-availability - it risks becoming a single point of failure if it's backed by a single IP address/host
+ // Note that MSDS_ENDPOINT should provide high-availability - it risks becoming a single point
+ // of failure if it's backed by a single IP address/host
// Retry count is 3 by default.
HttpGet requestAllData = new HttpGet(
SYSTEM_MSDS_ENDPOINT + MetadataStoreRoutingConstants.MSDS_GET_ALL_ROUTING_DATA_ENDPOINT);
diff --git a/zookeeper-api/src/test/conf/testng.xml b/zookeeper-api/src/test/conf/testng.xml
index 0847f47..bf78089 100644
--- a/zookeeper-api/src/test/conf/testng.xml
+++ b/zookeeper-api/src/test/conf/testng.xml
@@ -18,8 +18,8 @@ specific language governing permissions and limitations
under the License.
-->
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
-<suite name="Suite" parallel="false">
- <test name="Test" preserve-order="true">
+<suite name="Suite" parallel="false" preserve-order="true">
+ <test name="Test">
<packages>
<package name="org.apache.helix.zookeeper.*"/>
</packages>
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/constant/TestConstants.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/constant/TestConstants.java
new file mode 100644
index 0000000..a217245
--- /dev/null
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/constant/TestConstants.java
@@ -0,0 +1,45 @@
+package org.apache.helix.zookeeper.constant;
+
+/*
+ * 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.Collection;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+
+/**
+ * Constants to be used for testing.
+ */
+public class TestConstants {
+ // ZK hostname prefix and port to be used throughout the zookeeper-api module
+ public static final String ZK_PREFIX = "localhost:";
+ public static final int ZK_START_PORT = 2127;
+
+ // Based on the ZK hostname constants, construct a set of fake routing data mappings
+ public static final Map<String, Collection<String>> FAKE_ROUTING_DATA = ImmutableMap
+ .of(ZK_PREFIX + ZK_START_PORT,
+ ImmutableList.of("/sharding-key-0", "/sharding-key-1", "/sharding-key-2"),
+ ZK_PREFIX + (ZK_START_PORT + 1),
+ ImmutableList.of("/sharding-key-3", "/sharding-key-4", "/sharding-key-5"),
+ ZK_PREFIX + (ZK_START_PORT + 2),
+ ImmutableList.of("/sharding-key-6", "/sharding-key-7", "/sharding-key-8"));
+}
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/ZkTestBase.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/ZkTestBase.java
index 7e59652..51eda80 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/ZkTestBase.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/ZkTestBase.java
@@ -29,6 +29,7 @@ import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import org.apache.commons.io.FileUtils;
+import org.apache.helix.zookeeper.constant.TestConstants;
import org.apache.helix.zookeeper.zkclient.IDefaultNameSpace;
import org.apache.helix.zookeeper.zkclient.ZkServer;
import org.slf4j.Logger;
@@ -50,8 +51,8 @@ public class ZkTestBase {
private static final String MULTI_ZK_PROPERTY_KEY = "multiZk";
private static final String NUM_ZK_PROPERTY_KEY = "numZk";
- protected static final String ZK_PREFIX = "localhost:";
- protected static final int ZK_START_PORT = 2127;
+ public static final String ZK_PREFIX = TestConstants.ZK_PREFIX;
+ public static final int ZK_START_PORT = TestConstants.ZK_START_PORT;
/*
* Multiple ZK references
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientFactoryTestBase.java
similarity index 61%
copy from zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java
copy to zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientFactoryTestBase.java
index 323d5f4..6c3555f 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientFactoryTestBase.java
@@ -19,55 +19,44 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import java.util.NoSuchElementException;
-import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
-import org.apache.helix.msdcommon.datamodel.TrieRoutingData;
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.api.factory.RealmAwareZkClientFactory;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
-import org.apache.helix.zookeeper.impl.ZkTestBase;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
- protected static final String ZK_SHARDING_KEY_PREFIX = "/TEST_SHARDING_KEY";
- protected static final String TEST_VALID_PATH = ZK_SHARDING_KEY_PREFIX + "_" + 0 + "/a/b/c";
- protected static final String TEST_INVALID_PATH = ZK_SHARDING_KEY_PREFIX + "_invalid" + "/a/b/c";
-
- // <Realm, List of sharding keys> Mapping
- private static final Map<String, List<String>> RAW_ROUTING_DATA = new HashMap<>();
-
+/**
+ * Test Base for DedicatedZkClient and SharedZkClient, which are implementations of
+ * RealmAwareZkClient.
+ * This class allows TestDedicatedZkClient and TestSharedZkClient to share the common test logic by
+ * just swapping out the factory classes.
+ */
+public abstract class RealmAwareZkClientFactoryTestBase extends RealmAwareZkClientTestBase {
// The following RealmAwareZkClientFactory is to be defined in subclasses
protected RealmAwareZkClientFactory _realmAwareZkClientFactory;
protected RealmAwareZkClient _realmAwareZkClient;
- private MetadataStoreRoutingData _metadataStoreRoutingData;
+ private static final ZNRecord DUMMY_RECORD = new ZNRecord("DummyRecord");
@BeforeClass
- public void beforeClass() throws Exception {
- // Populate RAW_ROUTING_DATA
- for (int i = 0; i < _numZk; i++) {
- List<String> shardingKeyList = new ArrayList<>();
- shardingKeyList.add(ZK_SHARDING_KEY_PREFIX + "_" + i);
- String realmName = ZK_PREFIX + (ZK_START_PORT + i);
- RAW_ROUTING_DATA.put(realmName, shardingKeyList);
- }
-
- // Feed the raw routing data into TrieRoutingData to construct an in-memory representation of routing information
- _metadataStoreRoutingData = new TrieRoutingData(RAW_ROUTING_DATA);
+ public void beforeClass() throws IOException, InvalidRoutingDataException {
+ super.beforeClass();
+ DUMMY_RECORD.setSimpleField("Dummy", "Value");
}
@AfterClass
public void afterClass() {
+ super.afterClass();
if (_realmAwareZkClient != null && !_realmAwareZkClient.isClosed()) {
_realmAwareZkClient.close();
+ _realmAwareZkClient = null;
}
}
@@ -80,7 +69,7 @@ public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
@Test
public void testRealmAwareZkClientCreation() {
// Create a RealmAwareZkClient
- String invalidShardingKey = "InvalidShardingKey";
+ String invalidShardingKey = "InvalidShardingKeyNoLeadingSlash";
RealmAwareZkClient.RealmAwareZkClientConfig clientConfig =
new RealmAwareZkClient.RealmAwareZkClientConfig();
@@ -91,19 +80,37 @@ public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
builder.setZkRealmShardingKey(invalidShardingKey).build();
try {
- _realmAwareZkClient = _realmAwareZkClientFactory
- .buildZkClient(connectionConfig, clientConfig, _metadataStoreRoutingData);
+ _realmAwareZkClient =
+ _realmAwareZkClientFactory.buildZkClient(connectionConfig, clientConfig);
Assert.fail("Should not succeed with an invalid sharding key!");
} catch (IllegalArgumentException e) {
- // Expected
+ // Expected because invalid sharding key would cause an IllegalArgumentException to be thrown
+ } catch (Exception e) {
+ Assert.fail("Should not see any other types of Exceptions: " + e);
+ }
+
+ // Create a connection config with a valid sharding key, but one that does not exist in
+ // the routing data
+ String nonExistentShardingKey = "/NonExistentShardingKey";
+ connectionConfig = builder.setZkRealmShardingKey(nonExistentShardingKey).build();
+ try {
+ _realmAwareZkClient =
+ _realmAwareZkClientFactory.buildZkClient(connectionConfig, clientConfig);
+ Assert.fail("Should not succeed with a non-existent sharding key!");
+ } catch (NoSuchElementException e) {
+ // Expected non-existent sharding key would cause a NoSuchElementException to be thrown
+ } catch (Exception e) {
+ Assert.fail("Should not see any other types of Exceptions: " + e);
}
// Use a valid sharding key this time around
- String validShardingKey = ZK_SHARDING_KEY_PREFIX + "_" + 0; // Use TEST_SHARDING_KEY_0
- builder.setZkRealmShardingKey(validShardingKey);
- connectionConfig = builder.build();
- _realmAwareZkClient = _realmAwareZkClientFactory
- .buildZkClient(connectionConfig, clientConfig, _metadataStoreRoutingData);
+ connectionConfig = builder.setZkRealmShardingKey(ZK_SHARDING_KEY_PREFIX).build();
+ try {
+ _realmAwareZkClient =
+ _realmAwareZkClientFactory.buildZkClient(connectionConfig, clientConfig);
+ } catch (Exception e) {
+ Assert.fail("All other exceptions not allowed: " + e);
+ }
}
/**
@@ -115,14 +122,10 @@ public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
public void testRealmAwareZkClientCreatePersistent() {
_realmAwareZkClient.setZkSerializer(new ZNRecordSerializer());
- // Create a dummy ZNRecord
- ZNRecord znRecord = new ZNRecord("DummyRecord");
- znRecord.setSimpleField("Dummy", "Value");
-
// Test writing and reading against the validPath
_realmAwareZkClient.createPersistent(TEST_VALID_PATH, true);
- _realmAwareZkClient.writeData(TEST_VALID_PATH, znRecord);
- Assert.assertEquals(_realmAwareZkClient.readData(TEST_VALID_PATH), znRecord);
+ _realmAwareZkClient.writeData(TEST_VALID_PATH, DUMMY_RECORD);
+ Assert.assertEquals(_realmAwareZkClient.readData(TEST_VALID_PATH), DUMMY_RECORD);
// Test writing and reading against the invalid path
try {
@@ -138,6 +141,12 @@ public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
*/
@Test(dependsOnMethods = "testRealmAwareZkClientCreatePersistent")
public void testExists() {
+ // Create a ZNode for testing
+ _realmAwareZkClient.createPersistent(TEST_VALID_PATH, true);
+ _realmAwareZkClient.writeData(TEST_VALID_PATH, DUMMY_RECORD);
+ Assert.assertEquals(_realmAwareZkClient.readData(TEST_VALID_PATH), DUMMY_RECORD);
+
+ // Test exists()
Assert.assertTrue(_realmAwareZkClient.exists(TEST_VALID_PATH));
try {
@@ -153,9 +162,14 @@ public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
*/
@Test(dependsOnMethods = "testExists")
public void testDelete() {
+ // Create a ZNode for testing
+ _realmAwareZkClient.createPersistent(TEST_VALID_PATH, true);
+ _realmAwareZkClient.writeData(TEST_VALID_PATH, DUMMY_RECORD);
+ Assert.assertEquals(_realmAwareZkClient.readData(TEST_VALID_PATH), DUMMY_RECORD);
+
try {
_realmAwareZkClient.delete(TEST_INVALID_PATH);
- Assert.fail("Exists() should not succeed on an invalid path!");
+ Assert.fail("delete() should not succeed on an invalid path!");
} catch (IllegalArgumentException e) {
// Okay - expected
}
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java
index 323d5f4..900c79f 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/RealmAwareZkClientTestBase.java
@@ -19,148 +19,48 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
-import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
-import org.apache.helix.msdcommon.datamodel.TrieRoutingData;
-import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
-import org.apache.helix.zookeeper.api.factory.RealmAwareZkClientFactory;
-import org.apache.helix.zookeeper.datamodel.ZNRecord;
-import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
+import org.apache.helix.msdcommon.constant.MetadataStoreRoutingConstants;
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
+import org.apache.helix.msdcommon.mock.MockMetadataStoreDirectoryServer;
+import org.apache.helix.zookeeper.constant.TestConstants;
import org.apache.helix.zookeeper.impl.ZkTestBase;
-import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
-import org.testng.annotations.Test;
public abstract class RealmAwareZkClientTestBase extends ZkTestBase {
- protected static final String ZK_SHARDING_KEY_PREFIX = "/TEST_SHARDING_KEY";
- protected static final String TEST_VALID_PATH = ZK_SHARDING_KEY_PREFIX + "_" + 0 + "/a/b/c";
+ protected static final String ZK_SHARDING_KEY_PREFIX = "/sharding-key-0";
+ protected static final String TEST_VALID_PATH = ZK_SHARDING_KEY_PREFIX + "/a/b/c";
protected static final String TEST_INVALID_PATH = ZK_SHARDING_KEY_PREFIX + "_invalid" + "/a/b/c";
- // <Realm, List of sharding keys> Mapping
- private static final Map<String, List<String>> RAW_ROUTING_DATA = new HashMap<>();
-
- // The following RealmAwareZkClientFactory is to be defined in subclasses
- protected RealmAwareZkClientFactory _realmAwareZkClientFactory;
- protected RealmAwareZkClient _realmAwareZkClient;
- private MetadataStoreRoutingData _metadataStoreRoutingData;
+ // Create a MockMSDS for testing
+ private static MockMetadataStoreDirectoryServer _msdsServer;
+ private static final String MSDS_HOSTNAME = "localhost";
+ private static final int MSDS_PORT = 1111;
+ private static final String MSDS_NAMESPACE = "test";
@BeforeClass
- public void beforeClass() throws Exception {
- // Populate RAW_ROUTING_DATA
- for (int i = 0; i < _numZk; i++) {
- List<String> shardingKeyList = new ArrayList<>();
- shardingKeyList.add(ZK_SHARDING_KEY_PREFIX + "_" + i);
- String realmName = ZK_PREFIX + (ZK_START_PORT + i);
- RAW_ROUTING_DATA.put(realmName, shardingKeyList);
+ public void beforeClass() throws IOException, InvalidRoutingDataException {
+ // Create a mock MSDS so that HttpRoudingDataReader could fetch the routing data
+ if (_msdsServer == null) {
+ // Do not create again if Mock MSDS server has already been created by other tests
+ _msdsServer = new MockMetadataStoreDirectoryServer(MSDS_HOSTNAME, MSDS_PORT, MSDS_NAMESPACE,
+ TestConstants.FAKE_ROUTING_DATA);
+ _msdsServer.startServer();
}
- // Feed the raw routing data into TrieRoutingData to construct an in-memory representation of routing information
- _metadataStoreRoutingData = new TrieRoutingData(RAW_ROUTING_DATA);
+ // Register the MSDS endpoint as a System variable
+ String msdsEndpoint =
+ "http://" + MSDS_HOSTNAME + ":" + MSDS_PORT + "/admin/v2/namespaces/" + MSDS_NAMESPACE;
+ System.setProperty(MetadataStoreRoutingConstants.MSDS_SERVER_ENDPOINT_KEY, msdsEndpoint);
}
@AfterClass
public void afterClass() {
- if (_realmAwareZkClient != null && !_realmAwareZkClient.isClosed()) {
- _realmAwareZkClient.close();
- }
- }
-
- /**
- * 1. Create a RealmAwareZkClient with a non-existing sharding key (for which there is no valid ZK realm)
- * -> This should fail with an exception
- * 2. Create a RealmAwareZkClient with a valid sharding key
- * -> This should pass
- */
- @Test
- public void testRealmAwareZkClientCreation() {
- // Create a RealmAwareZkClient
- String invalidShardingKey = "InvalidShardingKey";
- RealmAwareZkClient.RealmAwareZkClientConfig clientConfig =
- new RealmAwareZkClient.RealmAwareZkClientConfig();
-
- // Create a connection config with the invalid sharding key
- RealmAwareZkClient.RealmAwareZkConnectionConfig.Builder builder =
- new RealmAwareZkClient.RealmAwareZkConnectionConfig.Builder();
- RealmAwareZkClient.RealmAwareZkConnectionConfig connectionConfig =
- builder.setZkRealmShardingKey(invalidShardingKey).build();
-
- try {
- _realmAwareZkClient = _realmAwareZkClientFactory
- .buildZkClient(connectionConfig, clientConfig, _metadataStoreRoutingData);
- Assert.fail("Should not succeed with an invalid sharding key!");
- } catch (IllegalArgumentException e) {
- // Expected
+ if (_msdsServer != null) {
+ _msdsServer.stopServer();
}
-
- // Use a valid sharding key this time around
- String validShardingKey = ZK_SHARDING_KEY_PREFIX + "_" + 0; // Use TEST_SHARDING_KEY_0
- builder.setZkRealmShardingKey(validShardingKey);
- connectionConfig = builder.build();
- _realmAwareZkClient = _realmAwareZkClientFactory
- .buildZkClient(connectionConfig, clientConfig, _metadataStoreRoutingData);
- }
-
- /**
- * Test the persistent create() call against a valid path and an invalid path.
- * Valid path is one that belongs to the realm designated by the sharding key.
- * Invalid path is one that does not belong to the realm designated by the sharding key.
- */
- @Test(dependsOnMethods = "testRealmAwareZkClientCreation")
- public void testRealmAwareZkClientCreatePersistent() {
- _realmAwareZkClient.setZkSerializer(new ZNRecordSerializer());
-
- // Create a dummy ZNRecord
- ZNRecord znRecord = new ZNRecord("DummyRecord");
- znRecord.setSimpleField("Dummy", "Value");
-
- // Test writing and reading against the validPath
- _realmAwareZkClient.createPersistent(TEST_VALID_PATH, true);
- _realmAwareZkClient.writeData(TEST_VALID_PATH, znRecord);
- Assert.assertEquals(_realmAwareZkClient.readData(TEST_VALID_PATH), znRecord);
-
- // Test writing and reading against the invalid path
- try {
- _realmAwareZkClient.createPersistent(TEST_INVALID_PATH, true);
- Assert.fail("Create() should not succeed on an invalid path!");
- } catch (IllegalArgumentException e) {
- // Okay - expected
- }
- }
-
- /**
- * Test that exists() works on valid path and fails on invalid path.
- */
- @Test(dependsOnMethods = "testRealmAwareZkClientCreatePersistent")
- public void testExists() {
- Assert.assertTrue(_realmAwareZkClient.exists(TEST_VALID_PATH));
-
- try {
- _realmAwareZkClient.exists(TEST_INVALID_PATH);
- Assert.fail("Exists() should not succeed on an invalid path!");
- } catch (IllegalArgumentException e) {
- // Okay - expected
- }
- }
-
- /**
- * Test that delete() works on valid path and fails on invalid path.
- */
- @Test(dependsOnMethods = "testExists")
- public void testDelete() {
- try {
- _realmAwareZkClient.delete(TEST_INVALID_PATH);
- Assert.fail("Exists() should not succeed on an invalid path!");
- } catch (IllegalArgumentException e) {
- // Okay - expected
- }
-
- Assert.assertTrue(_realmAwareZkClient.delete(TEST_VALID_PATH));
- Assert.assertFalse(_realmAwareZkClient.exists(TEST_VALID_PATH));
}
}
\ No newline at end of file
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java
index 8cf3f85..fe8d8bd 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestDedicatedZkClient.java
@@ -19,15 +19,17 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
+import java.io.IOException;
+
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.impl.factory.DedicatedZkClientFactory;
import org.testng.annotations.BeforeClass;
-public class TestDedicatedZkClient extends RealmAwareZkClientTestBase {
+public class TestDedicatedZkClient extends RealmAwareZkClientFactoryTestBase {
@BeforeClass
- public void beforeClass()
- throws Exception {
+ public void beforeClass() throws IOException, InvalidRoutingDataException {
super.beforeClass();
// Set the factory to DedicatedZkClientFactory
_realmAwareZkClientFactory = DedicatedZkClientFactory.getInstance();
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestFederatedZkClient.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestFederatedZkClient.java
index 5801690..0472df7 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestFederatedZkClient.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestFederatedZkClient.java
@@ -19,22 +19,17 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
+import java.io.IOException;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.NoSuchElementException;
import java.util.concurrent.TimeUnit;
-import org.apache.helix.msdcommon.datamodel.TrieRoutingData;
import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.api.client.RealmAwareZkClient;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
-import org.apache.helix.zookeeper.impl.ZkTestBase;
import org.apache.helix.zookeeper.zkclient.IZkStateListener;
-import org.apache.helix.zookeeper.zkclient.ZkServer;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.Op;
import org.apache.zookeeper.Watcher;
@@ -45,57 +40,33 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-public class TestFederatedZkClient extends ZkTestBase {
- private static final String TEST_SHARDING_KEY_PREFIX = "/test_sharding_key_";
- private static final String TEST_REALM_ONE_VALID_PATH = TEST_SHARDING_KEY_PREFIX + "1/a/b/c";
- private static final String TEST_REALM_TWO_VALID_PATH = TEST_SHARDING_KEY_PREFIX + "2/x/y/z";
+public class TestFederatedZkClient extends RealmAwareZkClientTestBase {
+ private static final String TEST_SHARDING_KEY_PREFIX = ZK_SHARDING_KEY_PREFIX;
+ private static final String TEST_REALM_ONE_VALID_PATH = TEST_SHARDING_KEY_PREFIX + "/1/a/b/c";
+ private static final String TEST_REALM_TWO_VALID_PATH = TEST_SHARDING_KEY_PREFIX + "/2/x/y/z";
private static final String TEST_INVALID_PATH = TEST_SHARDING_KEY_PREFIX + "invalid/a/b/c";
private static final String UNSUPPORTED_OPERATION_MESSAGE =
"Session-aware operation is not supported by FederatedZkClient.";
private RealmAwareZkClient _realmAwareZkClient;
- // Need to start an extra ZK server for multi-realm test, if only one ZK server is running.
- private String _extraZkRealm;
- private ZkServer _extraZkServer;
@BeforeClass
- public void beforeClass() throws InvalidRoutingDataException {
+ public void beforeClass() throws IOException, InvalidRoutingDataException {
System.out.println("Starting " + TestFederatedZkClient.class.getSimpleName());
-
- // Populate rawRoutingData
- // <Realm, List of sharding keys> Mapping
- Map<String, List<String>> rawRoutingData = new HashMap<>();
- for (int i = 0; i < _numZk; i++) {
- List<String> shardingKeyList = Collections.singletonList(TEST_SHARDING_KEY_PREFIX + (i + 1));
- String realmName = ZK_PREFIX + (ZK_START_PORT + i);
- rawRoutingData.put(realmName, shardingKeyList);
- }
-
- if (rawRoutingData.size() < 2) {
- System.out.println("There is only one ZK realm. Starting one more ZK to test multi-realm.");
- _extraZkRealm = ZK_PREFIX + (ZK_START_PORT + 1);
- _extraZkServer = startZkServer(_extraZkRealm);
- // RealmTwo's sharding key: /test_sharding_key_2
- List<String> shardingKeyList = Collections.singletonList(TEST_SHARDING_KEY_PREFIX + "2");
- rawRoutingData.put(_extraZkRealm, shardingKeyList);
- }
+ super.beforeClass();
// Feed the raw routing data into TrieRoutingData to construct an in-memory representation
// of routing information.
- _realmAwareZkClient = new FederatedZkClient(new RealmAwareZkClient.RealmAwareZkClientConfig(),
- new TrieRoutingData(rawRoutingData));
+ _realmAwareZkClient =
+ new FederatedZkClient(new RealmAwareZkClient.RealmAwareZkConnectionConfig.Builder().build(),
+ new RealmAwareZkClient.RealmAwareZkClientConfig());
}
@AfterClass
public void afterClass() {
+ super.afterClass();
// Close it as it is created in before class.
_realmAwareZkClient.close();
-
- // Close the extra zk server.
- if (_extraZkServer != null) {
- _extraZkServer.shutdown();
- }
-
System.out.println("Ending " + TestFederatedZkClient.class.getSimpleName());
}
@@ -103,7 +74,7 @@ public class TestFederatedZkClient extends ZkTestBase {
* Tests that an unsupported operation should throw an UnsupportedOperationException.
*/
@Test
- public void testUnsupportedOperations() {
+ public void testUnsupportedOperations() throws IOException, InvalidRoutingDataException {
// Test creating ephemeral.
try {
_realmAwareZkClient.create(TEST_REALM_ONE_VALID_PATH, "Hello", CreateMode.EPHEMERAL);
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestSharedZkClient.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestSharedZkClient.java
index 1dd44f6..08ec790 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestSharedZkClient.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/impl/client/TestSharedZkClient.java
@@ -19,6 +19,9 @@ package org.apache.helix.zookeeper.impl.client;
* under the License.
*/
+import java.io.IOException;
+
+import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.zookeeper.datamodel.ZNRecord;
import org.apache.helix.zookeeper.datamodel.serializer.ZNRecordSerializer;
import org.apache.helix.zookeeper.impl.factory.SharedZkClientFactory;
@@ -28,9 +31,10 @@ import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
-public class TestSharedZkClient extends RealmAwareZkClientTestBase {
+public class TestSharedZkClient extends RealmAwareZkClientFactoryTestBase {
+
@BeforeClass
- public void beforeClass() throws Exception {
+ public void beforeClass() throws IOException, InvalidRoutingDataException {
super.beforeClass();
// Set the factory to SharedZkClientFactory
_realmAwareZkClientFactory = SharedZkClientFactory.getInstance();
diff --git a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/util/TestHttpRoutingDataReader.java b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/util/TestHttpRoutingDataReader.java
index 1eccd1a..5c52d05 100644
--- a/zookeeper-api/src/test/java/org/apache/helix/zookeeper/util/TestHttpRoutingDataReader.java
+++ b/zookeeper-api/src/test/java/org/apache/helix/zookeeper/util/TestHttpRoutingDataReader.java
@@ -33,6 +33,7 @@ import org.apache.helix.msdcommon.constant.MetadataStoreRoutingConstants;
import org.apache.helix.msdcommon.datamodel.MetadataStoreRoutingData;
import org.apache.helix.msdcommon.exception.InvalidRoutingDataException;
import org.apache.helix.msdcommon.mock.MockMetadataStoreDirectoryServer;
+import org.apache.helix.zookeeper.constant.TestConstants;
import org.apache.helix.zookeeper.impl.ZkTestBase;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
@@ -42,25 +43,15 @@ import org.testng.annotations.Test;
public class TestHttpRoutingDataReader extends ZkTestBase {
private MockMetadataStoreDirectoryServer _msdsServer;
- private Map<String, Collection<String>> _testRawRoutingData;
private final String _host = "localhost";
private final int _port = 1991;
private final String _namespace = "TestHttpRoutingDataReader";
@BeforeClass
public void beforeClass() throws IOException {
- // Create fake routing data
- _testRawRoutingData = new HashMap<>();
- _testRawRoutingData
- .put("zk-0", ImmutableSet.of("/sharding-key-0", "/sharding-key-1", "/sharding-key-2"));
- _testRawRoutingData
- .put("zk-1", ImmutableSet.of("/sharding-key-3", "/sharding-key-4", "/sharding-key-5"));
- _testRawRoutingData
- .put("zk-2", ImmutableSet.of("/sharding-key-6", "/sharding-key-7", "/sharding-key-8"));
-
// Start MockMSDS
- _msdsServer =
- new MockMetadataStoreDirectoryServer(_host, _port, _namespace, _testRawRoutingData);
+ _msdsServer = new MockMetadataStoreDirectoryServer(_host, _port, _namespace,
+ TestConstants.FAKE_ROUTING_DATA);
_msdsServer.startServer();
// Register the endpoint as a System property
@@ -76,7 +67,7 @@ public class TestHttpRoutingDataReader extends ZkTestBase {
@Test
public void testGetRawRoutingData() throws IOException {
Map<String, List<String>> rawRoutingData = HttpRoutingDataReader.getRawRoutingData();
- _testRawRoutingData.forEach((realm, keys) -> Assert
+ TestConstants.FAKE_ROUTING_DATA.forEach((realm, keys) -> Assert
.assertEquals(new HashSet(rawRoutingData.get(realm)), new HashSet(keys)));
}
@@ -87,8 +78,10 @@ public class TestHttpRoutingDataReader extends ZkTestBase {
Map<String, Set<String>> groupedMappings = allMappings.entrySet().stream().collect(Collectors
.groupingBy(Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toSet())));
- _testRawRoutingData.forEach(
- (realm, keys) -> Assert.assertEquals(groupedMappings.get(realm), new HashSet(keys)));
+
+ TestConstants.FAKE_ROUTING_DATA.forEach((realm, keys) -> {
+ Assert.assertEquals(groupedMappings.get(realm), new HashSet(keys));
+ });
}
/**
@@ -98,12 +91,12 @@ public class TestHttpRoutingDataReader extends ZkTestBase {
public void testStaticMapping() throws IOException, InvalidRoutingDataException {
// Modify routing data
String newRealm = "newRealm";
- _testRawRoutingData.put(newRealm, ImmutableSet.of("/newKey"));
+ Map<String, Collection<String>> newRoutingData = new HashMap<>(TestConstants.FAKE_ROUTING_DATA);
+ newRoutingData.put(newRealm, ImmutableSet.of("/newKey"));
// Kill MSDS and restart with a new mapping
_msdsServer.stopServer();
- _msdsServer =
- new MockMetadataStoreDirectoryServer(_host, _port, _namespace, _testRawRoutingData);
+ _msdsServer = new MockMetadataStoreDirectoryServer(_host, _port, _namespace, newRoutingData);
_msdsServer.startServer();
// HttpRoutingDataReader should still return old data because it's static
@@ -112,9 +105,9 @@ public class TestHttpRoutingDataReader extends ZkTestBase {
Assert.assertFalse(rawRoutingData.containsKey(newRealm));
// Remove newRealm and check for equality
- _testRawRoutingData.remove(newRealm);
- Assert.assertEquals(rawRoutingData.keySet(), _testRawRoutingData.keySet());
- _testRawRoutingData.forEach((realm, keys) -> Assert
+ newRoutingData.remove(newRealm);
+ Assert.assertEquals(rawRoutingData.keySet(), TestConstants.FAKE_ROUTING_DATA.keySet());
+ TestConstants.FAKE_ROUTING_DATA.forEach((realm, keys) -> Assert
.assertEquals(new HashSet(rawRoutingData.get(realm)), new HashSet(keys)));
MetadataStoreRoutingData data = HttpRoutingDataReader.getMetadataStoreRoutingData();