[CURATOR-160] Add builders and dsl for ZooKeeper's config and reconfig methods.
Project: http://git-wip-us.apache.org/repos/asf/curator/repo Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/f37580ec Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/f37580ec Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/f37580ec Branch: refs/heads/CURATOR-215 Commit: f37580ec562d8f9467ca037d7d1c740ffdfe40c9 Parents: d4883a8 Author: Ioannis Canellos <[email protected]> Authored: Thu Nov 6 17:34:47 2014 +0200 Committer: Ioannis Canellos <[email protected]> Committed: Mon Nov 10 13:41:19 2014 +0200 ---------------------------------------------------------------------- .../main/java/org/apache/curator/RetryLoop.java | 3 +- .../curator/framework/CuratorFramework.java | 12 + .../api/BackgroundStatConfigurable.java | 24 ++ .../framework/api/BackgroundStatable.java | 24 ++ .../curator/framework/api/Configurable.java | 29 ++ .../curator/framework/api/CuratorEventType.java | 10 + .../curator/framework/api/Ensembleable.java | 24 ++ .../curator/framework/api/GetConfigBuilder.java | 27 ++ .../api/JoinBackgroundStatConfigurable.java | 30 ++ .../apache/curator/framework/api/Joinable.java | 31 ++ .../api/LeaveBackgroundStatConfigurable.java | 30 ++ .../apache/curator/framework/api/Leaveable.java | 30 ++ .../curator/framework/api/Memberable.java | 31 ++ .../curator/framework/api/ReconfigBuilder.java | 26 ++ .../framework/imps/CuratorFrameworkImpl.java | 10 + .../imps/EnsembleServersAndConfig.java | 52 ++++ .../framework/imps/GetConfigBuilderImpl.java | 187 ++++++++++++ .../framework/imps/ReconfigBuilderImpl.java | 216 +++++++++++++ .../framework/imps/TestReconfiguration.java | 305 +++++++++++++++++++ .../org/apache/curator/test/InstanceSpec.java | 4 + .../org/apache/curator/test/TestingCluster.java | 1 + 21 files changed, 1105 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-client/src/main/java/org/apache/curator/RetryLoop.java ---------------------------------------------------------------------- diff --git a/curator-client/src/main/java/org/apache/curator/RetryLoop.java b/curator-client/src/main/java/org/apache/curator/RetryLoop.java index 6b66e82..065ebef 100644 --- a/curator-client/src/main/java/org/apache/curator/RetryLoop.java +++ b/curator-client/src/main/java/org/apache/curator/RetryLoop.java @@ -150,7 +150,8 @@ public class RetryLoop return (rc == KeeperException.Code.CONNECTIONLOSS.intValue()) || (rc == KeeperException.Code.OPERATIONTIMEOUT.intValue()) || (rc == KeeperException.Code.SESSIONMOVED.intValue()) || - (rc == KeeperException.Code.SESSIONEXPIRED.intValue()); + (rc == KeeperException.Code.SESSIONEXPIRED.intValue()) || + (rc == KeeperException.Code.NEWCONFIGNOQUORUM.intValue()); } /** http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java index 9c23ddb..181e4e8 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFramework.java @@ -122,6 +122,18 @@ public interface CuratorFramework extends Closeable public SetACLBuilder setACL(); /** + * Start a reconfig builder + * @return builder object + */ + public ReconfigBuilder reconfig(); + + /** + * Start a getConfig builder + * @return + */ + public GetConfigBuilder getConfig(); + + /** * Start a transaction builder * * @return builder object http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatConfigurable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatConfigurable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatConfigurable.java new file mode 100644 index 0000000..e46ba89 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatConfigurable.java @@ -0,0 +1,24 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface BackgroundStatConfigurable<T> extends + BackgroundStatable<Configurable<T>>, + Configurable<T> { +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatable.java new file mode 100644 index 0000000..77c4e96 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/BackgroundStatable.java @@ -0,0 +1,24 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface BackgroundStatable<T> extends + Backgroundable<T>, + Statable<T> { +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/Configurable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/Configurable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/Configurable.java new file mode 100644 index 0000000..a47f9d0 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/Configurable.java @@ -0,0 +1,29 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface Configurable<T> { + + /** + * Sets the configuration version to use. + * @param config The version of the configuration. + * @throws Exception + */ + Ensembleable<T> fromConfig(long config) throws Exception; +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java b/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java index 684d11b..50e9195 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/CuratorEventType.java @@ -69,6 +69,16 @@ public enum CuratorEventType SET_ACL, /** + * Corresponds to {@link CuratorFramework#getConfig()} + */ + GET_CONFIG, + + /** + * Corresponds to {@link CuratorFramework#reconfig()} + */ + RECONFIG, + + /** * Corresponds to {@link Watchable#usingWatcher(Watcher)} or {@link Watchable#watched()} */ WATCHED, http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/Ensembleable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/Ensembleable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/Ensembleable.java new file mode 100644 index 0000000..c8a82fe --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/Ensembleable.java @@ -0,0 +1,24 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface Ensembleable<T> { + + T forEnsemble() throws Exception; +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java b/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java new file mode 100644 index 0000000..c2fdf6c --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/GetConfigBuilder.java @@ -0,0 +1,27 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface GetConfigBuilder extends + Watchable<BackgroundStatable<Ensembleable<byte[]>>>, + BackgroundStatable<Ensembleable<byte[]>>, + Ensembleable<byte[]> { +} + + http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/JoinBackgroundStatConfigurable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/JoinBackgroundStatConfigurable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/JoinBackgroundStatConfigurable.java new file mode 100644 index 0000000..fb18c0c --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/JoinBackgroundStatConfigurable.java @@ -0,0 +1,30 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +/** + * An incremental reconfiguration builder. + * This builder has access only to the incremental reconfiguration methods joining and leaving, so that we prevent + * mixing concepts that can't be used together. + */ +public interface JoinBackgroundStatConfigurable extends + Joinable<BackgroundStatConfigurable<byte[]>>, + BackgroundStatConfigurable<byte[]> { + +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/Joinable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/Joinable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/Joinable.java new file mode 100644 index 0000000..dde5b1c --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/Joinable.java @@ -0,0 +1,31 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface Joinable<T> { + + /** + * Adds one or more servers to joining the ensemble. + * The expected format is server.[id]=[hostname]:[peer port]:[election port]:[type];[client port] + * @param server The server to joining. + * @return this. + */ + T joining(String... server); + +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/LeaveBackgroundStatConfigurable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/LeaveBackgroundStatConfigurable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/LeaveBackgroundStatConfigurable.java new file mode 100644 index 0000000..196ffca --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/LeaveBackgroundStatConfigurable.java @@ -0,0 +1,30 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +/** + * An non-incremental reconfiguration builder. + * This builder has access only to the non-incremental reconfiguration methods withMembers, so that we prevent + * mixing concepts that can't be used together. + */ +public interface LeaveBackgroundStatConfigurable extends + Leaveable<BackgroundStatConfigurable<byte[]>>, + BackgroundStatConfigurable<byte[]> { + +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/Leaveable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/Leaveable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/Leaveable.java new file mode 100644 index 0000000..a3c3358 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/Leaveable.java @@ -0,0 +1,30 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface Leaveable<T> { + + /** + * Sets one or more servers to leaving the ensemble. + * @param server The server ids. + * @return this + */ + T leaving(String... server); + +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/Memberable.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/Memberable.java b/curator-framework/src/main/java/org/apache/curator/framework/api/Memberable.java new file mode 100644 index 0000000..6ef54c1 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/Memberable.java @@ -0,0 +1,31 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + + +public interface Memberable<T> { + + /** + * Sets one or more members that are meant to be part of the ensemble. + * The expected format is server.[id]=[hostname]:[peer port]:[election port]:[type];[client port] + * @param server The server to add as a member of the ensemble. + * @return this. + */ + T withMembers(String... server); +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java b/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java new file mode 100644 index 0000000..96ebdf7 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/api/ReconfigBuilder.java @@ -0,0 +1,26 @@ +/** + * 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. + */ +package org.apache.curator.framework.api; + +public interface ReconfigBuilder extends + Joinable<LeaveBackgroundStatConfigurable>, + Leaveable<JoinBackgroundStatConfigurable>, + Memberable<BackgroundStatConfigurable<byte[]>> { + +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java index cf38e21..53f0a61 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java @@ -413,6 +413,16 @@ public class CuratorFrameworkImpl implements CuratorFramework } @Override + public ReconfigBuilder reconfig() { + return new ReconfigBuilderImpl(this); + } + + @Override + public GetConfigBuilder getConfig() { + return new GetConfigBuilderImpl(this); + } + + @Override public CuratorTransaction inTransaction() { Preconditions.checkState(getState() == CuratorFrameworkState.STARTED, "instance must be started before calling this method"); http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/imps/EnsembleServersAndConfig.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/EnsembleServersAndConfig.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/EnsembleServersAndConfig.java new file mode 100644 index 0000000..df78aa7 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/EnsembleServersAndConfig.java @@ -0,0 +1,52 @@ +/** + * 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. + */ +package org.apache.curator.framework.imps; + +import java.util.Collections; +import java.util.List; + +class EnsembleServersAndConfig { + private final List<String> joiningServers; + private final List<String> leavingServers; + private final List<String> members; + private final long config; + + EnsembleServersAndConfig(List<String> joiningServers, List<String> leavingServers, List<String> members, long config) { + this.joiningServers = joiningServers.isEmpty() ? null : Collections.unmodifiableList(joiningServers); + this.leavingServers = leavingServers.isEmpty() ? null : Collections.unmodifiableList(leavingServers); + this.members = members.isEmpty() ? null : Collections.unmodifiableList(members); + this.config = config; + } + + public List<String> getJoiningServers() { + return joiningServers; + } + + public List<String> getLeavingServers() { + return leavingServers; + } + + public List<String> getMembers() { + return members; + } + + public long getConfig() { + return config; + } +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java new file mode 100644 index 0000000..54b1862 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetConfigBuilderImpl.java @@ -0,0 +1,187 @@ +/** + * 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. + */ +package org.apache.curator.framework.imps; + +import org.apache.curator.RetryLoop; +import org.apache.curator.TimeTrace; +import org.apache.curator.framework.api.BackgroundCallback; +import org.apache.curator.framework.api.BackgroundStatable; +import org.apache.curator.framework.api.CuratorEvent; +import org.apache.curator.framework.api.CuratorEventType; +import org.apache.curator.framework.api.CuratorWatcher; +import org.apache.curator.framework.api.Ensembleable; +import org.apache.curator.framework.api.GetConfigBuilder; +import org.apache.zookeeper.AsyncCallback; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.data.Stat; + +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; + +public class GetConfigBuilderImpl implements GetConfigBuilder, BackgroundOperation<Void> { + + private final CuratorFrameworkImpl client; + + private Backgrounding backgrounding; + private Watching watching; + private Stat stat; + + public GetConfigBuilderImpl(CuratorFrameworkImpl client) { + this.client = client; + backgrounding = new Backgrounding(); + watching = new Watching(); + } + + @Override + public Ensembleable<byte[]> storingStatIn(Stat stat) { + this.stat = new Stat(); + return this; + } + + @Override + public BackgroundStatable<Ensembleable<byte[]>> watched() { + watching = new Watching(true); + return this; + } + + @Override + public GetConfigBuilder usingWatcher(Watcher watcher) { + watching = new Watching(client, watcher); + return this; + } + + @Override + public GetConfigBuilder usingWatcher(final CuratorWatcher watcher) { + watching = new Watching(client, watcher); + return this; + } + + @Override + public Ensembleable<byte[]> inBackground() { + backgrounding = new Backgrounding(); + return this; + } + + @Override + public Ensembleable<byte[]> inBackground(Object context) { + backgrounding = new Backgrounding(context); + return this; + } + + @Override + public Ensembleable<byte[]> inBackground(BackgroundCallback callback) { + backgrounding = new Backgrounding(callback); + return this; + } + + @Override + public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context) { + backgrounding = new Backgrounding(callback, context); + return this; + } + + @Override + public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Executor executor) { + backgrounding = new Backgrounding(callback, executor); + return this; + } + + @Override + public Ensembleable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor) { + backgrounding = new Backgrounding(client, callback, context, executor); + return this; + } + + private void performBackgroundOperation() { + try { + client.getZooKeeper().getConfig(watching.getWatcher(), + new AsyncCallback.DataCallback() { + @Override + public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) { + try { + CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_CONFIG, + rc, path, null, ctx, stat, data, null, null, null); + backgrounding.getCallback().processResult(client, event); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }, backgrounding.getContext()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public byte[] forEnsemble() throws Exception { + byte[] responseData = null; + if ( backgrounding.inBackground() ) + { + client.processBackgroundOperation(new OperationAndData<Void>(this, null, backgrounding.getCallback(), null, backgrounding.getContext()), null); + } + else + { + responseData = configInForeground(); + } + return responseData; + } + + @Override + public void performBackgroundOperation(final OperationAndData<Void> operationAndData) throws Exception + { + final TimeTrace trace = client.getZookeeperClient().startTracer("GetDataBuilderImpl-Background"); + AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback() + { + @Override + public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) + { + trace.commit(); + CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.GET_CONFIG, rc, path, null, ctx, stat, data, null, null, null); + client.processBackgroundOperation(operationAndData, event); + } + }; + if ( watching.isWatched() ) + { + client.getZooKeeper().getConfig(watching.getWatcher(), callback, backgrounding.getContext()); + } + else + { + client.getZooKeeper().getConfig(false, callback, backgrounding.getContext()); + } + } + + + private byte[] configInForeground() throws Exception { + TimeTrace trace = client.getZookeeperClient().startTracer("GetConfigBuilderImpl-Foreground"); + try { + return RetryLoop.callWithRetry + ( + client.getZookeeperClient(), + new Callable<byte[]>() { + @Override + public byte[] call() throws Exception { + return client.getZooKeeper().getConfig(watching.getWatcher(), stat); + } + } + ); + } finally { + trace.commit(); + } + } +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java new file mode 100644 index 0000000..7a33297 --- /dev/null +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/ReconfigBuilderImpl.java @@ -0,0 +1,216 @@ +/** + * 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. + */ +package org.apache.curator.framework.imps; + +import org.apache.curator.RetryLoop; +import org.apache.curator.TimeTrace; +import org.apache.curator.framework.api.BackgroundCallback; +import org.apache.curator.framework.api.BackgroundStatConfigurable; +import org.apache.curator.framework.api.Configurable; +import org.apache.curator.framework.api.CuratorEvent; +import org.apache.curator.framework.api.CuratorEventType; +import org.apache.curator.framework.api.Ensembleable; +import org.apache.curator.framework.api.JoinBackgroundStatConfigurable; +import org.apache.curator.framework.api.LeaveBackgroundStatConfigurable; +import org.apache.curator.framework.api.ReconfigBuilder; +import org.apache.zookeeper.AsyncCallback; +import org.apache.zookeeper.data.Stat; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; + +public class ReconfigBuilderImpl implements ReconfigBuilder { + + private final CuratorFrameworkImpl client; + + public ReconfigBuilderImpl(CuratorFrameworkImpl client) { + this.client = client; + } + + private static class ReconfigBuilderBase implements BackgroundStatConfigurable<byte[]>, Ensembleable<byte[]>, BackgroundOperation<EnsembleServersAndConfig> { + + final CuratorFrameworkImpl client; + final List<String> joiningServers = new LinkedList<String>(); + final List<String> leavingServers = new LinkedList<String>(); + final List<String> members = new LinkedList<String>(); + Backgrounding backgrounding; + Stat stat; + long config; + + private ReconfigBuilderBase(CuratorFrameworkImpl client) { + this.client = client; + backgrounding = new Backgrounding(); + } + + @Override + public Configurable<byte[]> inBackground() { + backgrounding = new Backgrounding(); + return this; + } + + @Override + public Configurable<byte[]> inBackground(Object context) { + backgrounding = new Backgrounding(context); + return this; + } + + @Override + public Configurable<byte[]> inBackground(BackgroundCallback callback) { + backgrounding = new Backgrounding(callback); + return this; + } + + @Override + public Configurable<byte[]> inBackground(BackgroundCallback callback, Object context) { + backgrounding = new Backgrounding(callback, context); + return this; + } + + @Override + public Configurable<byte[]> inBackground(BackgroundCallback callback, Executor executor) { + backgrounding = new Backgrounding(callback, executor); + return this; + } + + @Override + public Configurable<byte[]> inBackground(BackgroundCallback callback, Object context, Executor executor) { + backgrounding = new Backgrounding(client, callback, context, executor); + return this; + } + + @Override + public Ensembleable<byte[]> fromConfig(long config) throws Exception { + this.config = config; + return this; + } + + @Override + public Configurable<byte[]> storingStatIn(Stat stat) { + this.stat = stat; + return this; + } + + @Override + public byte[] forEnsemble() throws Exception { + if (backgrounding.inBackground()) { + client.processBackgroundOperation(new OperationAndData<EnsembleServersAndConfig>(this, + new EnsembleServersAndConfig(joiningServers, leavingServers, members, config), + backgrounding.getCallback(), null, backgrounding.getContext()), null); + return new byte[0]; + } else { + return ensembleInForeground(); + } + } + + private byte[] ensembleInForeground() throws Exception { + TimeTrace trace = client.getZookeeperClient().startTracer("ReconfigBuilderImpl-Foreground"); + byte[] responseData = RetryLoop.callWithRetry + ( + client.getZookeeperClient(), + new Callable<byte[]>() { + @Override + public byte[] call() throws Exception { + return client.getZooKeeper().reconfig( + joiningServers.isEmpty() ? null : joiningServers, + leavingServers.isEmpty() ? null : leavingServers, + members.isEmpty() ? null : members, + config, + stat + ); + } + } + ); + trace.commit(); + return responseData; + } + + @Override + public void performBackgroundOperation(final OperationAndData<EnsembleServersAndConfig> operationAndData) throws Exception { + final TimeTrace trace = client.getZookeeperClient().startTracer("ReconfigBuilderImpl-Background"); + AsyncCallback.DataCallback callback = new AsyncCallback.DataCallback() { + @Override + public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) { + trace.commit(); + CuratorEvent event = new CuratorEventImpl(client, CuratorEventType.RECONFIG, rc, path, null, ctx, stat, data, null, null, null); + client.processBackgroundOperation(operationAndData, event); + } + }; + client.getZooKeeper().reconfig( + operationAndData.getData().getJoiningServers(), + operationAndData.getData().getLeavingServers(), + operationAndData.getData().getMembers(), + operationAndData.getData().getConfig(), + callback, + operationAndData.getContext() + ); + + } + } + + private static class JoinReconfigBuilder extends ReconfigBuilderBase implements JoinBackgroundStatConfigurable { + + private JoinReconfigBuilder(CuratorFrameworkImpl client) { + super(client); + } + + @Override + public BackgroundStatConfigurable<byte[]> joining(String... servers) { + joiningServers.addAll(Arrays.asList(servers)); + return this; + } + } + + private static class LeaveReconfigBuilder extends ReconfigBuilderBase implements LeaveBackgroundStatConfigurable { + + private LeaveReconfigBuilder(CuratorFrameworkImpl client) { + super(client); + } + + @Override + public BackgroundStatConfigurable<byte[]> leaving(String... servers) { + leavingServers.addAll(Arrays.asList(servers)); + return this; + } + } + + + @Override + public LeaveBackgroundStatConfigurable joining(String... servers) { + LeaveReconfigBuilder builder = new LeaveReconfigBuilder(client); + builder.joiningServers.addAll(Arrays.asList(servers)); + return builder; + } + + @Override + public JoinBackgroundStatConfigurable leaving(String... servers) { + JoinReconfigBuilder builder = new JoinReconfigBuilder(client); + builder.leavingServers.addAll(Arrays.asList(servers)); + return builder; + } + + @Override + public BackgroundStatConfigurable<byte[]> withMembers(String... servers) { + ReconfigBuilderBase builder = new ReconfigBuilderBase(client); + builder.members.addAll(Arrays.asList(servers)); + return builder; + } +} http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java new file mode 100644 index 0000000..e8896ae --- /dev/null +++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestReconfiguration.java @@ -0,0 +1,305 @@ +/** + * 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. + */ +package org.apache.curator.framework.imps; + +import org.apache.curator.framework.CuratorFramework; +import org.apache.curator.framework.CuratorFrameworkFactory; +import org.apache.curator.framework.api.BackgroundCallback; +import org.apache.curator.framework.api.CuratorEvent; +import org.apache.curator.retry.RetryOneTime; +import org.apache.curator.test.InstanceSpec; +import org.apache.curator.test.TestingCluster; +import org.apache.zookeeper.data.Stat; +import org.apache.zookeeper.server.quorum.flexible.QuorumMaj; +import org.apache.zookeeper.server.quorum.flexible.QuorumVerifier; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import java.io.IOException; +import java.io.StringReader; +import java.util.Properties; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; + +public class TestReconfiguration { + + TestingCluster cluster; + + @BeforeMethod + public void setup() throws Exception { + cluster = new TestingCluster(5); + cluster.start(); + } + + @AfterMethod + public void tearDown() throws IOException { + cluster.close(); + } + + @Test + public void testSyncIncremental() throws Exception { + CuratorFramework client = CuratorFrameworkFactory.newClient(cluster.getConnectString(), new RetryOneTime(1)); + client.start(); + client.blockUntilConnected(); + try { + Stat stat = new Stat(); + byte[] bytes = client.getConfig().storingStatIn(stat).forEnsemble(); + Assert.assertNotNull(bytes); + QuorumVerifier qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 5); + String server1 = getServerString(qv, cluster, 1L); + String server2 = getServerString(qv, cluster, 2L); + + //Remove Servers + bytes = client.reconfig().leaving("1").storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 4); + bytes = client.reconfig().leaving("2").storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 3); + + //Add Servers + bytes = client.reconfig().joining("server.1=" + server1).storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 4); + bytes = client.reconfig().joining("server.2=" + server2).storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 5); + } finally { + client.close(); + } + } + + @Test + public void testAsyncIncremental() throws Exception { + CuratorFramework client = CuratorFrameworkFactory.newClient(cluster.getConnectString(), new RetryOneTime(1)); + client.start(); + client.blockUntilConnected(); + try { + final AtomicReference<byte[]> bytes = new AtomicReference<byte[]>(); + final BackgroundCallback callback = new BackgroundCallback() { + @Override + public void processResult(CuratorFramework client, CuratorEvent event) throws Exception { + bytes.set(event.getData()); + ((CountDownLatch)event.getContext()).countDown(); + } + + }; + + CountDownLatch latch = new CountDownLatch(1); + client.getConfig().inBackground(callback, latch).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + Assert.assertNotNull(bytes.get()); + QuorumVerifier qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 5); + String server1 = getServerString(qv, cluster, 1L); + String server2 = getServerString(qv, cluster, 2L); + + + //Remove Servers + latch = new CountDownLatch(1); + client.reconfig().leaving("1").inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 4); + latch = new CountDownLatch(1); + client.reconfig().leaving("2").inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 3); + + //Add Servers + latch = new CountDownLatch(1); + client.reconfig().joining("server.1=" + server1).inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 4); + latch = new CountDownLatch(1); + client.reconfig().joining("server.2=" + server2).inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 5); + } finally { + client.close(); + } + } + + @Test + public void testSyncNonIncremental() throws Exception { + CuratorFramework client = CuratorFrameworkFactory.newClient(cluster.getConnectString(), new RetryOneTime(1)); + client.start(); + client.blockUntilConnected(); + try { + Stat stat = new Stat(); + byte[] bytes = client.getConfig().storingStatIn(stat).forEnsemble(); + Assert.assertNotNull(bytes); + QuorumVerifier qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 5); + String server1 = getServerString(qv, cluster, 1L); + String server2 = getServerString(qv, cluster, 2L); + String server3 = getServerString(qv, cluster, 3L); + String server4 = getServerString(qv, cluster, 4L); + String server5 = getServerString(qv, cluster, 5L); + + //Remove Servers + bytes = client.reconfig() + .withMembers("server.2=" + server2, + "server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 4); + bytes = client.reconfig() + .withMembers("server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 3); + + //Add Servers + bytes = client.reconfig() + .withMembers("server.1=" + server1, + "server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 4); + bytes = client.reconfig() + .withMembers("server.1=" + server1, + "server.2=" + server2, + "server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .storingStatIn(stat).fromConfig(qv.getVersion()).forEnsemble(); + qv = getQuorumVerifier(bytes); + Assert.assertEquals(qv.getAllMembers().size(), 5); + } finally { + client.close(); + } + } + + @Test + public void testAsyncNonIncremental() throws Exception { + CuratorFramework client = CuratorFrameworkFactory.newClient(cluster.getConnectString(), new RetryOneTime(1)); + client.start(); + client.blockUntilConnected(); + try { + final AtomicReference<byte[]> bytes = new AtomicReference<byte[]>(); + final BackgroundCallback callback = new BackgroundCallback() { + @Override + public void processResult(CuratorFramework client, CuratorEvent event) throws Exception { + bytes.set(event.getData()); + ((CountDownLatch)event.getContext()).countDown(); + } + + }; + + CountDownLatch latch = new CountDownLatch(1); + client.getConfig().inBackground(callback, latch).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + Assert.assertNotNull(bytes.get()); + QuorumVerifier qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 5); + String server1 = getServerString(qv, cluster, 1L); + String server2 = getServerString(qv, cluster, 2L); + String server3 = getServerString(qv, cluster, 3L); + String server4 = getServerString(qv, cluster, 4L); + String server5 = getServerString(qv, cluster, 5L); + + //Remove Servers + latch = new CountDownLatch(1); + client.reconfig() + .withMembers("server.2=" + server2, + "server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 4); + latch = new CountDownLatch(1); + client.reconfig() + .withMembers("server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 3); + + //Add Servers + latch = new CountDownLatch(1); + client.reconfig() + .withMembers("server.1=" + server1, + "server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 4); + latch = new CountDownLatch(1); + client.reconfig() + .withMembers("server.1=" + server1, + "server.2=" + server2, + "server.3=" + server3, + "server.4=" + server4, + "server.5=" + server5) + .inBackground(callback, latch).fromConfig(qv.getVersion()).forEnsemble(); + latch.await(5, TimeUnit.SECONDS); + qv = getQuorumVerifier(bytes.get()); + Assert.assertEquals(qv.getAllMembers().size(), 5); + } finally { + client.close(); + } + } + + + static QuorumVerifier getQuorumVerifier(byte[] bytes) throws Exception { + Properties properties = new Properties(); + properties.load(new StringReader(new String(bytes))); + return new QuorumMaj(properties); + } + + static InstanceSpec getInstance(TestingCluster cluster, int id) { + for (InstanceSpec spec : cluster.getInstances()) { + if (spec.getServerId() == id) { + return spec; + } + } + throw new IllegalStateException("InstanceSpec with id:" + id + " not found"); + } + + static String getServerString(QuorumVerifier qv, TestingCluster cluster, long id) throws Exception { + String str = qv.getAllMembers().get(id).toString(); + //check if connection string is already there. + if (str.contains(";")) { + return str; + } else { + return str + ";" + getInstance(cluster, (int) id).getConnectString(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-test/src/main/java/org/apache/curator/test/InstanceSpec.java ---------------------------------------------------------------------- diff --git a/curator-test/src/main/java/org/apache/curator/test/InstanceSpec.java b/curator-test/src/main/java/org/apache/curator/test/InstanceSpec.java index b39a949..6d495df 100644 --- a/curator-test/src/main/java/org/apache/curator/test/InstanceSpec.java +++ b/curator-test/src/main/java/org/apache/curator/test/InstanceSpec.java @@ -70,6 +70,10 @@ public class InstanceSpec private final int tickTime; private final int maxClientCnxns; + public static void reset() { + nextServerId.set(1); + } + public static InstanceSpec newInstanceSpec() { return new InstanceSpec(null, -1, -1, -1, true, -1, -1, -1); http://git-wip-us.apache.org/repos/asf/curator/blob/f37580ec/curator-test/src/main/java/org/apache/curator/test/TestingCluster.java ---------------------------------------------------------------------- diff --git a/curator-test/src/main/java/org/apache/curator/test/TestingCluster.java b/curator-test/src/main/java/org/apache/curator/test/TestingCluster.java index cd86b72..f6bdbd8 100644 --- a/curator-test/src/main/java/org/apache/curator/test/TestingCluster.java +++ b/curator-test/src/main/java/org/apache/curator/test/TestingCluster.java @@ -249,6 +249,7 @@ public class TestingCluster implements Closeable private static Map<InstanceSpec, Collection<InstanceSpec>> makeSpecs(int instanceQty) { + InstanceSpec.reset(); ImmutableList.Builder<InstanceSpec> builder = ImmutableList.builder(); for ( int i = 0; i < instanceQty; ++i ) {
