This is an automated email from the ASF dual-hosted git repository.
chenhang 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 e169cbd3f5 Add new api resumeCompaction and suspendCompaction to
support resume and suspend compaction through api (#3509)
e169cbd3f5 is described below
commit e169cbd3f5785d107beff115056ce2068e0e45ba
Author: gaozhangmin <[email protected]>
AuthorDate: Wed Oct 26 12:04:31 2022 +0800
Add new api resumeCompaction and suspendCompaction to support resume and
suspend compaction through api (#3509)
### Motivation
Compaction would bring high disk io util, It would better allowing to
control suspending and resuming compaction through api
### Changes
Add two apis to control resuming and suspending compaction.
`/api/v1/bookie/gc/suspend_compaction`
`/api/v1/bookie/gc/resume_compaction`
---
.../org/apache/bookkeeper/http/HttpRouter.java | 4 +
.../org/apache/bookkeeper/http/HttpServer.java | 3 +-
.../bookkeeper/bookie/GarbageCollectorThread.java | 8 ++
.../bookie/InterleavedLedgerStorage.java | 24 ++++++
.../apache/bookkeeper/bookie/LedgerStorage.java | 24 ++++++
.../bookkeeper/bookie/SortedLedgerStorage.java | 30 +++++++
.../bookie/storage/ldb/DbLedgerStorage.java | 30 +++++++
.../ldb/SingleDirectoryDbLedgerStorage.java | 24 ++++++
.../server/http/BKHttpServiceProvider.java | 6 ++
.../http/service/ResumeCompactionService.java | 86 +++++++++++++++++++
.../http/service/SuspendCompactionService.java | 99 ++++++++++++++++++++++
.../bookkeeper/bookie/MockLedgerStorage.java | 24 ++++++
.../bookkeeper/server/http/TestHttpService.java | 71 ++++++++++++++++
site3/website/docs/admin/http.md | 53 ++++++++++++
14 files changed, 485 insertions(+), 1 deletion(-)
diff --git
a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java
b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java
index e4dbf299e0..1d1d562ff7 100644
---
a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java
+++
b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpRouter.java
@@ -47,6 +47,8 @@ public abstract class HttpRouter<Handler> {
public static final String EXPAND_STORAGE =
"/api/v1/bookie/expand_storage";
public static final String GC =
"/api/v1/bookie/gc";
public static final String GC_DETAILS =
"/api/v1/bookie/gc_details";
+ public static final String SUSPEND_GC_COMPACTION =
"/api/v1/bookie/gc/suspend_compaction";
+ public static final String RESUME_GC_COMPACTION =
"/api/v1/bookie/gc/resume_compaction";
public static final String BOOKIE_STATE =
"/api/v1/bookie/state";
public static final String BOOKIE_STATE_READONLY =
"/api/v1/bookie/state/readonly";
public static final String BOOKIE_IS_READY =
"/api/v1/bookie/is_ready";
@@ -87,6 +89,8 @@ public abstract class HttpRouter<Handler> {
handlerFactory.newHandler(HttpServer.ApiType.BOOKIE_STATE_READONLY));
this.endpointHandlers.put(BOOKIE_IS_READY,
handlerFactory.newHandler(HttpServer.ApiType.BOOKIE_IS_READY));
this.endpointHandlers.put(BOOKIE_INFO,
handlerFactory.newHandler(HttpServer.ApiType.BOOKIE_INFO));
+ this.endpointHandlers.put(SUSPEND_GC_COMPACTION,
handlerFactory.newHandler(HttpServer.ApiType.SUSPEND_GC_COMPACTION));
+ this.endpointHandlers.put(RESUME_GC_COMPACTION,
handlerFactory.newHandler(HttpServer.ApiType.RESUME_GC_COMPACTION));
// autorecovery
this.endpointHandlers.put(AUTORECOVERY_STATUS, handlerFactory
diff --git
a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java
b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java
index 902194a0ec..7bfd62e975 100644
---
a/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java
+++
b/bookkeeper-http/http-server/src/main/java/org/apache/bookkeeper/http/HttpServer.java
@@ -85,7 +85,8 @@ public interface HttpServer {
BOOKIE_STATE_READONLY,
BOOKIE_IS_READY,
BOOKIE_INFO,
-
+ RESUME_GC_COMPACTION,
+ SUSPEND_GC_COMPACTION,
// autorecovery
AUTORECOVERY_STATUS,
RECOVERY_BOOKIE,
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/GarbageCollectorThread.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/GarbageCollectorThread.java
index 2e153f7ab7..7502205ffa 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/GarbageCollectorThread.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/GarbageCollectorThread.java
@@ -333,6 +333,14 @@ public class GarbageCollectorThread extends SafeRunnable {
return forceGarbageCollection.get();
}
+ public boolean isMajorGcSuspend() {
+ return suspendMajorCompaction.get();
+ }
+
+ public boolean isMinorGcSuspend() {
+ return suspendMinorCompaction.get();
+ }
+
public void suspendMajorGC() {
if (suspendMajorCompaction.compareAndSet(false, true)) {
LOG.info("Suspend Major Compaction triggered by thread: {}",
Thread.currentThread().getName());
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorage.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorage.java
index 7597acc0a6..083a14f36e 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorage.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/InterleavedLedgerStorage.java
@@ -273,6 +273,30 @@ public class InterleavedLedgerStorage implements
CompactableLedgerStorage, Entry
return gcThread.isInForceGC();
}
+ public void suspendMinorGC() {
+ gcThread.suspendMinorGC();
+ }
+
+ public void suspendMajorGC() {
+ gcThread.suspendMajorGC();
+ }
+
+ public void resumeMinorGC() {
+ gcThread.resumeMinorGC();
+ }
+
+ public void resumeMajorGC() {
+ gcThread.resumeMajorGC();
+ }
+
+ public boolean isMajorGcSuspended() {
+ return gcThread.isMajorGcSuspend();
+ }
+
+ public boolean isMinorGcSuspended() {
+ return gcThread.isMinorGcSuspend();
+ }
+
@Override
public void start() {
gcThread.start();
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerStorage.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerStorage.java
index c409112eef..6b0b0fd37e 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerStorage.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/LedgerStorage.java
@@ -236,6 +236,30 @@ public interface LedgerStorage {
return;
}
+ default void suspendMinorGC() {
+ return;
+ }
+
+ default void suspendMajorGC() {
+ return;
+ }
+
+ default void resumeMinorGC() {
+ return;
+ }
+
+ default void resumeMajorGC() {
+ return;
+ }
+
+ default boolean isMajorGcSuspended() {
+ return false;
+ }
+
+ default boolean isMinorGcSuspended() {
+ return false;
+ }
+
/**
* Class for describing location of a generic inconsistency.
Implementations should
* ensure that detail is populated with an exception which adequately
describes the
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/SortedLedgerStorage.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/SortedLedgerStorage.java
index b9a4b7cfd8..d7984b1c2e 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/SortedLedgerStorage.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/SortedLedgerStorage.java
@@ -376,6 +376,36 @@ public class SortedLedgerStorage
interleavedLedgerStorage.forceGC(forceMajor, forceMinor);
}
+ @Override
+ public void suspendMinorGC() {
+ interleavedLedgerStorage.suspendMinorGC();
+ }
+
+ @Override
+ public void suspendMajorGC() {
+ interleavedLedgerStorage.suspendMajorGC();
+ }
+
+ @Override
+ public void resumeMinorGC() {
+ interleavedLedgerStorage.resumeMinorGC();
+ }
+
+ @Override
+ public void resumeMajorGC() {
+ interleavedLedgerStorage.resumeMajorGC();
+ }
+
+ @Override
+ public boolean isMajorGcSuspended() {
+ return interleavedLedgerStorage.isMajorGcSuspended();
+ }
+
+ @Override
+ public boolean isMinorGcSuspended() {
+ return interleavedLedgerStorage.isMinorGcSuspended();
+ }
+
@Override
public List<DetectedInconsistency>
localConsistencyCheck(Optional<RateLimiter> rateLimiter) throws IOException {
return interleavedLedgerStorage.localConsistencyCheck(rateLimiter);
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorage.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorage.java
index d1404e0179..f5784423d6 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorage.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/DbLedgerStorage.java
@@ -524,6 +524,36 @@ public class DbLedgerStorage implements LedgerStorage {
return
ledgerStorageList.stream().anyMatch(SingleDirectoryDbLedgerStorage::isInForceGC);
}
+ @Override
+ public void suspendMinorGC() {
+
ledgerStorageList.stream().forEach(SingleDirectoryDbLedgerStorage::suspendMinorGC);
+ }
+
+ @Override
+ public void suspendMajorGC() {
+
ledgerStorageList.stream().forEach(SingleDirectoryDbLedgerStorage::suspendMajorGC);
+ }
+
+ @Override
+ public void resumeMinorGC() {
+
ledgerStorageList.stream().forEach(SingleDirectoryDbLedgerStorage::resumeMinorGC);
+ }
+
+ @Override
+ public void resumeMajorGC() {
+
ledgerStorageList.stream().forEach(SingleDirectoryDbLedgerStorage::resumeMajorGC);
+ }
+
+ @Override
+ public boolean isMajorGcSuspended() {
+ return
ledgerStorageList.stream().allMatch(SingleDirectoryDbLedgerStorage::isMajorGcSuspended);
+ }
+
+ @Override
+ public boolean isMinorGcSuspended() {
+ return
ledgerStorageList.stream().allMatch(SingleDirectoryDbLedgerStorage::isMinorGcSuspended);
+ }
+
@Override
public List<GarbageCollectionStatus> getGarbageCollectionStatus() {
return ledgerStorageList.stream()
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/SingleDirectoryDbLedgerStorage.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/SingleDirectoryDbLedgerStorage.java
index d15eaf10c5..8b752b33ca 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/SingleDirectoryDbLedgerStorage.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/bookie/storage/ldb/SingleDirectoryDbLedgerStorage.java
@@ -278,6 +278,30 @@ public class SingleDirectoryDbLedgerStorage implements
CompactableLedgerStorage
return gcThread.isInForceGC();
}
+ public void suspendMinorGC() {
+ gcThread.suspendMinorGC();
+ }
+
+ public void suspendMajorGC() {
+ gcThread.suspendMajorGC();
+ }
+
+ public void resumeMinorGC() {
+ gcThread.resumeMinorGC();
+ }
+
+ public void resumeMajorGC() {
+ gcThread.resumeMajorGC();
+ }
+
+ public boolean isMajorGcSuspended() {
+ return gcThread.isMajorGcSuspend();
+ }
+
+ public boolean isMinorGcSuspended() {
+ return gcThread.isMinorGcSuspend();
+ }
+
@Override
public void shutdown() throws InterruptedException {
try {
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java
index 0b10f84ed8..8ebf29e831 100644
---
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/BKHttpServiceProvider.java
@@ -58,6 +58,8 @@ import
org.apache.bookkeeper.server.http.service.LostBookieRecoveryDelayService;
import org.apache.bookkeeper.server.http.service.MetricsService;
import org.apache.bookkeeper.server.http.service.ReadLedgerEntryService;
import org.apache.bookkeeper.server.http.service.RecoveryBookieService;
+import org.apache.bookkeeper.server.http.service.ResumeCompactionService;
+import org.apache.bookkeeper.server.http.service.SuspendCompactionService;
import org.apache.bookkeeper.server.http.service.TriggerAuditService;
import org.apache.bookkeeper.server.http.service.TriggerGCService;
import org.apache.bookkeeper.server.http.service.WhoIsAuditorService;
@@ -223,6 +225,10 @@ public class BKHttpServiceProvider implements
HttpServiceProvider {
return new BookieIsReadyService(bookieServer.getBookie());
case BOOKIE_INFO:
return new BookieInfoService(bookieServer.getBookie());
+ case SUSPEND_GC_COMPACTION:
+ return new SuspendCompactionService(bookieServer);
+ case RESUME_GC_COMPACTION:
+ return new ResumeCompactionService(bookieServer);
// autorecovery
case AUTORECOVERY_STATUS:
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/ResumeCompactionService.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/ResumeCompactionService.java
new file mode 100644
index 0000000000..92d66fbcf7
--- /dev/null
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/ResumeCompactionService.java
@@ -0,0 +1,86 @@
+/*
+ * 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.server.http.service;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.bookkeeper.common.util.JsonUtil;
+import org.apache.bookkeeper.http.HttpServer;
+import org.apache.bookkeeper.http.service.HttpEndpointService;
+import org.apache.bookkeeper.http.service.HttpServiceRequest;
+import org.apache.bookkeeper.http.service.HttpServiceResponse;
+import org.apache.bookkeeper.proto.BookieServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ResumeCompactionService implements HttpEndpointService {
+
+ static final Logger LOG =
LoggerFactory.getLogger(ResumeCompactionService.class);
+
+ protected BookieServer bookieServer;
+
+ public ResumeCompactionService(BookieServer bookieServer) {
+ checkNotNull(bookieServer);
+ this.bookieServer = bookieServer;
+ }
+
+ @Override
+ public HttpServiceResponse handle(HttpServiceRequest request) throws
Exception {
+ HttpServiceResponse response = new HttpServiceResponse();
+
+ if (HttpServer.Method.PUT == request.getMethod()) {
+ String requestBody = request.getBody();
+ if (null == requestBody) {
+ return new HttpServiceResponse("Empty request body",
HttpServer.StatusCode.BAD_REQUEST);
+ } else {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> configMap = JsonUtil.fromJson(requestBody,
HashMap.class);
+ Boolean resumeMajor = (Boolean) configMap.get("resumeMajor");
+ Boolean resumeMinor = (Boolean) configMap.get("resumeMinor");
+ if (resumeMajor == null && resumeMinor == null) {
+ return new HttpServiceResponse("No resumeMajor or
resumeMinor params found",
+ HttpServer.StatusCode.BAD_REQUEST);
+ }
+ String output = "";
+ if (resumeMajor != null && resumeMajor) {
+ output = "Resume majorGC on BookieServer: " +
bookieServer.toString();
+
bookieServer.getBookie().getLedgerStorage().resumeMajorGC();
+ }
+ if (resumeMinor != null && resumeMinor) {
+ output += ", Resume minorGC on BookieServer: " +
bookieServer.toString();
+
bookieServer.getBookie().getLedgerStorage().resumeMinorGC();
+ }
+ String jsonResponse = JsonUtil.toJson(output);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("output body:" + jsonResponse);
+ }
+ response.setBody(jsonResponse);
+ response.setCode(HttpServer.StatusCode.OK);
+ return response;
+ }
+ } else {
+ response.setCode(HttpServer.StatusCode.NOT_FOUND);
+ response.setBody("Not found method. Should be PUT to resume major
or minor compaction, Or GET to get "
+ + "compaction state.");
+ return response;
+ }
+ }
+}
diff --git
a/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/SuspendCompactionService.java
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/SuspendCompactionService.java
new file mode 100644
index 0000000000..74e284ad96
--- /dev/null
+++
b/bookkeeper-server/src/main/java/org/apache/bookkeeper/server/http/service/SuspendCompactionService.java
@@ -0,0 +1,99 @@
+/*
+ * 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.server.http.service;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.bookkeeper.common.util.JsonUtil;
+import org.apache.bookkeeper.http.HttpServer;
+import org.apache.bookkeeper.http.service.HttpEndpointService;
+import org.apache.bookkeeper.http.service.HttpServiceRequest;
+import org.apache.bookkeeper.http.service.HttpServiceResponse;
+import org.apache.bookkeeper.proto.BookieServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SuspendCompactionService implements HttpEndpointService {
+
+ static final Logger LOG =
LoggerFactory.getLogger(SuspendCompactionService.class);
+
+ protected BookieServer bookieServer;
+
+ public SuspendCompactionService(BookieServer bookieServer) {
+ checkNotNull(bookieServer);
+ this.bookieServer = bookieServer;
+ }
+
+ @Override
+ public HttpServiceResponse handle(HttpServiceRequest request) throws
Exception {
+ HttpServiceResponse response = new HttpServiceResponse();
+
+ if (HttpServer.Method.PUT == request.getMethod()) {
+ String requestBody = request.getBody();
+ if (null == requestBody) {
+ return new HttpServiceResponse("Empty request body",
HttpServer.StatusCode.BAD_REQUEST);
+ } else {
+ @SuppressWarnings("unchecked")
+ Map<String, Object> configMap = JsonUtil.fromJson(requestBody,
HashMap.class);
+ Boolean suspendMajor = (Boolean) configMap.get("suspendMajor");
+ Boolean suspendMinor = (Boolean) configMap.get("suspendMinor");
+ if (suspendMajor == null && suspendMinor == null) {
+ return new HttpServiceResponse("No suspendMajor or
suspendMinor params found",
+ HttpServer.StatusCode.BAD_REQUEST);
+ }
+ String output = "";
+ if (suspendMajor != null && suspendMajor) {
+ output = "Suspend majorGC on BookieServer: " +
bookieServer.toString();
+
bookieServer.getBookie().getLedgerStorage().suspendMajorGC();
+ }
+ if (suspendMinor != null && suspendMinor) {
+ output += ", Suspend minorGC on BookieServer: " +
bookieServer.toString();
+
bookieServer.getBookie().getLedgerStorage().suspendMinorGC();
+ }
+ String jsonResponse = JsonUtil.toJson(output);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("output body:" + jsonResponse);
+ }
+ response.setBody(jsonResponse);
+ response.setCode(HttpServer.StatusCode.OK);
+ return response;
+ }
+ } else if (HttpServer.Method.GET == request.getMethod()) {
+ boolean isMajorGcSuspend =
bookieServer.getBookie().getLedgerStorage().isMajorGcSuspended();
+ boolean isMinorGcSuspend =
bookieServer.getBookie().getLedgerStorage().isMinorGcSuspended();
+ Map<String, String> output = new HashMap<>();
+ output.put("isMajorGcSuspended",
Boolean.toString(isMajorGcSuspend));
+ output.put("isMinorGcSuspended",
Boolean.toString(isMinorGcSuspend));
+ String jsonResponse = JsonUtil.toJson(output);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("output body:" + jsonResponse);
+ }
+ response.setBody(jsonResponse);
+ response.setCode(HttpServer.StatusCode.OK);
+ return response;
+ } else {
+ response.setCode(HttpServer.StatusCode.NOT_FOUND);
+ response.setBody("Not found method. Should be PUT to suspend major
or minor compaction, "
+ + "Or GET to get compaction state.");
+ return response;
+ }
+ }
+}
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java
index f5b94e422c..33e18e90cd 100644
---
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/bookie/MockLedgerStorage.java
@@ -280,6 +280,30 @@ public class MockLedgerStorage implements
CompactableLedgerStorage {
CompactableLedgerStorage.super.forceGC(forceMajor, forceMinor);
}
+ public void suspendMinorGC() {
+ CompactableLedgerStorage.super.suspendMinorGC();
+ }
+
+ public void suspendMajorGC() {
+ CompactableLedgerStorage.super.suspendMajorGC();
+ }
+
+ public void resumeMinorGC() {
+ CompactableLedgerStorage.super.resumeMinorGC();
+ }
+
+ public void resumeMajorGC() {
+ CompactableLedgerStorage.super.suspendMajorGC();
+ }
+
+ public boolean isMajorGcSuspended() {
+ return CompactableLedgerStorage.super.isMajorGcSuspended();
+ }
+
+ public boolean isMinorGcSuspended() {
+ return CompactableLedgerStorage.super.isMinorGcSuspended();
+ }
+
@Override
public List<DetectedInconsistency>
localConsistencyCheck(Optional<RateLimiter> rateLimiter) throws IOException {
return
CompactableLedgerStorage.super.localConsistencyCheck(rateLimiter);
diff --git
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java
index 1f718f4742..cdb9c4fdd4 100644
---
a/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java
+++
b/bookkeeper-server/src/test/java/org/apache/bookkeeper/server/http/TestHttpService.java
@@ -964,4 +964,75 @@ public class TestHttpService extends
BookKeeperClusterTestCase {
readOnlyState = JsonUtil.fromJson(response.getBody(),
ReadOnlyState.class);
assertFalse(readOnlyState.isReadOnly());
}
+
+ @Test
+ public void testSuspendCompaction() throws Exception {
+ HttpEndpointService suspendCompactionService = bkHttpServiceProvider
+
.provideHttpEndpointService(HttpServer.ApiType.SUSPEND_GC_COMPACTION);
+
+ HttpEndpointService resumeCompactionService = bkHttpServiceProvider
+
.provideHttpEndpointService(HttpServer.ApiType.RESUME_GC_COMPACTION);
+
+ //1, PUT with null body, should return error
+ HttpServiceRequest request1 = new HttpServiceRequest(null,
HttpServer.Method.PUT, null);
+ HttpServiceResponse response1 =
suspendCompactionService.handle(request1);
+ assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(),
response1.getStatusCode());
+
+ //2, PUT with null, should return error, because should contains
"suspendMajor" or "suspendMinor"
+ String putBody2 = "{}";
+ HttpServiceRequest request2 = new HttpServiceRequest(putBody2,
HttpServer.Method.PUT, null);
+ HttpServiceResponse response2 =
suspendCompactionService.handle(request2);
+ assertEquals(HttpServer.StatusCode.BAD_REQUEST.getValue(),
response2.getStatusCode());
+
+
+ //3, GET before suspend, should success
+ HttpServiceRequest request3 = new HttpServiceRequest(null,
HttpServer.Method.GET, null);
+ HttpServiceResponse response3 =
suspendCompactionService.handle(request3);
+ assertEquals(HttpServer.StatusCode.OK.getValue(),
response3.getStatusCode());
+
+ Map responseMap = JsonUtil.fromJson(
+ response3.getBody(),
+ Map.class
+ );
+ assertEquals(responseMap.get("isMajorGcSuspended"), "false");
+ assertEquals(responseMap.get("isMinorGcSuspended"), "false");
+
+
+ //2, PUT, with body, should success
+ String putBody4 = "{\"suspendMajor\": true, \"suspendMinor\": true}";
+ HttpServiceRequest request4 = new HttpServiceRequest(putBody4,
HttpServer.Method.PUT, null);
+ HttpServiceResponse response4 =
suspendCompactionService.handle(request4);
+ assertEquals(HttpServer.StatusCode.OK.getValue(),
response4.getStatusCode());
+
+ //3, GET after suspend, should success
+ HttpServiceRequest request5 = new HttpServiceRequest(null,
HttpServer.Method.GET, null);
+ HttpServiceResponse response5 =
suspendCompactionService.handle(request5);
+ assertEquals(HttpServer.StatusCode.OK.getValue(),
response5.getStatusCode());
+
+ Map responseMap5 = JsonUtil.fromJson(
+ response5.getBody(),
+ Map.class
+ );
+ assertEquals(responseMap5.get("isMajorGcSuspended"), "true");
+ assertEquals(responseMap5.get("isMinorGcSuspended"), "true");
+
+
+ //2, PUT, with body, should success
+ String putBody6 = "{\"resumeMajor\": true, \"resumeMinor\": true}";
+ HttpServiceRequest request6 = new HttpServiceRequest(putBody6,
HttpServer.Method.PUT, null);
+ HttpServiceResponse response6 =
resumeCompactionService.handle(request6);
+ assertEquals(HttpServer.StatusCode.OK.getValue(),
response6.getStatusCode());
+
+ //3, GET after suspend, should success
+ HttpServiceRequest request7 = new HttpServiceRequest(null,
HttpServer.Method.GET, null);
+ HttpServiceResponse response7 =
suspendCompactionService.handle(request7);
+ assertEquals(HttpServer.StatusCode.OK.getValue(),
response7.getStatusCode());
+
+ Map responseMap7 = JsonUtil.fromJson(
+ response7.getBody(),
+ Map.class
+ );
+ assertEquals(responseMap7.get("isMajorGcSuspended"), "false");
+ assertEquals(responseMap7.get("isMinorGcSuspended"), "false");
+ }
}
diff --git a/site3/website/docs/admin/http.md b/site3/website/docs/admin/http.md
index d827720856..6c71c09740 100644
--- a/site3/website/docs/admin/http.md
+++ b/site3/website/docs/admin/http.md
@@ -339,6 +339,59 @@ Currently all the HTTP endpoints could be divided into
these 5 components:
"minorCompactionCounter" : 0
} ]
```
+### Endpoint: /api/v1/bookie/gc/suspend_compaction
+1. Method: PUT
+ * Description: suspend the next compaction stage for this bookie.
+ * Body:
+ ```json
+ {
+ "suspendMajor": "true",
+ "suspendMinor": "true"
+ }
+ ```
+ * Response:
+
+ | Code | Description |
+ |:-------|:------------|
+ |200 | Successful operation |
+ |403 | Permission denied |
+ |404 | Not found |
+
+2. Method: GET
+ * Description: whether major or minor compaction is suspending or not
for this bookie. true for is running.
+ * Response:
+
+ | Code | Description |
+ |:-------|:------------|
+ |200 | Successful operation |
+ |403 | Permission denied |
+ |404 | Not found |
+ * Body:
+ ```json
+ {
+ "isMajorGcSuspended" : "true",
+ "isMinorGcSuspended" : "true"
+
+ }
+ ```
+
+### Endpoint: /api/v1/bookie/gc/resume_compaction
+1. Method: PUT
+ * Description: resume the suspended compaction for this bookie.
+ * Body:
+ ```json
+ {
+ "resumeMajor": "true",
+ "resumeMinor": "true"
+ }
+ ```
+ * Response:
+
+ | Code | Description |
+ |:-------|:------------|
+ |200 | Successful operation |
+ |403 | Permission denied |
+ |404 | Not found |
### Endpoint: /api/v1/bookie/state
1. Method: GET