This is an automated email from the ASF dual-hosted git repository.
shoothzj pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new d92bd204dd [client] new API to check if Bookkeeper client is connected
to metadata service (#4342)
d92bd204dd is described below
commit d92bd204ddc27e4a3b931c59136c1436364f5dd4
Author: congbo <[email protected]>
AuthorDate: Fri Jul 26 10:09:25 2024 +0800
[client] new API to check if Bookkeeper client is connected to metadata
service (#4342)
# Motivation
when zookeeper disconnect, use bookkeeper api to create new ledger will
fail. add a new api to check metadata driver is available, if not available,
use current ledger continue and don't rollover ledger
## ** tip **
Although it may not solve all issues since it's not atomic, it will reduce
the losses caused by zk unavailability.
# Modification
add a new api named isDriverMetadataServiceAvailable
---
.../org/apache/bookkeeper/client/BookKeeper.java | 5 +++
.../apache/bookkeeper/client/api/BookKeeper.java | 7 +++
.../bookkeeper/meta/MetadataClientDriver.java | 9 ++++
.../bookkeeper/meta/zk/ZKMetadataClientDriver.java | 5 +++
.../bookkeeper/meta/zk/ZKMetadataDriverBase.java | 23 ++++++++++
.../api/DriverMetadataServiceAvailableTest.java | 52 ++++++++++++++++++++++
.../meta/zk/ZKMetadataDriverTestBase.java | 1 +
7 files changed, 102 insertions(+)
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeper.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeper.java
index a42128ec42..2433bb9efa 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeper.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/BookKeeper.java
@@ -1609,6 +1609,11 @@ public class BookKeeper implements
org.apache.bookkeeper.client.api.BookKeeper {
});
}
+ @Override
+ public CompletableFuture<Boolean> isDriverMetadataServiceAvailable() {
+ return metadataDriver.isMetadataServiceAvailable();
+ }
+
private final ClientContext clientCtx = new ClientContext() {
@Override
public ClientInternalConf getConf() {
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/BookKeeper.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/BookKeeper.java
index 1e7fa35670..7b041d9a70 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/BookKeeper.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/client/api/BookKeeper.java
@@ -81,6 +81,13 @@ public interface BookKeeper extends AutoCloseable {
*/
CompletableFuture<LedgerMetadata> getLedgerMetadata(long ledgerId);
+ /**
+ * Return driver metadata service is available.
+ *
+ * @return the metadata service is available.
+ */
+ CompletableFuture<Boolean> isDriverMetadataServiceAvailable();
+
/**
* Close the client and release every resource.
*
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/MetadataClientDriver.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/MetadataClientDriver.java
index 1615f04ecd..d71c32f63e 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/MetadataClientDriver.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/MetadataClientDriver.java
@@ -114,4 +114,13 @@ public interface MetadataClientDriver extends
AutoCloseable {
default CompletableFuture<Boolean> isHealthCheckEnabled() {
return FutureUtils.value(true);
}
+
+ /**
+ * Return driver metadata service is available.
+ *
+ * @return the metadata service is available.
+ */
+ default CompletableFuture<Boolean> isMetadataServiceAvailable() {
+ return FutureUtils.value(true);
+ }
}
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriver.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriver.java
index 1fe6210ce9..a89dd31f14 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriver.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataClientDriver.java
@@ -20,6 +20,7 @@ package org.apache.bookkeeper.meta.zk;
import com.google.common.annotations.VisibleForTesting;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import lombok.extern.slf4j.Slf4j;
import org.apache.bookkeeper.conf.ClientConfiguration;
@@ -111,4 +112,8 @@ public class ZKMetadataClientDriver
}
});
}
+
+ public CompletableFuture<Boolean> isMetadataServiceAvailable() {
+ return CompletableFuture.completedFuture(metadataServiceAvailable);
+ }
}
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBase.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBase.java
index 643ddd3ced..b85176a1af 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBase.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverBase.java
@@ -27,6 +27,7 @@ import static
org.apache.bookkeeper.util.BookKeeperConstants.READONLY;
import java.io.IOException;
import java.net.URI;
+import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@@ -53,6 +54,7 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.ACL;
import org.apache.zookeeper.data.Stat;
@@ -64,6 +66,9 @@ import org.apache.zookeeper.data.Stat;
public class ZKMetadataDriverBase implements AutoCloseable {
protected static final String SCHEME = "zk";
+
+ protected volatile boolean metadataServiceAvailable;
+
private static final int ZK_CLIENT_WAIT_FOR_SHUTDOWN_TIMEOUT_MS = 5000;
public static String getZKServersFromServiceUri(URI uri) {
@@ -179,6 +184,7 @@ public class ZKMetadataDriverBase implements AutoCloseable {
// if an external zookeeper is added, use the zookeeper instance
this.zk = (ZooKeeper) (optionalCtx.get());
this.ownZKHandle = false;
+ this.metadataServiceAvailable = true;
} else {
final String metadataServiceUriStr;
try {
@@ -212,6 +218,12 @@ public class ZKMetadataDriverBase implements AutoCloseable
{
.sessionTimeoutMs(conf.getZkTimeout())
.operationRetryPolicy(zkRetryPolicy)
.requestRateLimit(conf.getZkRequestRateLimit())
+ .watchers(Collections.singleton(watchedEvent -> {
+ if (log.isDebugEnabled()) {
+ log.debug("Got ZK session watch event: {}",
watchedEvent);
+ }
+ handleState(watchedEvent.getState());
+ }))
.statsLogger(statsLogger)
.build();
@@ -247,6 +259,17 @@ public class ZKMetadataDriverBase implements AutoCloseable
{
acls);
}
+ private void handleState(Watcher.Event.KeeperState zkClientState) {
+ switch (zkClientState) {
+ case Expired:
+ case Disconnected:
+ this.metadataServiceAvailable = false;
+ break;
+ default:
+ this.metadataServiceAvailable = true;
+ }
+ }
+
public LayoutManager getLayoutManager() {
return layoutManager;
}
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/DriverMetadataServiceAvailableTest.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/DriverMetadataServiceAvailableTest.java
new file mode 100644
index 0000000000..2b0c01bf8e
--- /dev/null
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/client/api/DriverMetadataServiceAvailableTest.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.bookkeeper.client.api;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.apache.bookkeeper.conf.ClientConfiguration;
+import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
+import org.awaitility.Awaitility;
+import org.junit.Test;
+
+/**
+ * Bookkeeper Client API driver metadata service available test.
+ */
+public class DriverMetadataServiceAvailableTest extends
BookKeeperClusterTestCase {
+
+ public DriverMetadataServiceAvailableTest() {
+ super(3);
+ }
+
+ @Test
+ public void testDriverMetadataServiceAvailable()
+ throws Exception {
+ ClientConfiguration conf = new ClientConfiguration();
+ conf.setMetadataServiceUri(zkUtil.getMetadataServiceUri());
+ conf.setZkTimeout(3000);
+ try (BookKeeper bkc = BookKeeper.newBuilder(conf).build()) {
+ Awaitility.await().until(() ->
bkc.isDriverMetadataServiceAvailable().get());
+ zkUtil.sleepCluster(5, TimeUnit.SECONDS, new CountDownLatch(1));
+ Awaitility.await().until(() ->
!bkc.isDriverMetadataServiceAvailable().get());
+ Awaitility.await().until(() ->
bkc.isDriverMetadataServiceAvailable().get());
+ }
+ }
+}
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java
index e5129fb716..38c85ec7af 100644
---
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/meta/zk/ZKMetadataDriverTestBase.java
@@ -57,6 +57,7 @@ public abstract class ZKMetadataDriverTestBase {
when(mockZkBuilder.operationRetryPolicy(any(RetryPolicy.class)))
.thenReturn(mockZkBuilder);
when(mockZkBuilder.requestRateLimit(anyDouble())).thenReturn(mockZkBuilder);
+ when(mockZkBuilder.watchers(any())).thenReturn(mockZkBuilder);
when(mockZkBuilder.statsLogger(any(StatsLogger.class))).thenReturn(mockZkBuilder);
this.mockZkc = mock(ZooKeeperClient.class);