diff --git a/README.md b/README.md index 8d1aad7..3f55777 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ etcd-java requires Java 8 or higher. ## Usage -Create the client. Methods are grouped into separate `KvClient`, `LeaseClient` and `LockClient` interfaces. - +Create the client. Methods are grouped into separate `KvClient`, `LeaseClient`, `LockClient`, and `MaintenanceClient` interfaces. ```java KvStoreClient client = EtcdClient.forEndpoint("localhost", 2379).withPlainText().build(); @@ -29,7 +28,7 @@ KvStoreClient client = EtcdClient.forEndpoint("localhost", 2379).withPlainText() KvClient kvClient = client.getKvClient(); LeaseClient leaseClient = client.getLeaseClient(); LockClient lockClient = client.getLockClient(); - +MaintenanceClient maintenanceClient = client.getMaintenanceClient(); ``` Put a key-value synchronously diff --git a/src/main/java/com/ibm/etcd/client/EtcdClient.java b/src/main/java/com/ibm/etcd/client/EtcdClient.java index be82293..a5135c9 100644 --- a/src/main/java/com/ibm/etcd/client/EtcdClient.java +++ b/src/main/java/com/ibm/etcd/client/EtcdClient.java @@ -65,6 +65,8 @@ import com.ibm.etcd.client.lease.PersistentLease; import com.ibm.etcd.client.lock.EtcdLockClient; import com.ibm.etcd.client.lock.LockClient; +import com.ibm.etcd.client.maintenance.EtcdMaintenanceClient; +import com.ibm.etcd.client.maintenance.MaintenanceClient; import io.grpc.CallCredentials; import io.grpc.CallOptions; @@ -129,6 +131,7 @@ public class EtcdClient implements KvStoreClient { private final EtcdKvClient kvClient; private volatile LeaseClient leaseClient; // lazy-instantiated private volatile LockClient lockClient; // lazy-instantiated + private volatile MaintenanceClient maintenanceClient; // lazy-instantiated private volatile PersistentLease sessionLease; // lazy-instantiated public static class Builder { @@ -740,6 +743,17 @@ public LockClient getLockClient() { return lc; } + @Override + public MaintenanceClient getMaintenanceClient() { + MaintenanceClient mc = maintenanceClient; + if (mc == null) synchronized (this) { + if ((mc = maintenanceClient) == null) { + maintenanceClient = mc = new EtcdMaintenanceClient(grpc); + } + } + return mc; + } + @Override public PersistentLease getSessionLease() { PersistentLease sl = sessionLease; diff --git a/src/main/java/com/ibm/etcd/client/KvStoreClient.java b/src/main/java/com/ibm/etcd/client/KvStoreClient.java index 9030393..3a99662 100644 --- a/src/main/java/com/ibm/etcd/client/KvStoreClient.java +++ b/src/main/java/com/ibm/etcd/client/KvStoreClient.java @@ -21,6 +21,7 @@ import com.ibm.etcd.client.lease.LeaseClient; import com.ibm.etcd.client.lease.PersistentLease; import com.ibm.etcd.client.lock.LockClient; +import com.ibm.etcd.client.maintenance.MaintenanceClient; public interface KvStoreClient extends Closeable { @@ -30,6 +31,8 @@ public interface KvStoreClient extends Closeable { LockClient getLockClient(); + MaintenanceClient getMaintenanceClient(); + /** * Returns a singular {@link PersistentLease} bound * to the life of this client instance. May be lazily diff --git a/src/main/java/com/ibm/etcd/client/maintenance/EtcdMaintenanceClient.java b/src/main/java/com/ibm/etcd/client/maintenance/EtcdMaintenanceClient.java new file mode 100644 index 0000000..96a44e1 --- /dev/null +++ b/src/main/java/com/ibm/etcd/client/maintenance/EtcdMaintenanceClient.java @@ -0,0 +1,41 @@ +package com.ibm.etcd.client.maintenance; + +import com.google.common.util.concurrent.ListenableFuture; +import com.ibm.etcd.api.*; +import com.ibm.etcd.client.GrpcClient; +import io.grpc.MethodDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class EtcdMaintenanceClient implements MaintenanceClient { + private static final Logger logger = LoggerFactory.getLogger(EtcdMaintenanceClient.class); + + private static final MethodDescriptor METHOD_ENDPOINT_STATUS = + MaintenanceGrpc.getStatusMethod(); + private static final MethodDescriptor METHOD_ENDPOINT_HASHKV = + MaintenanceGrpc.getHashKVMethod(); + private static final MethodDescriptor METHOD_ENDPOINT_DEFRAG = + MaintenanceGrpc.getDefragmentMethod(); + + private final GrpcClient client; + + public EtcdMaintenanceClient(GrpcClient client) { + this.client = client; + } + + @Override + public ListenableFuture status() { + return client.call(METHOD_ENDPOINT_STATUS, StatusRequest.newBuilder().build(), false); + } + + @Override + public ListenableFuture hashkv() { + return client.call(METHOD_ENDPOINT_HASHKV, HashKVRequest.newBuilder().build(), false); + } + + @Override + public ListenableFuture defrag() { + return client.call(METHOD_ENDPOINT_DEFRAG, DefragmentRequest.newBuilder().build(), false); + } + +} diff --git a/src/main/java/com/ibm/etcd/client/maintenance/MaintenanceClient.java b/src/main/java/com/ibm/etcd/client/maintenance/MaintenanceClient.java new file mode 100644 index 0000000..1850e2e --- /dev/null +++ b/src/main/java/com/ibm/etcd/client/maintenance/MaintenanceClient.java @@ -0,0 +1,26 @@ +package com.ibm.etcd.client.maintenance; + +import com.google.common.util.concurrent.ListenableFuture; +import com.ibm.etcd.api.HashKVResponse; +import com.ibm.etcd.api.StatusResponse; +import com.ibm.etcd.api.DefragmentResponse; + +public interface MaintenanceClient { + /** + * + * @return future for {@link StatusResponse} + */ + ListenableFuture status(); + + /** + * + * @return future for {@link HashKVResponse} + */ + ListenableFuture hashkv(); + + /** + * + * @return future for {@link DefragmentResponse} + */ + ListenableFuture defrag(); +} diff --git a/src/test/java/com/ibm/etcd/client/EtcdTestSuite.java b/src/test/java/com/ibm/etcd/client/EtcdTestSuite.java index 2d24971..aa46aea 100644 --- a/src/test/java/com/ibm/etcd/client/EtcdTestSuite.java +++ b/src/test/java/com/ibm/etcd/client/EtcdTestSuite.java @@ -49,7 +49,8 @@ LeaseTest.class, LockTest.class, PersistentLeaseKeyTest.class, - RangeCacheTest.class + RangeCacheTest.class, + MaintenanceTest.class }) public class EtcdTestSuite { diff --git a/src/test/java/com/ibm/etcd/client/MaintenanceTest.java b/src/test/java/com/ibm/etcd/client/MaintenanceTest.java new file mode 100644 index 0000000..d9fd563 --- /dev/null +++ b/src/test/java/com/ibm/etcd/client/MaintenanceTest.java @@ -0,0 +1,55 @@ +package com.ibm.etcd.client; + +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import com.ibm.etcd.api.*; +import com.ibm.etcd.client.maintenance.MaintenanceClient; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +public class MaintenanceTest { + static KvStoreClient client; + + static MaintenanceClient maintenanceClient; + + @BeforeClass + public static void setup() { + client = EtcdClient.forEndpoint("localhost", 2379) + .withPlainText().build(); + maintenanceClient = client.getMaintenanceClient(); + } + @AfterClass + public static void teardown() throws Exception { + if (client != null) { + client.close(); + } + } + + @Test + public void testStatus() throws Exception { + StatusResponse resp = maintenanceClient.status().get(1, SECONDS); + assertNotNull(resp.getVersion()); + assertTrue(resp.getDbSize() > 0L); + assertTrue(resp.getDbSizeInUse() > 0L); + assertTrue(resp.hasHeader()); + assertTrue(resp.getHeader().getRevision() > 0L); + } + + @Test + public void testHashkv() throws Exception { + HashKVResponse resp = maintenanceClient.hashkv().get(1, SECONDS); + assertNotNull(resp); + assertTrue(resp.getHash() != 0L); + assertTrue(resp.hasHeader()); + assertTrue(resp.getHeader().getRevision() > 0L); + } + + @Test + public void testDefrag() throws Exception { + DefragmentResponse resp = maintenanceClient.defrag().get(5, SECONDS); + assertNotNull(resp); + } +}