From 0e064ddd62036ecd309361817ab9fff604ad7bd3 Mon Sep 17 00:00:00 2001 From: xyuanlu Date: Thu, 12 Oct 2023 11:57:40 -0700 Subject: [PATCH] property --- .../HelixRestDataProviderManager.java | 68 ++++++++++++++ .../dataprovider/PerClusterDataProvider.java | 91 +++++++++++++++++++ .../dataprovider/RestCurrentStateCache.java | 42 +++++++++ .../dataprovider/RestPropertyCache.java | 82 +++++++++++++++++ .../dataprovider/RestServiceDataProvider.java | 43 +++++++++ .../helix/rest/server/ServerContext.java | 15 +++ .../api/client/RealmAwareZkClient.java | 13 +++ .../impl/client/DedicatedZkClient.java | 11 +++ .../impl/client/FederatedZkClient.java | 11 +++ .../helix/zookeeper/impl/client/ZkClient.java | 1 + 10 files changed, 377 insertions(+) create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/HelixRestDataProviderManager.java create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/PerClusterDataProvider.java create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestCurrentStateCache.java create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestPropertyCache.java create mode 100644 helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestServiceDataProvider.java diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/HelixRestDataProviderManager.java b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/HelixRestDataProviderManager.java new file mode 100644 index 0000000000..58d59fc87d --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/HelixRestDataProviderManager.java @@ -0,0 +1,68 @@ +package org.apache.helix.rest.common.dataprovider; + +/* + * 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. + * + */ + +/** Init, register listener and manager callback handler for different + * clusters manage the providers lifecycle + * + */ + +import java.util.List; +import org.apache.helix.HelixAdmin; +import org.apache.helix.manager.zk.ZkBaseDataAccessor; +import org.apache.helix.zookeeper.api.client.RealmAwareZkClient; + + +public class HelixRestDataProviderManager { + + protected RealmAwareZkClient _zkclient; + + private HelixAdmin _helixAdmin; + + private RestServiceDataProvider _restServiceDataProvider; + // list of callback handlers + + //TODO: create own zk client + public HelixRestDataProviderManager(RealmAwareZkClient zkclient, HelixAdmin helixAdmin) { + _zkclient = zkclient; + _helixAdmin = helixAdmin; + _restServiceDataProvider = new RestServiceDataProvider(); + init(); + } + + public RestServiceDataProvider getRestServiceDataProvider() { + return _restServiceDataProvider; + } + + private void init() { + List clusters = _helixAdmin.getClusters(); + for (String cluster : clusters) { + PerClusterDataProvider clusterDataProvider = + new PerClusterDataProvider(cluster, _zkclient, new ZkBaseDataAccessor(_zkclient)); + clusterDataProvider.initCache(); + // register callback handler for each provider + _restServiceDataProvider.addClusterDataProvider(cluster, clusterDataProvider); + } + } + + public void close() { + } +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/PerClusterDataProvider.java b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/PerClusterDataProvider.java new file mode 100644 index 0000000000..adcde81f28 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/PerClusterDataProvider.java @@ -0,0 +1,91 @@ +package org.apache.helix.rest.common.dataprovider; + +/* + * 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.Map; +import org.apache.helix.BaseDataAccessor; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.PropertyKey; +import org.apache.helix.common.caches.PropertyCache; +import org.apache.helix.manager.zk.ZKHelixDataAccessor; +import org.apache.helix.model.ClusterConfig; +import org.apache.helix.model.ClusterConstraints; +import org.apache.helix.model.CurrentState; +import org.apache.helix.model.ExternalView; +import org.apache.helix.model.IdealState; +import org.apache.helix.model.InstanceConfig; +import org.apache.helix.model.LiveInstance; +import org.apache.helix.model.ResourceConfig; +import org.apache.helix.model.StateModelDefinition; +import org.apache.helix.zookeeper.api.client.RealmAwareZkClient; + + +/** + * Dara cache for each Helix cluster. Configs, ideal stats and current states are read from ZK and updated + * using event changes. External view are consolidated using current state. + */ +public class PerClusterDataProvider { + + private HelixDataAccessor _accessor; + + private RealmAwareZkClient _zkclient; + + private final String _clusterName; + + // Simple caches + private final RestPropertyCache _instanceConfigCache; + private final RestPropertyCache _clusterConfigCache; + private final RestPropertyCache _resourceConfigCache; + private final RestPropertyCache _liveInstanceCache; + private final RestPropertyCache _idealStateCache; + private final RestPropertyCache _stateModelDefinitionCache; + + // special caches + private final RestCurrentStateCache _currentStateCache; + + // TODO: add external view caches + + public PerClusterDataProvider(String clusterName, RealmAwareZkClient zkClient, BaseDataAccessor baseDataAccessor) { + _clusterName = clusterName; + _accessor = new ZKHelixDataAccessor(clusterName, baseDataAccessor); + + _zkclient = zkClient; + _instanceConfigCache = null; + _clusterConfigCache = null; + _resourceConfigCache = null; + _liveInstanceCache = null; + _idealStateCache = null; + _stateModelDefinitionCache = null; + _currentStateCache = null; + } + // TODO: consolidate EV from CSs + public Map consolidateExternalViews() { + return null; + } + + // Used for dummy cache. Remove later + public void initCache(final HelixDataAccessor accessor) { + + } + + public void initCache() { + + } +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestCurrentStateCache.java b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestCurrentStateCache.java new file mode 100644 index 0000000000..c92f4ce5b7 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestCurrentStateCache.java @@ -0,0 +1,42 @@ +package org.apache.helix.rest.common.dataprovider; + +/* + * 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.concurrent.ConcurrentHashMap; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.model.CurrentState; + + +/** + * Special cache for instances current states. + * + */ +public class RestCurrentStateCache { + + //Map> + private ConcurrentHashMap> _objCache; + + public RestCurrentStateCache() { + _objCache = new ConcurrentHashMap<>(); + } + + public void init(final HelixDataAccessor accessor) { + } +} \ No newline at end of file diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestPropertyCache.java b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestPropertyCache.java new file mode 100644 index 0000000000..7cc129f136 --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestPropertyCache.java @@ -0,0 +1,82 @@ +package org.apache.helix.rest.common.dataprovider; + +/* + * 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.Collections; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.HelixProperty; +import org.apache.helix.PropertyKey; +import org.apache.helix.common.caches.PropertyCache; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Class for caching simple HelixProperty objects. + * @param + */ +public class RestPropertyCache { + private static final Logger LOG = LoggerFactory.getLogger(RestPropertyCache.class); + + private ConcurrentHashMap _objCache; + private final String _propertyDescription; + + private final RestPropertyCache.PropertyCacheKeyFuncs _keyFuncs; + + public interface PropertyCacheKeyFuncs { + /** + * Get PropertyKey for the root of this type of object, used for LIST all objects + * @return property key to object root + */ + PropertyKey getRootKey(HelixDataAccessor accessor); + + /** + * Get PropertyKey for a single object of this type, used for GET single instance of the type + * @param objName object name + * @return property key to the object instance + */ + PropertyKey getObjPropertyKey(HelixDataAccessor accessor, String objName); + + /** + * Get the string to identify the object when we actually use them. It's not necessarily the + * "id" field of HelixProperty, but could have more semantic meanings of that object type + * @param obj object instance + * @return object identifier + */ + String getObjName(O obj); + } + + public RestPropertyCache(String propertyDescription, RestPropertyCache.PropertyCacheKeyFuncs keyFuncs) { + _keyFuncs = keyFuncs; + _propertyDescription = propertyDescription; + } + + public void init(final HelixDataAccessor accessor) { + _objCache = new ConcurrentHashMap<>(accessor.getChildValuesMap(_keyFuncs.getRootKey(accessor), true)); + LOG.info("Init RestPropertyCache for {}. ", _propertyDescription); + } + + public Map getPropertyMap() { + return Collections.unmodifiableMap(_objCache); + } + +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestServiceDataProvider.java b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestServiceDataProvider.java new file mode 100644 index 0000000000..d880dbf7ce --- /dev/null +++ b/helix-rest/src/main/java/org/apache/helix/rest/common/dataprovider/RestServiceDataProvider.java @@ -0,0 +1,43 @@ +package org.apache.helix.rest.common.dataprovider; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.HashMap; +import java.util.Map; + + +public class RestServiceDataProvider { + protected Map _clusterDataProviders ; + + + public RestServiceDataProvider() { + _clusterDataProviders = new HashMap<>(); + } + + public PerClusterDataProvider getClusterData(String clusterName) { + return _clusterDataProviders.get(clusterName); + } + + public void addClusterDataProvider(String clusterName, PerClusterDataProvider clusterData) { + _clusterDataProviders.put(clusterName, clusterData); + } + + +} diff --git a/helix-rest/src/main/java/org/apache/helix/rest/server/ServerContext.java b/helix-rest/src/main/java/org/apache/helix/rest/server/ServerContext.java index d355db0fe8..3ab0b97f58 100644 --- a/helix-rest/src/main/java/org/apache/helix/rest/server/ServerContext.java +++ b/helix-rest/src/main/java/org/apache/helix/rest/server/ServerContext.java @@ -35,6 +35,8 @@ import org.apache.helix.manager.zk.ZkBaseDataAccessor; import org.apache.helix.manager.zk.ZkBucketDataAccessor; import org.apache.helix.msdcommon.exception.InvalidRoutingDataException; +import org.apache.helix.rest.common.dataprovider.HelixRestDataProviderManager; +import org.apache.helix.rest.common.dataprovider.RestServiceDataProvider; import org.apache.helix.rest.metadatastore.ZkMetadataStoreDirectory; import org.apache.helix.task.TaskDriver; import org.apache.helix.tools.ClusterSetup; @@ -80,6 +82,8 @@ public class ServerContext implements IZkDataListener, IZkChildListener, IZkStat // Create ZkBucketDataAccessor for ReadOnlyWagedRebalancer. private volatile ZkBucketDataAccessor _zkBucketDataAccessor; + private volatile HelixRestDataProviderManager _helixRestDataProviderManager; + /** * Multi-ZK support */ @@ -292,6 +296,17 @@ public ZkBucketDataAccessor getZkBucketDataAccessor() { return _zkBucketDataAccessor; } + public HelixRestDataProviderManager getHelixRestDataProviderManager() { + if (_helixRestDataProviderManager == null) { + synchronized (this) { + if (_helixRestDataProviderManager == null) { + _helixRestDataProviderManager = new HelixRestDataProviderManager(getRealmAwareZkClient(), getHelixAdmin()); + } + } + } + return _helixRestDataProviderManager; + } + public void close() { if (_zkClient != null) { _zkClient.close(); diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/client/RealmAwareZkClient.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/client/RealmAwareZkClient.java index ac0240d5f5..7abbd23599 100644 --- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/client/RealmAwareZkClient.java +++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/api/client/RealmAwareZkClient.java @@ -31,6 +31,7 @@ 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.RecursivePersistListener; import org.apache.helix.zookeeper.zkclient.callback.ZkAsyncCallbacks; import org.apache.helix.zookeeper.zkclient.exception.ZkTimeoutException; import org.apache.helix.zookeeper.zkclient.serialize.BasicZkSerializer; @@ -164,6 +165,18 @@ void subscribeStateChanges( void unsubscribeStateChanges( org.apache.helix.zookeeper.zkclient.deprecated.IZkStateListener listener); + default void subscribePersistRecursiveListener(String path, + RecursivePersistListener recursivePersistListener) { + throw new UnsupportedOperationException( + "subscribePersistRecursiveListener() is not supported!"); + } + + default void unsubscribePersistRecursiveListener(String path, + RecursivePersistListener recursivePersistListener) { + throw new UnsupportedOperationException( + "subscribePersistRecursiveListener() is not supported!"); + } + void unsubscribeAll(); // data access 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 8dba7d81ef..143300d3b1 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 @@ -35,6 +35,7 @@ import org.apache.helix.zookeeper.zkclient.IZkChildListener; import org.apache.helix.zookeeper.zkclient.IZkConnection; import org.apache.helix.zookeeper.zkclient.IZkDataListener; +import org.apache.helix.zookeeper.zkclient.RecursivePersistListener; import org.apache.helix.zookeeper.zkclient.ZkConnection; import org.apache.helix.zookeeper.zkclient.callback.ZkAsyncCallbacks; import org.apache.helix.zookeeper.zkclient.deprecated.IZkStateListener; @@ -156,6 +157,16 @@ public void unsubscribeStateChanges(IZkStateListener listener) { _rawZkClient.unsubscribeStateChanges(listener); } + @Override + public void subscribePersistRecursiveListener(String path, RecursivePersistListener recursivePersistListener) { + + } + + @Override + public void unsubscribePersistRecursiveListener(String path, RecursivePersistListener recursivePersistListener) { + + } + @Override public void unsubscribeAll() { _rawZkClient.unsubscribeAll(); 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 8069985e3f..d0ddae18f4 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 @@ -38,6 +38,7 @@ 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.RecursivePersistListener; import org.apache.helix.zookeeper.zkclient.ZkConnection; import org.apache.helix.zookeeper.zkclient.callback.ZkAsyncCallbacks; import org.apache.helix.zookeeper.zkclient.serialize.BasicZkSerializer; @@ -158,6 +159,16 @@ public void unsubscribeStateChanges( throwUnsupportedOperationException(); } + @Override + public void subscribePersistRecursiveListener(String path, RecursivePersistListener recursivePersistListener) { + + } + + @Override + public void unsubscribePersistRecursiveListener(String path, RecursivePersistListener recursivePersistListener) { + + } + @Override public void unsubscribeAll() { _zkRealmToZkClientMap.values().forEach(ZkClient::unsubscribeAll); diff --git a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/ZkClient.java b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/ZkClient.java index 1dd601c21e..3ff9dc0581 100644 --- a/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/ZkClient.java +++ b/zookeeper-api/src/main/java/org/apache/helix/zookeeper/impl/client/ZkClient.java @@ -22,6 +22,7 @@ import org.apache.helix.zookeeper.api.client.HelixZkClient; import org.apache.helix.zookeeper.exception.ZkClientException; import org.apache.helix.zookeeper.zkclient.IZkConnection; +import org.apache.helix.zookeeper.zkclient.RecursivePersistListener; import org.apache.helix.zookeeper.zkclient.ZkConnection; import org.apache.helix.zookeeper.zkclient.serialize.BasicZkSerializer; import org.apache.helix.zookeeper.zkclient.serialize.PathBasedZkSerializer;