This is an automated email from the ASF dual-hosted git repository. xyuanlu pushed a commit to branch metaclient in repository https://gitbox.apache.org/repos/asf/helix.git
commit 8629a81441fb54dc809755bdf94b283c57cf5764 Author: xyuanlu <[email protected]> AuthorDate: Mon Nov 21 11:32:03 2022 -0800 Add listener interfaces and config class (#2249) Add listener interfaces and factory class for metaclient interface --- .../apache/helix/metaclient/api/AsyncCallback.java | 36 +- .../helix/metaclient/api/ChildChangeListener.java | 39 +++ .../metaclient/api/ConnectStateChangeListener.java | 39 +++ .../helix/metaclient/api/DataChangeListener.java | 33 ++ .../metaclient/api/DirectChildChangeListener.java | 37 ++ .../metaclient/api/DirectChildSubscribeResult.java | 45 +++ .../helix/metaclient/api/MetaClientInterface.java | 371 ++++++++++++++++++--- .../metaclient/factories/MetaClientConfig.java | 115 +++++++ .../metaclient/factories/MetaClientFactory.java | 37 ++ .../helix/metaclient/impl/zk/ZkMetaClient.java | 245 ++++++++++++++ 10 files changed, 954 insertions(+), 43 deletions(-) diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/AsyncCallback.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/AsyncCallback.java index 1bfa5c6ab..88ae31623 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/api/AsyncCallback.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/AsyncCallback.java @@ -22,28 +22,58 @@ package org.apache.helix.metaclient.api; import java.util.List; /** - * An asynchronous callback is deferred to invoke after an async CRUD operation returns. - * The corresponding callback is registered when async CRUD API is invoked. + * An asynchronous callback is deferred to invoke after an async CRUD operation finish and return. + * The corresponding callback is registered when async CRUD API is invoked. Implementation processes + * the result of each CRUD call. It should check return code and perform accordingly. */ +// TODO: define return code. failure code should map to MetaClient exceptions. public interface AsyncCallback { //This callback is used when stat object is returned from the operation. interface StatCallback extends AsyncCallback { + /** + * Process the result of asynchronous calls that returns a stat object. + * @param returnCode The return code of the call. + * @param key the key that passed to asynchronous calls. + * @param context context object that passed to asynchronous calls. + * @param stat the stats of the entry of the given key, returned from the async call. + */ void processResult(int returnCode, String key, Object context, MetaClientInterface.Stat stat); } //This callback is used when data is returned from the operation. interface DataCallback extends AsyncCallback { + /** + * Process the result of asynchronous calls that returns entry data. + * @param returnCode The return code of the call. + * @param key The key that passed to asynchronous calls. + * @param context context object that passed to asynchronous calls. + * @param data returned entry data from the call. + * @param stat the stats of the entry of the given key. + */ void processResult(int returnCode, String key, Object context, byte[] data, MetaClientInterface.Stat stat); } //This callback is used when nothing is returned from the operation. interface VoidCallback extends AsyncCallback { + /** + * Process the result of asynchronous calls that has no return value. + * @param returnCode The return code of the call. + * @param key he key that passed to asynchronous calls. + * @param context context object that passed to asynchronous calls. + */ void processResult(int returnCode, String key, Object context); } //This callback is used to process the list if OpResults from a single transactional call. interface TransactionCallback extends AsyncCallback { - void processResult(int returnCode, String key, Object context, List<OpResult> opResults); + /** + * Process the result of asynchronous transactional calls. + * @param returnCode The return code of the transaction call. + * @param keys List of keys passed to the async transactional call. + * @param context context object that passed to asynchronous calls. + * @param opResults The list of transactional results. + */ + void processResult(int returnCode, List<String> keys, Object context, List<OpResult> opResults); } } \ No newline at end of file diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/ChildChangeListener.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/ChildChangeListener.java new file mode 100644 index 000000000..4d09450da --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/ChildChangeListener.java @@ -0,0 +1,39 @@ +package org.apache.helix.metaclient.api; + +/* + * 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. + */ + +/** + * Listener interface for children change events on a particular key. It includes new child + * creation, child deletion, child data change. + * TODO: add type for persist listener is removed + * For hierarchy key spaces like zookeeper, it refers to an entry's entire subtree. + * For flat key spaces, it refers to keys that matches `prefix*`. + */ +public interface ChildChangeListener { + enum ChangeType { + ENTRY_CREATED, // Any child entry created + ENTRY_DELETED, // Any child entry deleted + ENTRY_DATA_CHANGE // Any child entry has value change + } + /** + * Called when any child of the current key has changed. + */ + void handleChildChange(String changedPath, ChangeType changeType) throws Exception; +} \ No newline at end of file diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/ConnectStateChangeListener.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/ConnectStateChangeListener.java new file mode 100644 index 000000000..63e7ae4e8 --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/ConnectStateChangeListener.java @@ -0,0 +1,39 @@ +package org.apache.helix.metaclient.api; + +/* + * 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. + */ + +public interface ConnectStateChangeListener { + /** + * Called when the connection state has changed. I + * @param prevState previous state before state change event. + * @param currentState client state after state change event. If it is a one time listsner, it is + * possible that the metaclient state changes again + */ + void handleConnectStateChanged(MetaClientInterface.ConnectState prevState, MetaClientInterface.ConnectState currentState) throws Exception; + + /** + * Called when new connection failed to established. + * @param error error returned from metaclient or metadata service. + */ + void handleConnectionEstablishmentError(final Throwable error) throws Exception; + + // TODO: Consider add a callback for new connection when we add support for session ID. + +} \ No newline at end of file diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/DataChangeListener.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/DataChangeListener.java new file mode 100644 index 000000000..84d11b34f --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/DataChangeListener.java @@ -0,0 +1,33 @@ +package org.apache.helix.metaclient.api; + +/* + * 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. + */ + +/** + * Listener interface for events on a particular key, including entry creating, deleting and value change. + */ +public interface DataChangeListener { + enum ChangeType { + ENTRY_CREATED, // Entry created of the specific path that the listener register to + ENTRY_DELETED, // Entry deleted of the specific path that the listener register to + ENTRY_UPDATE // Entry value updated + } + + void handleDataChange(String key, Object data, ChangeType changeType) throws Exception; +} diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/DirectChildChangeListener.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/DirectChildChangeListener.java new file mode 100644 index 000000000..83e67b8e6 --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/DirectChildChangeListener.java @@ -0,0 +1,37 @@ +package org.apache.helix.metaclient.api; + +/* + * 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. + */ + +/** + * Listener interface for direct child change event on a particular key. It includes new + * child creation or child deletion. The callback won't differentiate these types. + * For hierarchy key spaces like zookeeper, it refers to an entry's direct child nodes. + * For flat key spaces, it refers to keys that matches `prefix*separator`. + */ +public interface DirectChildChangeListener { + /** + * Called when there is a direct child entry creation or deleted. + * @param key The parent key where child change listener is subscribed. It would be the key + * passed to subscribeDirectChildChange. + * @throws Exception + */ + void handleDirectChildChange(String key) throws Exception; + +} diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/DirectChildSubscribeResult.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/DirectChildSubscribeResult.java new file mode 100644 index 000000000..6d45954b5 --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/DirectChildSubscribeResult.java @@ -0,0 +1,45 @@ +package org.apache.helix.metaclient.api; + +/* + * 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.List; + + +public class DirectChildSubscribeResult { + // A list of direct children names at the time when change is subscribed. + // It includes only one level child name, does not include further sub children names. + private final List<String> _children; + + // true means the listener is registered successfully. + private final boolean _isRegistered; + + public DirectChildSubscribeResult(List<String> children, boolean isRegistered) { + _children = children; + _isRegistered = isRegistered; + } + + public List<String> getDirectChildren() { + return _children; + } + + public boolean isRegistered() { + return _isRegistered; + } +} diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java b/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java index 4ad649c26..5118f6359 100644 --- a/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java +++ b/meta-client/src/main/java/org/apache/helix/metaclient/api/MetaClientInterface.java @@ -20,51 +20,101 @@ package org.apache.helix.metaclient.api; */ import java.util.List; +import java.util.concurrent.TimeUnit; public interface MetaClientInterface<T> { enum EntryMode { - //The node will be removed automatically when the session associated with the creation + // The node will be removed automatically when the session associated with the creation // of the node expires. EPHEMERAL, - //The node will not be automatically deleted upon client's disconnect. - PERSISTENT + + // The node will not be automatically deleted upon client's disconnect. + // An ephemeral node cannot have sub entry. + PERSISTENT, + + // The node will not be automatically deleted when the last sub-entry of the node is deleted. + // The node is an ephemeral node. + CONTAINER + } + + enum ConnectState { + // Client is connected to server + CONNECTED, + + // Authentication failed. + AUTH_FAILED, + + // Server has expired this connection. + EXPIRED, + + // When client failed to connect server. + INIT_FAILED, + + // When client explicitly call disconnect. + CLOSED_BY_CLIENT } /** * Interface representing the metadata of an entry. It contains entry type and version number. + * TODO: we will add session ID to entry stats in the future */ class Stat { private int _version; private EntryMode _entryMode; - public EntryMode getEntryType() {return _entryMode;} - public int getVersion() {return _version;} + public EntryMode getEntryType() { + return _entryMode; + } + + public int getVersion() { + return _version; + } } //synced CRUD API - void create(final String key, T data, final EntryMode mode); - void create(final String key, T data, final EntryMode mode, long ttl); + /** + * Create an persistent entry with given key and data. The entry will not be created if there is + * an existing entry with the same key. + * @param key key to identify the entry + * @param data value of the entry + */ + void create(final String key, T data); + + /** + * Create an entry of given EntryMode with given key and data. The entry will not be created if + * there is an existing entry with ethe same key. + * @param key key to identify the entry + * @param data value of the entry + * @param mode EntryMode identifying if the entry will be deleted upon client disconnect + */ + void create(final String key, final T data, final EntryMode mode); + + // TODO: add TTL create and renew API /** * Set the data for the entry of the given key if it exists and the given version matches the * version of the node (if the given version is -1, it matches any node's versions). + * @param key key to identify the entry + * @param data new data of the entry + * @param version expected version of the entry. -1 matched any version. */ - void set(final String key, T data, int version); + void set(final String key, final T data, int version); /** * Update existing data of a given key using an updater. This method will issue a read to get * current data and apply updater upon the current data. - * @param updater : An updater that modifies the entry value. + * @param key key to identify the entry + * @param updater An updater that modifies the entry value. * @return: the updated value. */ - T update(String key, DataUpdater<T> updater); + T update(final String key, DataUpdater<T> updater); /** * Check if there is an entry for the given key. - * @param key + * @param key key to identify the entry * @return return a Stat object if the entry exists. Return null otherwise. */ Stat exists(final String key); @@ -72,87 +122,328 @@ public interface MetaClientInterface<T> { /** * Fetch the data for a given key. * TODO: define exception type when key does not exist + * @param key key to identify the entry + * @return Return data of the entry */ - T get(String key); + T get(final String key); /** * API for transaction. The list of operation will be executed as an atomic operation. * @param ops a list of operations. These operations will all be executed or non of them. - * @return + * @return Return a list of OpResult. */ List<OpResult> transactionOP(final Iterable<Op> ops); /** - * Return a list of sub entries for the given keys - * @param path: For metadata storage that has hierarchical key space (e.g. ZK), the path would be - * a parent path, - * For metadata storage that has non-hierarchical key space (e.g. etcd), the path would - * be a prefix path. + * Return a list of children for the given keys. + * @param key For metadata storage that has hierarchical key space (e.g. ZK), the key would be + * a parent key, + * For metadata storage that has non-hierarchical key space (e.g. etcd), the key would + * be a prefix key. + * @eturn Return a list of children keys. Return direct child name only for hierarchical key + * space, return the whole sub key for non-hierarchical key space. */ - List<String> getSubEntryKeys(final String path); + List<String> getDirestChildrenKeys(final String key); /** - * Return the number of sub entries for the given keys - * @param path: For metadata storage that has hierarchical key space (e.g. ZK), the path would be - * a parent path, - * For metadata storage that has non-hierarchical key space (e.g. etcd), the path would - * be a prefix path. + * Return the number of children for the given keys. + * @param key For metadata storage that has hierarchical key space (e.g. ZK), the key would be + * a parent key, + * For metadata storage that has non-hierarchical key space (e.g. etcd), the key would + * be a prefix key. */ - int countSubEntries(final String path); + int countDirestChildren(final String key); /** * Remove the entry associated with the given key. * For metadata storage that has hierarchical key space, the entry can only be deleted if the key * has no child entry. - * TODO: throws - * @param path - * @return + * TODO: define exception to throw + * @param key key to identify the entry to delete + * @return Return true if the deletion is completed */ - boolean delete(String path); + boolean delete(final String key); /** * Remove the entry associated with the given key. * For metadata storage that has hierarchical key space, remove all its child entries as well * For metadata storage that has non-hierarchical key space, this API is the same as delete() - * @param path - * @return + * @param key key to identify the entry to delete + * @return Return true if the deletion is completed */ - boolean recursiveDelete(String path); + boolean recursiveDelete(final String key); /* Asynchronous methods return immediately. * They take a callback object that will be executed either on successful execution of the request * or on error with an appropriate return code indicating the error. */ - void asyncCreate(final String key, T data, int version, long ttl, + + /** + * User may register callbacks for async CRUD calls. These callbacks will be executed in a async + * thread pool. User could define the thread pool size. Default value is 10. + * TODO: add const default value in a separate file + * @param poolSize pool size for executing user resisted async callbacks + */ + void setAsyncExecPoolSize(int poolSize); + + /** + * The asynchronous version of create. + * @param key key to identify the entry + * @param data value of the entry + * @param mode EntryMode identifying if the entry will be deleted upon client disconnect + * @param cb An user defined VoidCallback implementation that will be invoked when async create return. + * @see org.apache.helix.metaclient.api.AsyncCallback.VoidCallback + */ + void asyncCreate(final String key, final T data, final EntryMode mode, AsyncCallback.VoidCallback cb); - void asyncSet(final String key, T data, int version, AsyncCallback.VoidCallback cb); + /** + * The asynchronous version of set. + * @param key key to identify the entry + * @param data new data of the entry + * @param version expected version if the entry. -1 matched any version + * @param cb An user defined VoidCallback implementation that will be invoked when async create return. + * @see org.apache.helix.metaclient.api.AsyncCallback.VoidCallback + */ + void asyncSet(final String key, final T data, final int version, AsyncCallback.VoidCallback cb); - void asyncUpdate(final String key, DataUpdater<T> updater, AsyncCallback.VoidCallback cb); + /** + * The asynchronous version of update. + * @param key key to identify the entry + * @param updater An updater that modifies the entry value. + * @param cb An user defined VoidCallback implementation that will be invoked when async create return. + * It will contain the newly updated data if update succeeded. + * @see org.apache.helix.metaclient.api.AsyncCallback.DataCallback + */ + void asyncUpdate(final String key, DataUpdater<T> updater, AsyncCallback.DataCallback cb); + /** + * The asynchronous version of get. + * @param key key to identify the entry + * @param cb An user defined VoidCallback implementation that will be invoked when async get return. + * It will contain the entry data if get succeeded. + * @see org.apache.helix.metaclient.api.AsyncCallback.DataCallback + */ void asyncGet(final String key, AsyncCallback.DataCallback cb); - void asyncCountSubEntries(final String path, AsyncCallback.DataCallback cb); + /** + * The asynchronous version of get sub entries. + * @param key key to identify the entry + * @param cb An user defined VoidCallback implementation that will be invoked when async count child return. + * It will contain the list of child keys if succeeded. + * @see org.apache.helix.metaclient.api.AsyncCallback.DataCallback + */ + void asyncCountChildren(final String key, AsyncCallback.DataCallback cb); + /** + * The asynchronous version of get sub entries. + * @param key key to identify the entry + * @param cb An user defined VoidCallback implementation that will be invoked when async exist return. + * It will contain the stats of the entry if succeeded. + * @see org.apache.helix.metaclient.api.AsyncCallback.StatCallback + */ void asyncExist(final String key, AsyncCallback.StatCallback cb); - void asyncDelete(final String keys, AsyncCallback.VoidCallback cb); + /** + * The asynchronous version of delete. + * @param key key to identify the entry + * @param cb An user defined VoidCallback implementation that will be invoked when async delete + * finish and return. @see org.apache.helix.metaclient.api.AsyncCallback.DataCallback + */ + void asyncDelete(final String key, AsyncCallback.VoidCallback cb); - void asyncTransaction(final String keys, AsyncCallback.TransactionCallback cb); + /** + * The asynchronous version of transaction operations. + * @param ops A list of operations + * @param cb An user defined TransactionCallback implementation that will be invoked when + * transaction operations finish and return. The TransactionCallback will contain + * either a list of OpResult if transaction finish successfully, or a return code + * indicating failure reason. @see org.apache.helix.metaclient.api.AsyncCallback.TransactionCallback + */ + void asyncTransaction(final Iterable<Op> ops, AsyncCallback.TransactionCallback cb); /* Batched APIs return result to user when all request finishes. * These calls are not executed as a transaction. */ - boolean[] create(List<String> key, List<T> data, List<EntryMode> mode, List<Long> ttl); - boolean[] set(List<String> keys, List<T> values, List<Integer> version); + /** + * Batch version of create. All entries will be created in persist mode. Returns when all request + * finishes. These calls are not executed as a transaction. + * @param key A list of key for create operations. + * @param data A list of data. Need to be in the same length of list of key. + * @return A list of boolean indicating create result of each operation. + */ + boolean[] create(List<String> key, List<T> data); + + /** + * Batch version of create. Returns when all request finishes. These calls are not executed as a + * transaction. + * @param key A list of key for create operations. + * @param data A list of data. Need to be in the same length of list of key. + * @param mode A list of EntryMode. Need to be in the same length of list of key. + * @return A list of boolean indicating create result of each operation. + */ + boolean[] create(List<String> key, List<T> data, List<EntryMode> mode); + + /** + * Batch version of set. Returns when all request finishes. These calls are not executed as a + * transaction. + * @param keys A list of key for set operations. + * @param datas A list of data. Need to be in the same length of list of key. + * @param version A list of expected version of the entry. -1 matched any version. + * Need to be in the same length of list of key. + * @return A list of boolean indicating set result of each operation. + */ + boolean[] set(List<String> keys, List<T> datas, List<Integer> version); + /** + * Batch version of update. Returns when all request finishes. These calls are not executed as a + * transaction. + * @param keys A list of key for update operations. + * @param updater A list of updater. Need to be in the same length of list of key. + * @return A list of updated entry values. + */ List<T> update(List<String> keys, List<DataUpdater<T>> updater); + /** + * Batch version of get. Returns when all request finishes. These calls are not executed as a + * transaction. + * @param keys A list of key for get operations. + * @return A list of entry values. + */ List<T> get(List<String> keys); + /** + * Batch version of exists. Returns when all request finishes. These calls are not executed as a + * transaction. + * @param keys A list of key for exists operations. + * @return A list of stats for the given entries. + */ List<Stat> exists(List<String> keys); + /** + * Batch version of delete. Returns when all request finishes. These calls are not executed as a + * transaction. + * @param keys A list of key for delete operations. + * @return A list of boolean indicating delete result of each operation. + */ boolean[] delete(List<String> keys); + /** + * Maintains a connection with underlying metadata service based on config params. Connection + * created by this method will be used to perform CRUD operations on metadata service. + * @return True if connection is successfully established. + */ + boolean connect(); + + /** + * Disconnect from server explicitly. + */ + void disconnect(); + + /** + * @return client current connection state with metadata service. + */ + ConnectState getClientConnectionState(); + + // Event notification APIs, user can register multiple listeners on the same key/connection state. + // All listeners will be automatically removed when client is disconnected. + // TODO: add auto re-register listener option + + /** + * Subscribe change of a particular entry. Including entry data change, entry deletion and creation + * of the given key. + * @param key Key to identify the entry + * @param listener An implementation of DataChangeListener + * @see org.apache.helix.metaclient.api.DataChangeListener + * @param skipWatchingNonExistNode Will not register lister to an non-exist key if set to true. + * Please set to false if you are expecting ENTRY_CREATED type. + * @param persistListener The listener will persist when set to true. Otherwise it will be a one + * time triggered listener. + * @return Return an boolean indication if subscribe succeeded. + */ + boolean subscribeDataChange(String key, DataChangeListener listener, + boolean skipWatchingNonExistNode, boolean persistListener); + + /** + * Subscribe for direct child change event on a particular key. It includes new child + * creation or deletion. It does not include existing child data change. + * For hierarchy key spaces like zookeeper, it refers to an entry's direct children nodes. + * For flat key spaces, it refers to keys that matches `prefix*separator`. + * @param key key to identify the entry. + * @param listener An implementation of DirectSubEntryChangeListener. + * @see org.apache.helix.metaclient.api.DirectChildChangeListener + * @param skipWatchingNonExistNode If the passed in key does not exist, no listener wil be registered. + * @param persistListener The listener will persist when set to true. Otherwise it will be a one + * time triggered listener. + * + * @return Return an DirectSubEntrySubscribeResult. It will contain a list of direct sub children if + * subscribe succeeded. + */ + DirectChildSubscribeResult subscribeDirectChildChange(String key, + DirectChildChangeListener listener, boolean skipWatchingNonExistNode, + boolean persistListener); + + /** + * Subscribe for connection state change. + * @param listener An implementation of ConnectStateChangeListener. + * @see org.apache.helix.metaclient.api.ConnectStateChangeListener + * @param persistListener The listener will persist when set to true. Otherwise it will be a one + * time triggered listener. + * + * @return Return an boolean indication if subscribe succeeded. + */ + boolean subscribeStateChanges(ConnectStateChangeListener listener, boolean persistListener); + + /** + * Subscribe change for all children including entry change and data change. + * For hierarchy key spaces like zookeeper, it would watch the whole tree structure. + * For flat key spaces, it would watch for keys with certain prefix. + * @param key key to identify the entry. + * @param listener An implementation of ChildChangeListener. + * @see org.apache.helix.metaclient.api.ChildChangeListener + * @param skipWatchingNonExistNode If the passed in key does not exist, no listener wil be registered. + * @param persistListener The listener will persist when set to true. Otherwise it will be a one + * time triggered listener. + */ + boolean subscribeChildChanges(String key, ChildChangeListener listener, + boolean skipWatchingNonExistNode, boolean persistListener); + + /** + * Unsubscribe the listener to further changes. No-op if the listener is not subscribed to the key. + * @param key Key to identify the entry. + * @param listener The listener to unsubscribe. + */ + void unsubscribeDataChange(String key, DataChangeListener listener); + + /** + * Unsubscribe the listener to further changes. No-op if the listener is not subscribed to the key. + * @param key Key to identify the entry. + * @param listener The listener to unsubscribe. + */ + void unsubscribeDirectChildChange(String key, DirectChildChangeListener listener); + + /** + * Unsubscribe the listener to further changes. No-op if the listener is not subscribed to the key. + * @param key Key to identify the entry. + * @param listener The listener to unsubscribe. + */ + void unsubscribeChildChanges(String key, ChildChangeListener listener); + + /** + * Unsubscribe the listener to further changes. No-op if the listener is not subscribed to the key. + * @param listener The listener to unsubscribe. + */ + void unsubscribeConnectStateChanges(ConnectStateChangeListener listener); + + /** + * Block the call until the given key exists or timeout. + * @param key Key to monitor. + * @param timeUnit timeout unit + * @param timeOut timeout value + * @return + */ + boolean waitUntilExists(String key, TimeUnit timeUnit, long timeOut); + + // TODO: Secure CRUD APIs } \ No newline at end of file diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientConfig.java b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientConfig.java new file mode 100644 index 000000000..f317fd923 --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientConfig.java @@ -0,0 +1,115 @@ +package org.apache.helix.metaclient.factories; + +/* + * 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. + */ + +class MetaClientConfig { + + public enum StoreType { + ZOOKEEPER, ETCD, CUSTOMIZED + } + + private final String _connectionAddress; + private final long _connectionTimeout; + private final boolean _enableAuth; + private final StoreType _storeType; + + public String getConnectionAddress() { + return _connectionAddress; + } + + public long getConnectionTimeout() { + return _connectionTimeout; + } + + public boolean isAuthEnabled() { + return _enableAuth; + } + + public StoreType getStoreType() { + return _storeType; + } + + // TODO: More options to add later + // private boolean _autoReRegistWatcher; // re-register one time watcher when set to true + // private boolean _resetWatchWhenReConnect; // re-register previous existing watcher when reconnect + // + // public enum RetryProtocol { + // NO_RETRY, EXP_BACK_OFF, CONST_RETRY_INTERVAL + // } + // private RetryProtocol _retryProtocol; + + + private MetaClientConfig(String connectionAddress, long connectionTimeout, boolean enableAuth, + StoreType storeType) { + _connectionAddress = connectionAddress; + _connectionTimeout = connectionTimeout; + _enableAuth = enableAuth; + _storeType = storeType; + } + + public static class Builder { + private String _connectionAddress; + + private long _connectionTimeout; + private boolean _enableAuth; + //private RetryProtocol _retryProtocol; + private StoreType _storeType; + + + + public MetaClientConfig build() { + validate(); + return new MetaClientConfig(_connectionAddress, _connectionTimeout, _enableAuth, _storeType); + } + + public Builder() { + // set default values + setAuthEnabled(false); + setConnectionTimeout(-1); + } + + public Builder setConnectionAddress(String connectionAddress) { + _connectionAddress = connectionAddress; + return this; + } + + public Builder setAuthEnabled(Boolean enableAuth) { + _enableAuth = enableAuth; + return this; + } + + public Builder setConnectionTimeout(long timeout) { + _connectionTimeout = timeout; + return this; + } + + public Builder setStoreType(StoreType storeType) { + _storeType = storeType; + return this; + } + + private void validate() { + if (_storeType == null || _connectionAddress == null) { + throw new IllegalArgumentException( + "MetaClientConfig.Builder: store type or connection string is null"); + } + } + } +} \ No newline at end of file diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java new file mode 100644 index 000000000..cf3feb0ef --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/factories/MetaClientFactory.java @@ -0,0 +1,37 @@ +package org.apache.helix.metaclient.factories; + +/* + * 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 org.apache.helix.metaclient.api.MetaClientInterface; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * A factory class for MetaClient. It returns MetaClient entity based on config. + */ +public class MetaClientFactory { + private static final Logger LOG = LoggerFactory.getLogger(MetaClientFactory.class); + + public MetaClientInterface getMetaClient(MetaClientConfig config) { + return null; + } +} diff --git a/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java new file mode 100644 index 000000000..8437e387f --- /dev/null +++ b/meta-client/src/main/java/org/apache/helix/metaclient/impl/zk/ZkMetaClient.java @@ -0,0 +1,245 @@ +package org.apache.helix.metaclient.impl.zk; + +/* + * 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.List; +import java.util.concurrent.TimeUnit; + +import org.apache.helix.metaclient.api.AsyncCallback; +import org.apache.helix.metaclient.api.ChildChangeListener; +import org.apache.helix.metaclient.api.ConnectStateChangeListener; +import org.apache.helix.metaclient.api.DataChangeListener; +import org.apache.helix.metaclient.api.DataUpdater; +import org.apache.helix.metaclient.api.DirectChildChangeListener; +import org.apache.helix.metaclient.api.DirectChildSubscribeResult; +import org.apache.helix.metaclient.api.MetaClientInterface; +import org.apache.helix.metaclient.api.OpResult; +import org.apache.helix.zookeeper.api.client.RealmAwareZkClient; + + +public class ZkMetaClient implements MetaClientInterface { + + private RealmAwareZkClient _zkClient; + + public ZkMetaClient() { + + } + + @Override + public void create(String key, Object data) { + + } + + @Override + public void create(String key, Object data, EntryMode mode) { + + } + + @Override + public void set(String key, Object data, int version) { + + } + + @Override + public Object update(String key, DataUpdater updater) { + return null; + } + + @Override + public Stat exists(String key) { + return null; + } + + @Override + public Object get(String key) { + return null; + } + + @Override + public List<String> getDirestChildrenKeys(String key) { + return null; + } + + @Override + public int countDirestChildren(String key) { + return 0; + } + + @Override + public boolean delete(String key) { + return false; + } + + @Override + public boolean recursiveDelete(String key) { + return false; + } + + @Override + public void setAsyncExecPoolSize(int poolSize) { + + } + + @Override + public void asyncCreate(String key, Object data, EntryMode mode, AsyncCallback.VoidCallback cb) { + + } + + @Override + public void asyncSet(String key, Object data, int version, AsyncCallback.VoidCallback cb) { + + } + + @Override + public void asyncUpdate(String key, DataUpdater updater, AsyncCallback.DataCallback cb) { + + } + + @Override + public void asyncGet(String key, AsyncCallback.DataCallback cb) { + + } + + @Override + public void asyncCountChildren(String key, AsyncCallback.DataCallback cb) { + + } + + @Override + public void asyncExist(String key, AsyncCallback.StatCallback cb) { + + } + + @Override + public void asyncDelete(String keys, AsyncCallback.VoidCallback cb) { + + } + + @Override + public boolean[] create(List key, List data, List mode) { + return new boolean[0]; + } + + @Override + public boolean[] create(List key, List data) { + return new boolean[0]; + } + + @Override + public void asyncTransaction(Iterable iterable, AsyncCallback.TransactionCallback cb) { + + } + + + @Override + public boolean connect() { + return false; + } + + @Override + public void disconnect() { + + } + + @Override + public ConnectState getClientConnectionState() { + return null; + } + + @Override + public boolean subscribeDataChange(String key, DataChangeListener listener, + boolean skipWatchingNonExistNode, boolean persistListener) { + return false; + } + + @Override + public DirectChildSubscribeResult subscribeDirectChildChange(String key, + DirectChildChangeListener listener, boolean skipWatchingNonExistNode, + boolean persistListener) { + return null; + } + + @Override + public boolean subscribeStateChanges(ConnectStateChangeListener listener, + boolean persistListener) { + return false; + } + + @Override + public boolean subscribeChildChanges(String key, ChildChangeListener listener, + boolean skipWatchingNonExistNode, boolean persistListener) { + return false; + } + + @Override + public void unsubscribeDataChange(String key, DataChangeListener listener) { + + } + + @Override + public void unsubscribeDirectChildChange(String key, DirectChildChangeListener listener) { + + } + + @Override + public void unsubscribeChildChanges(String key, ChildChangeListener listener) { + + } + + @Override + public void unsubscribeConnectStateChanges(ConnectStateChangeListener listener) { + + } + + @Override + public boolean waitUntilExists(String key, TimeUnit timeUnit, long time) { + return false; + } + + @Override + public boolean[] delete(List keys) { + return new boolean[0]; + } + + @Override + public List<Stat> exists(List keys) { + return null; + } + + @Override + public List get(List keys) { + return null; + } + + @Override + public List update(List keys, List updater) { + return null; + } + + @Override + public boolean[] set(List keys, List values, List version) { + return new boolean[0]; + } + + @Override + public List<OpResult> transactionOP(Iterable iterable) { + return null; + } +}
