- standalone-server
leader-election
distributed-group
distributed-value
diff --git a/examples/standalone-server/src/main/java/io/atomix/examples/server/StandaloneServerExample.java b/examples/standalone-server/src/main/java/io/atomix/examples/server/StandaloneServerExample.java
deleted file mode 100644
index 6fe1ad703f..0000000000
--- a/examples/standalone-server/src/main/java/io/atomix/examples/server/StandaloneServerExample.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2015 the original author or authors.
- *
- * Licensed 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 io.atomix.examples.server;
-
-import io.atomix.Atomix;
-import io.atomix.AtomixReplica;
-import io.atomix.catalyst.transport.Address;
-import io.atomix.catalyst.transport.NettyTransport;
-import io.atomix.copycat.server.storage.Storage;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Server example.
- *
- * @author Jordan Halterman
- */
-public class StandaloneServerExample {
-
- /**
- * Starts the server.
- */
- public static void main(String[] args) throws Exception {
- if (args.length < 2)
- throw new IllegalArgumentException("must supply a path and set of host:port tuples");
-
- // Parse the address to which to bind the server.
- String[] mainParts = args[1].split(":");
- Address address = new Address(mainParts[0], Integer.valueOf(mainParts[1]));
-
- // Build a list of all member addresses to which to connect.
- List members = new ArrayList<>();
- for (int i = 1; i < args.length; i++) {
- String[] parts = args[i].split(":");
- members.add(new Address(parts[0], Integer.valueOf(parts[1])));
- }
-
- Atomix server = AtomixReplica.builder(address, members)
- .withTransport(new NettyTransport())
- .withStorage(new Storage(args[0]))
- .build();
-
- server.open().join();
-
- while (server.isOpen()) {
- Thread.sleep(1000);
- }
- }
-
-}
diff --git a/manager/pom.xml b/manager/pom.xml
index 1b01a0fecf..24049ac67f 100644
--- a/manager/pom.xml
+++ b/manager/pom.xml
@@ -16,5 +16,11 @@
atomix-resource
${project.version}
+
+ io.atomix.catalyst
+ catalyst-netty
+ ${catalyst.version}
+ test
+
diff --git a/manager/src/main/java/io/atomix/manager/ResourceClient.java b/manager/src/main/java/io/atomix/manager/ResourceClient.java
index 60dc476cc2..cef0e832ff 100644
--- a/manager/src/main/java/io/atomix/manager/ResourceClient.java
+++ b/manager/src/main/java/io/atomix/manager/ResourceClient.java
@@ -15,14 +15,30 @@
*/
package io.atomix.manager;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.transport.Address;
import io.atomix.catalyst.transport.Transport;
import io.atomix.catalyst.util.Assert;
import io.atomix.catalyst.util.ConfigurationException;
+import io.atomix.catalyst.util.PropertiesReader;
import io.atomix.catalyst.util.concurrent.Futures;
import io.atomix.catalyst.util.concurrent.ThreadContext;
-import io.atomix.copycat.client.*;
+import io.atomix.copycat.client.ConnectionStrategies;
+import io.atomix.copycat.client.CopycatClient;
+import io.atomix.copycat.client.RecoveryStrategies;
+import io.atomix.copycat.client.RetryStrategies;
+import io.atomix.copycat.client.ServerSelectionStrategies;
+import io.atomix.manager.options.ClientOptions;
import io.atomix.manager.state.GetResourceKeys;
import io.atomix.manager.state.ResourceExists;
import io.atomix.manager.state.ResourceManagerException;
@@ -33,11 +49,6 @@
import io.atomix.resource.util.ResourceInstance;
import io.atomix.resource.util.ResourceRegistry;
-import java.util.*;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
/**
* Provides an interface for creating and operating on {@link io.atomix.resource.Resource}s remotely.
*
@@ -87,6 +98,29 @@
*/
public class ResourceClient implements ResourceManager {
+ /**
+ * Returns a new ResourceClient builder from the given configuration file.
+ *
+ * @param properties The properties file from which to load the replica builder.
+ * @return The replica builder.
+ */
+ public static Builder builder(String properties) {
+ return builder(PropertiesReader.load(properties).properties());
+ }
+
+ /**
+ * Returns a new ResourceClient builder from the given properties.
+ *
+ * @param properties The properties from which to load the replica builder.
+ * @return The replica builder.
+ */
+ public static Builder builder(Properties properties) {
+ ClientOptions clientProperties = new ClientOptions(properties);
+ return builder(clientProperties.servers())
+ .withTransport(clientProperties.transport())
+ .withSerializer(clientProperties.serializer());
+ }
+
/**
* Returns a new Atomix client builder.
*
diff --git a/manager/src/main/java/io/atomix/manager/ResourceServer.java b/manager/src/main/java/io/atomix/manager/ResourceServer.java
index ded0388fa3..a869fd096a 100644
--- a/manager/src/main/java/io/atomix/manager/ResourceServer.java
+++ b/manager/src/main/java/io/atomix/manager/ResourceServer.java
@@ -15,14 +15,23 @@
*/
package io.atomix.manager;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Properties;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.transport.Address;
import io.atomix.catalyst.transport.Transport;
import io.atomix.catalyst.util.Assert;
import io.atomix.catalyst.util.ConfigurationException;
+import io.atomix.catalyst.util.PropertiesReader;
import io.atomix.catalyst.util.concurrent.ThreadContext;
import io.atomix.copycat.server.CopycatServer;
import io.atomix.copycat.server.storage.Storage;
+import io.atomix.manager.options.ServerOptions;
import io.atomix.manager.state.ResourceManagerException;
import io.atomix.manager.state.ResourceManagerState;
import io.atomix.manager.util.ResourceManagerTypeResolver;
@@ -30,12 +39,6 @@
import io.atomix.resource.ResourceType;
import io.atomix.resource.util.ResourceRegistry;
-import java.time.Duration;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.concurrent.CompletableFuture;
-import java.util.stream.Collectors;
-
/**
* Standalone Atomix server.
*
@@ -79,6 +82,45 @@
*/
public final class ResourceServer {
+ /**
+ * Returns a new ResourceServer builder from the given configuration file.
+ *
+ * @param properties The properties file from which to load the replica builder.
+ * @return The replica builder.
+ */
+ public static Builder builder(String properties) {
+ return builder(PropertiesReader.load(properties).properties());
+ }
+
+ /**
+ * Returns a new ResourceServer builder from the given properties.
+ *
+ * @param properties The properties from which to load the replica builder.
+ * @return The replica builder.
+ */
+ public static Builder builder(Properties properties) {
+ ServerOptions serverProperties = new ServerOptions(properties);
+ Collection
servers = serverProperties.servers();
+ return builder(serverProperties.clientAddress(), serverProperties.serverAddress(), servers)
+ .withTransport(serverProperties.transport())
+ .withStorage(Storage.builder()
+ .withStorageLevel(serverProperties.storageLevel())
+ .withDirectory(serverProperties.storageDirectory())
+ .withMaxSegmentSize(serverProperties.maxSegmentSize())
+ .withMaxEntriesPerSegment(serverProperties.maxEntriesPerSegment())
+ .withMaxSnapshotSize(serverProperties.maxSnapshotSize())
+ .withRetainStaleSnapshots(serverProperties.retainStaleSnapshots())
+ .withCompactionThreads(serverProperties.compactionThreads())
+ .withMinorCompactionInterval(serverProperties.minorCompactionInterval())
+ .withMajorCompactionInterval(serverProperties.majorCompactionInterval())
+ .withCompactionThreshold(serverProperties.compactionThreshold())
+ .build())
+ .withSerializer(serverProperties.serializer())
+ .withElectionTimeout(serverProperties.electionTimeout())
+ .withHeartbeatInterval(serverProperties.heartbeatInterval())
+ .withSessionTimeout(serverProperties.sessionTimeout());
+ }
+
/**
* Returns a new Atomix server builder.
*
@@ -465,4 +507,4 @@ public ResourceServer build() {
}
}
-}
+}
\ No newline at end of file
diff --git a/core/src/main/java/io/atomix/util/AtomixProperties.java b/manager/src/main/java/io/atomix/manager/options/AtomixOptions.java
similarity index 59%
rename from core/src/main/java/io/atomix/util/AtomixProperties.java
rename to manager/src/main/java/io/atomix/manager/options/AtomixOptions.java
index 9e0c99acfe..2b7f12a7f4 100644
--- a/core/src/main/java/io/atomix/util/AtomixProperties.java
+++ b/manager/src/main/java/io/atomix/manager/options/AtomixOptions.java
@@ -13,58 +13,38 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-package io.atomix.util;
+package io.atomix.manager.options;
+
+import java.util.Collection;
+import java.util.Properties;
import io.atomix.catalyst.serializer.Serializer;
import io.atomix.catalyst.transport.Address;
-import io.atomix.catalyst.util.ConfigurationException;
import io.atomix.catalyst.util.PropertiesReader;
import io.atomix.catalyst.util.QualifiedProperties;
-import java.util.Collection;
-import java.util.Properties;
-
/**
- * Base class for Atomix properties.
+ * Atomix options.
*
* @author replicas() {
- return reader.getCollection(SEED, p -> parseAddress(reader.getString(p)));
- }
-
- /**
- * Parses an address string.
- *
- * @param address The address string.
- * @return The address.
- */
- protected Address parseAddress(String address) {
- String[] split = address.split(":");
- if (split.length != 2) {
- throw new ConfigurationException("malformed address: " + address);
- }
-
- try {
- return new Address(split[0], Integer.valueOf(split[1]));
- } catch (NumberFormatException e) {
- throw new ConfigurationException("invalid port number: " + split[1]);
- }
+ public Collection servers() {
+ return reader.getCollection(SEED, p -> new Address(reader.getString(p)));
}
/**
diff --git a/core/src/main/java/io/atomix/util/ClientProperties.java b/manager/src/main/java/io/atomix/manager/options/ClientOptions.java
similarity index 91%
rename from core/src/main/java/io/atomix/util/ClientProperties.java
rename to manager/src/main/java/io/atomix/manager/options/ClientOptions.java
index 5fa5e2156a..919ac41eba 100644
--- a/core/src/main/java/io/atomix/util/ClientProperties.java
+++ b/manager/src/main/java/io/atomix/manager/options/ClientOptions.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License
*/
-package io.atomix.util;
+package io.atomix.manager.options;
import io.atomix.catalyst.transport.Transport;
import io.atomix.catalyst.util.ConfigurationException;
@@ -23,16 +23,16 @@
import java.util.Properties;
/**
- * Atomix client properties.
+ * Client options.
*
* @author concurrent
variables
core
+ standalone
examples
testing
all
@@ -150,7 +151,7 @@
Atomix API Reference (${jv})
Atomix API Reference (${jv})
true
- io.atomix.examples*:*.state*:*.util*:io.atomix.testing*
+ io.atomix.examples*:*.state*:*.util*:io.atomix.testing*:*.config
-Xdoclint:none
-notimestamp
diff --git a/standalone/.gitignore b/standalone/.gitignore
new file mode 100644
index 0000000000..176aab5aa2
--- /dev/null
+++ b/standalone/.gitignore
@@ -0,0 +1,2 @@
+*.log
+/target
diff --git a/standalone/pom.xml b/standalone/pom.xml
new file mode 100644
index 0000000000..032ae0133e
--- /dev/null
+++ b/standalone/pom.xml
@@ -0,0 +1,38 @@
+
+
+ 4.0.0
+
+
+ io.atomix
+ atomix-parent
+ 1.0.0-SNAPSHOT
+
+
+ atomix-standalone-parent
+ pom
+ Atomix Standalone Parent Pom
+ Standalone Atomix Processes.
+ http://github.com/atomix/atomix
+ 2013
+
+
+ 1.1.2
+
+
+
+ standalone-server
+
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+
diff --git a/standalone/standalone-server/conf/example.properties b/standalone/standalone-server/conf/example.properties
new file mode 100644
index 0000000000..b48df391d1
--- /dev/null
+++ b/standalone/standalone-server/conf/example.properties
@@ -0,0 +1,115 @@
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed 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
+#
+
+# This is the address to which to bind the local server. This address may or may
+# not be present in the cluster.seed list below. If the address is present in the
+# seed list, this node will start as a full member of the cluster. If the address is
+# not present in the seed list, this node will join the cluster defined by the seeds.
+server.address=localhost:5000
+
+# This is the transport to use to communicate between replicas. The transport must
+# be the same class on all replicas.
+server.transport=io.atomix.catalyst.transport.NettyTransport
+
+# These are standard TCP configuration options.
+server.transport.connectTimeout=5000
+server.transport.sendBufferSize=-1
+server.transport.receiveBufferSize=-1
+server.transport.reuseAddress=true
+server.transport.tcpKeepAlive=true
+server.transport.tcpNoDelay=false
+server.transport.acceptBacklog=1024
+
+# This property indicates whether SSL should be enabled for the transport.
+server.transport.ssl.enabled=false
+
+# This is a list of members of the cluster to which to connect. If the local member
+# is joining a cluster, its address will not be present in the seed list. If the
+# local member is forming a new cluster, its address will be present in the seed
+# list. The first time the cluster is started, n seed nodes should be started where
+# n is the size of the Raft quorum.
+cluster.seed.1=localhost:5000
+cluster.seed.2=localhost:5001
+cluster.seed.3=localhost:5002
+
+# This property indicates the desired size of the quorum. The quorum consists
+# of some set of nodes that participate in the Raft consensus algorithm. Writes to
+# the cluster are synchronously replicated to a majority of the members in the quorum.
+# Atomix guarantees that at least cluster.quorumHint replicas will be in the quorum
+# so long as cluster.quorumHint members have joined the cluster.
+# The default value of -1 indicates that the cluster.seed list represents the desired
+# quorum size. This is typically a good default since clusters are normally started with
+# the desired number of nodes as seed nodes.
+cluster.quorumHint=-1
+
+# This property indicates the desired number of backup replicas for each active member
+# of the quorum. When a quorum member is partitioned or crashes, Atomix will attempt to
+# replace that member with a backup replica. The process of replacing nodes can be shortened
+# by replicating to more backup nodes. Members of the quorum replicate to backup nodes
+# asynchronously, so the number of backups does not significantly impact latency.
+cluster.backupCount=0
+
+# These properties are Raft-specific configurations that define the intervals at which
+# Raft servers and clients communicate with one another. The electionTimeout and heartbeatInterval
+# control the frequency of communication between servers. The sessionTimeout controls the
+# frequency of keep-alive requests from clients. Note that decreasing the sessionTimeout can
+# result in e.g. a lock held by a crashed node being released sooner, but decreasing the sessionTimeout
+# also implies more overhead for frequent keep-aive requests.
+cluster.electionTimeout=1000
+cluster.heartbeatInterval=500
+cluster.sessionTimeout=10000
+
+# These properties dictate how Raft logs are stored for this replica. By default, Atomix stores
+# logs on disk. Alternatively, the MAPPED and MEMORY storage.level can be used for greater efficiency
+# at the potential expense of more memory consumption and loss of safety. In order for writes to be
+# lost in a cluster of replicas using storage.level=MEMORY, a majority of the cluster would have
+# to crash and lose their logs from memory.
+storage.level=DISK
+storage.directory=logs
+storage.maxSegmentSize=33554432
+storage.maxEntriesPerSegment=1048576
+
+# These properties dictate the behavior of log compaction in Atomix. Log compaction includes a
+# combination of incremental rewrites of the log and storage of snapshots of the system's state.
+# Snapshots inherit the storage.level, so snapshots stored with storage.level=MEMORY will not
+# be stored on disk but can be replicated to other servers.
+storage.compaction.maxSnapshotSize=33554432
+storage.compaction.retainSnapshots=false
+storage.compaction.threads=2
+storage.compaction.minor=60000
+storage.compaction.major=600000
+storage.compaction.threshold=0.5
+
+# These properties dictate the behavior of the serializer. Serializable types can be registered
+# along with serializable type IDs for more efficient serialization.
+
+# This property indicates whether serializable types must be whitelisted. If types must be whitelisted
+# for serialization, serializable types must be registered in the serializer.types.* properties.
+# If whitelisting is disabled, unregistered types may be serialized with their class name.
+serializer.whitelist=false
+serializer.allocator=io.atomix.catalyst.buffer.PooledHeapAllocator
+
+# This is an example of a serializable type and custom serializer.
+#serializer.types.1=com.mycompany.FooClass
+#serializer.serializers.1=com.mycompany.FooClassSerializer
+
+# This is an example of a serializable abstract type and a custom abstract type serializer.
+#serializer.types.2=com.mycompany.AbstractFooClass
+#serializer.abstractSerializers.2=com.mycompany.AbstractFooClassSerializer
+
+# This is an example of a serialization framework interface and the default framework serializer.
+#serializer.types.3=com.mycompany.MyCompanySerializable
+#serializer.defaultSerializers.3=com.mycompany.MyCompanySerializableSerializer
diff --git a/examples/standalone-server/pom.xml b/standalone/standalone-server/pom.xml
similarity index 74%
rename from examples/standalone-server/pom.xml
rename to standalone/standalone-server/pom.xml
index a7cfaa3474..52af3dbbb8 100644
--- a/examples/standalone-server/pom.xml
+++ b/standalone/standalone-server/pom.xml
@@ -4,24 +4,35 @@
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. -->
-
+
4.0.0
io.atomix
- atomix-examples-parent
+ atomix-standalone-parent
1.0.0-SNAPSHOT
- atomix-standalone-server-example
- Atomix Resources Example
+ atomix-standalone-server
+ Atomix Standalone Server
io.atomix
- atomix-all
+ atomix-resource-manager
${project.version}
+
+ io.atomix.catalyst
+ catalyst-netty
+ ${catalyst.version}
+
+
+ net.sourceforge.argparse4j
+ argparse4j
+ 0.7.0
+
@@ -32,6 +43,7 @@
1.6
true
+ true
atomix-standalone-server
@@ -56,7 +68,7 @@
- io.atomix.examples.server.StandaloneServerExample
+ io.atomix.standalone.server.StandaloneServer
diff --git a/standalone/standalone-server/src/main/java/io/atomix/standalone/server/StandaloneServer.java b/standalone/standalone-server/src/main/java/io/atomix/standalone/server/StandaloneServer.java
new file mode 100644
index 0000000000..0468ae8c56
--- /dev/null
+++ b/standalone/standalone-server/src/main/java/io/atomix/standalone/server/StandaloneServer.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2016 the original author or authors.
+ *
+ * Licensed 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 io.atomix.standalone.server;
+
+import java.util.List;
+import java.util.Properties;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import io.atomix.catalyst.transport.Address;
+import io.atomix.catalyst.util.PropertiesReader;
+import io.atomix.manager.ResourceServer;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+import net.sourceforge.argparse4j.inf.Namespace;
+
+/**
+ * Standalone Server.
+ *
+ * @author Jonathan Halterman
+ */
+public class StandaloneServer {
+ public static void main(String[] args) throws Exception {
+ ArgumentParser parser = ArgumentParsers.newArgumentParser("AtomixServer")
+ .defaultHelp(true)
+ .description("Atomix server");
+ parser.addArgument("-config").help("Atomix configuration file");
+ parser.addArgument("-server").help("Server address in host:port format");
+ parser.addArgument("-seed").help("Comma-separated list of seed node addresses in host:port format");
+
+ Namespace ns = null;
+ try {
+ ns = parser.parseArgs(args);
+ } catch (ArgumentParserException e) {
+ parser.handleError(e);
+ System.exit(1);
+ }
+
+ ResourceServer.Builder builder = null;
+ String config = ns.getString("config");
+
+ if (config != null) {
+ Properties properties = PropertiesReader.load(config).properties();
+ builder = ResourceServer.builder(properties);
+ } else {
+ String server = ns.getString("server");
+ String seed = ns.getString("seed");
+ if (server == null || seed == null) {
+ System.err.println("Must supply -config or -server and -seed");
+ System.exit(1);
+ }
+
+ List seeds = Stream.of(seed.split(",")).map(a -> new Address(a)).collect(Collectors.toList());
+ builder = ResourceServer.builder(new Address(server), seeds);
+ }
+
+ ResourceServer server = builder.build();
+ server.start().join();
+
+ while (server.isRunning()) {
+ synchronized (StandaloneServer.class) {
+ StandaloneServer.class.wait();
+ }
+ }
+ }
+}
diff --git a/examples/standalone-server/src/main/resources/logback.xml b/standalone/standalone-server/src/main/resources/logback.xml
similarity index 100%
rename from examples/standalone-server/src/main/resources/logback.xml
rename to standalone/standalone-server/src/main/resources/logback.xml