This is an automated email from the ASF dual-hosted git repository.
mivanac pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push:
new e4d2f16c5d GEODE-10419: Enhancment of backup disk-store command (#7851)
e4d2f16c5d is described below
commit e4d2f16c5dad27a96f39a4bec695572040bcedb7
Author: Mario Ivanac <[email protected]>
AuthorDate: Wed Sep 14 16:39:18 2022 +0200
GEODE-10419: Enhancment of backup disk-store command (#7851)
* GEODE-10419: initial commit
* GEODE-10419: documentation impacts
* GEODE-10419: added DT
---
.../DistributedSystemBridgeIntegrationTest.java | 4 +-
.../InternalConfigurationPersistenceService.java | 2 +-
.../internal/cache/backup/BackupConfigFactory.java | 10 +
.../internal/cache/backup/BackupOperation.java | 8 +
.../geode/internal/cache/backup/BackupService.java | 8 +-
.../geode/internal/cache/backup/BackupTask.java | 36 ++-
.../cache/backup/FileSystemBackupWriterConfig.java | 1 +
.../geode/internal/cache/backup/PrepareBackup.java | 8 +-
.../cache/backup/PrepareBackupFactory.java | 5 +-
.../geode/management/internal/i18n/CliStrings.java | 8 +
.../gfsh/command-pages/backup.html.md.erb | 10 +-
.../commands/BackupDiskStoreCommandDUnitTest.java | 273 +++++++++++++++++++++
.../cli/commands/BackupDiskStoreCommand.java | 40 ++-
13 files changed, 399 insertions(+), 14 deletions(-)
diff --git
a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemBridgeIntegrationTest.java
b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemBridgeIntegrationTest.java
index 9c184c843f..6f53fa411a 100644
---
a/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemBridgeIntegrationTest.java
+++
b/geode-core/src/integrationTest/java/org/apache/geode/management/internal/beans/DistributedSystemBridgeIntegrationTest.java
@@ -19,6 +19,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
@@ -68,7 +69,6 @@ public class DistributedSystemBridgeIntegrationTest {
backupService = mock(BackupService.class);
when(cache.getBackupService()).thenReturn(backupService);
when(cache.getPersistentMemberManager()).thenReturn(memberManager);
- when(cache.getBackupService()).thenReturn(backupService);
DLockService dlock = mock(DLockService.class);
when(dlock.lock(any(), anyLong(), anyLong())).thenReturn(true);
@@ -114,7 +114,7 @@ public class DistributedSystemBridgeIntegrationTest {
InOrder inOrder = inOrder(dm, backupService);
inOrder.verify(dm).putOutgoing(isA(PrepareBackupRequest.class));
- inOrder.verify(backupService).prepareBackup(any(), any());
+ inOrder.verify(backupService).prepareBackup(any(), any(), eq(null));
inOrder.verify(dm).putOutgoing(isA(FinishBackupRequest.class));
inOrder.verify(backupService).doBackup();
}
diff --git
a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
index f59591fe7f..11116d68af 100644
---
a/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
+++
b/geode-core/src/main/java/org/apache/geode/distributed/internal/InternalConfigurationPersistenceService.java
@@ -95,7 +95,7 @@ public class InternalConfigurationPersistenceService
implements ConfigurationPer
*/
public static final String CLUSTER_CONFIG_ARTIFACTS_DIR_NAME =
"cluster_config";
- private static final String CLUSTER_CONFIG_DISK_STORE_NAME =
"cluster_config";
+ public static final String CLUSTER_CONFIG_DISK_STORE_NAME = "cluster_config";
public static final String CLUSTER_CONFIG_DISK_DIR_PREFIX = "ConfigDiskDir_";
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupConfigFactory.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupConfigFactory.java
index e77f5ece96..f04d06d5ef 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupConfigFactory.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupConfigFactory.java
@@ -17,6 +17,7 @@ package org.apache.geode.internal.cache.backup;
import static
org.apache.geode.internal.cache.backup.AbstractBackupWriterConfig.TIMESTAMP;
import static
org.apache.geode.internal.cache.backup.AbstractBackupWriterConfig.TYPE;
import static
org.apache.geode.internal.cache.backup.FileSystemBackupWriterConfig.BASELINE_DIR;
+import static
org.apache.geode.internal.cache.backup.FileSystemBackupWriterConfig.INCLUDE_DISK_STORES;
import static
org.apache.geode.internal.cache.backup.FileSystemBackupWriterConfig.TARGET_DIR;
import java.text.SimpleDateFormat;
@@ -27,6 +28,7 @@ class BackupConfigFactory {
private String targetDirPath;
private String baselineDirPath;
+ private String includeDiskStores;
BackupConfigFactory() {
// nothing
@@ -42,6 +44,11 @@ class BackupConfigFactory {
return this;
}
+ BackupConfigFactory withIncludeDiskStores(String includeDiskStores) {
+ this.includeDiskStores = includeDiskStores;
+ return this;
+ }
+
Properties createBackupProperties() {
Properties properties = new Properties();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
@@ -51,6 +58,9 @@ class BackupConfigFactory {
if (baselineDirPath != null) {
properties.setProperty(BASELINE_DIR, baselineDirPath);
}
+ if (includeDiskStores != null) {
+ properties.setProperty(INCLUDE_DISK_STORES, includeDiskStores);
+ }
return properties;
}
}
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupOperation.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupOperation.java
index 3084c0ed69..29b10decac 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupOperation.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupOperation.java
@@ -71,6 +71,14 @@ public class BackupOperation {
return performBackup(properties);
}
+ public BackupStatus backupAllMembers(String targetDirPath, String
baselineDirPath,
+ String includeDiskStores) {
+ Properties properties = new
BackupConfigFactory().withTargetDirPath(targetDirPath)
+
.withBaselineDirPath(baselineDirPath).withIncludeDiskStores(includeDiskStores)
+ .createBackupProperties();
+ return performBackup(properties);
+ }
+
private BackupStatus performBackup(Properties properties) throws
ManagementException {
if (backupLockService.obtainLock(dm)) {
try {
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupService.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupService.java
index 8f0139dee3..d25143cb43 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupService.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupService.java
@@ -54,8 +54,14 @@ public class BackupService {
public HashSet<PersistentID> prepareBackup(InternalDistributedMember sender,
BackupWriter writer)
throws IOException, InterruptedException {
+ return prepareBackup(sender, writer, null);
+ }
+
+ public HashSet<PersistentID> prepareBackup(InternalDistributedMember sender,
BackupWriter writer,
+ String includeDiskStores)
+ throws IOException, InterruptedException {
validateRequestingSender(sender);
- BackupTask backupTask = new BackupTask(cache, writer);
+ BackupTask backupTask = new BackupTask(cache, writer, includeDiskStores);
if (!currentTask.compareAndSet(null, backupTask)) {
throw new IOException("Another backup is already in progress");
}
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupTask.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupTask.java
index 8124dee40d..6695f4ef2c 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupTask.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/BackupTask.java
@@ -14,13 +14,19 @@
*/
package org.apache.geode.internal.cache.backup;
+import static
org.apache.geode.distributed.internal.InternalConfigurationPersistenceService.CLUSTER_CONFIG_DISK_STORE_NAME;
+
import java.io.IOException;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
+import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.geode.InternalGemFireError;
@@ -37,7 +43,6 @@ import org.apache.geode.logging.internal.log4j.api.LogService;
*/
class BackupTask {
private static final Logger logger = LogService.getLogger();
-
private final Map<DiskStoreImpl, DiskStoreBackup> backupByDiskStore = new
HashMap<>();
private final RestoreScript restoreScript = new RestoreScript();
private final InternalCache cache;
@@ -46,15 +51,25 @@ class BackupTask {
private final CountDownLatch otherMembersReady = new CountDownLatch(1);
private final HashSet<PersistentID> diskStoresWithData = new HashSet<>();
private final BackupWriter backupWriter;
+ private final Set<String> includeDiskStoresSet = new HashSet<>();
private volatile boolean isCancelled;
private TemporaryBackupFiles temporaryFiles;
private BackupFileCopier fileCopier;
- BackupTask(InternalCache cache, BackupWriter backupWriter) {
+ BackupTask(InternalCache cache, BackupWriter backupWriter, String
includeDiskStores) {
this.cache = cache;
this.backupWriter = backupWriter;
+ if (includeDiskStores != null) {
+
this.includeDiskStoresSet.addAll(Arrays.stream(includeDiskStores.split(","))
+ .filter(StringUtils::isNotBlank)
+ .collect(Collectors.toSet()));
+ if (!this.includeDiskStoresSet.isEmpty()) {
+ // add internal disk-store for shared configuration data
+ this.includeDiskStoresSet.add(CLUSTER_CONFIG_DISK_STORE_NAME);
+ }
+ }
}
HashSet<PersistentID> getPreparedDiskStores() throws InterruptedException {
@@ -86,7 +101,9 @@ class BackupTask {
private void prepareForBackup() {
for (DiskStore store : cache.listDiskStoresIncludingRegionOwned()) {
DiskStoreImpl storeImpl = (DiskStoreImpl) store;
-
+ if (!isDiskStoreIncluded(store)) {
+ continue;
+ }
storeImpl.lockStoreBeforeBackup();
if (logger.isDebugEnabled()) {
logger.debug("Acquired lock for backup on disk store {}",
store.getName());
@@ -145,6 +162,9 @@ class BackupTask {
Map<DiskStoreImpl, DiskStoreBackup> backupByDiskStore = new HashMap<>();
for (DiskStore store : diskStores) {
+ if (!isDiskStoreIncluded(store)) {
+ continue;
+ }
DiskStoreImpl diskStore = (DiskStoreImpl) store;
try {
if (diskStore.hasPersistedData()) {
@@ -161,6 +181,16 @@ class BackupTask {
return backupByDiskStore;
}
+ boolean isDiskStoreIncluded(DiskStore store) {
+ if (includeDiskStoresSet.isEmpty()) {
+ return true;
+ }
+ if (includeDiskStoresSet.contains(store.getName())) {
+ return true;
+ }
+ return false;
+ }
+
void abort() {
isCancelled = true;
otherMembersReady.countDown();
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/FileSystemBackupWriterConfig.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/FileSystemBackupWriterConfig.java
index 02ef4b12b2..700fdfb996 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/FileSystemBackupWriterConfig.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/FileSystemBackupWriterConfig.java
@@ -22,6 +22,7 @@ class FileSystemBackupWriterConfig extends
AbstractBackupWriterConfig {
static final String TARGET_DIR = "TARGET_DIRECTORY";
static final String BASELINE_DIR = "BASELINE_DIRECTORY";
+ static final String INCLUDE_DISK_STORES = "INCLUDE_DISK_STORES";
FileSystemBackupWriterConfig(Properties properties) {
super(properties);
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackup.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackup.java
index 24e1b72800..0d11a4ae35 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackup.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackup.java
@@ -26,11 +26,14 @@ class PrepareBackup {
private final InternalDistributedMember member;
private final InternalCache cache;
private final BackupWriter backupWriter;
+ private final String includeDiskStores;
- PrepareBackup(InternalDistributedMember member, InternalCache cache,
BackupWriter backupWriter) {
+ PrepareBackup(InternalDistributedMember member, InternalCache cache,
BackupWriter backupWriter,
+ String includeDiskStores) {
this.member = member;
this.cache = cache;
this.backupWriter = backupWriter;
+ this.includeDiskStores = includeDiskStores;
}
HashSet<PersistentID> run() throws IOException, InterruptedException {
@@ -38,7 +41,8 @@ class PrepareBackup {
if (cache == null) {
persistentIds = new HashSet<>();
} else {
- persistentIds = cache.getBackupService().prepareBackup(member,
backupWriter);
+ persistentIds =
+ cache.getBackupService().prepareBackup(member, backupWriter,
includeDiskStores);
}
return persistentIds;
}
diff --git
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackupFactory.java
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackupFactory.java
index 757aebcf51..b79abaa607 100644
---
a/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackupFactory.java
+++
b/geode-core/src/main/java/org/apache/geode/internal/cache/backup/PrepareBackupFactory.java
@@ -15,6 +15,7 @@
package org.apache.geode.internal.cache.backup;
import static
org.apache.geode.internal.cache.backup.AbstractBackupWriterConfig.TYPE;
+import static
org.apache.geode.internal.cache.backup.FileSystemBackupWriterConfig.INCLUDE_DISK_STORES;
import java.util.HashSet;
import java.util.Properties;
@@ -42,7 +43,9 @@ class PrepareBackupFactory {
String memberId = cleanSpecialCharacters(member.toString());
BackupWriter backupWriter =
BackupWriterFactory.getFactoryForType(properties.getProperty(TYPE))
.createWriter(properties, memberId);
- return new PrepareBackup(member, cache, backupWriter);
+
+ String includeDiskStores = properties.getProperty(INCLUDE_DISK_STORES);
+ return new PrepareBackup(member, cache, backupWriter, includeDiskStores);
}
BackupResponse createBackupResponse(InternalDistributedMember sender,
diff --git
a/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java
b/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java
index 26d5ed7da2..f533c77960 100644
---
a/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java
+++
b/geode-core/src/main/java/org/apache/geode/management/internal/i18n/CliStrings.java
@@ -531,6 +531,14 @@ public class CliStrings {
public static final String BACKUP_DISK_STORE_MSG_NO_DISKSTORES_BACKED_UP =
"No disk store(s) were backed up.";
+ public static final String BACKUP_INCLUDE_DISK_STORES =
"include-disk-stores";
+ public static final String BACKUP_INCLUDE_DISK_STORES__HELP = "List of
disk-stores to include.";
+ public static final String
BACKUP_DISK_STORE__MSG__SPECIFY_VALID_INCLUDE_DISKSTORE_UNKNOWN_DISKSTORE_0 =
+ "Specify valid include-disk-stores. Unknown Disk Store : \"{0}\".";
+
+ public static final String
BACKUP_DISK_STORE__MSG__SPECIFY_VALID_INCLUDE_DISKSTORE_UNKNOWN_DISKSTORE_1 =
+ "Specify valid include-disk-stores. Blank name added in list of
disk-stores";
+
/* 'compact disk-store' command */
public static final String COMPACT_DISK_STORE = "compact disk-store";
public static final String COMPACT_DISK_STORE__HELP =
diff --git a/geode-docs/tools_modules/gfsh/command-pages/backup.html.md.erb
b/geode-docs/tools_modules/gfsh/command-pages/backup.html.md.erb
index d3832a842d..8c1b099499 100644
--- a/geode-docs/tools_modules/gfsh/command-pages/backup.html.md.erb
+++ b/geode-docs/tools_modules/gfsh/command-pages/backup.html.md.erb
@@ -32,7 +32,7 @@ You can also use this command to perform an incremental
backup. See [Creating Ba
**Syntax:**
``` pre
-backup disk-store --dir=value [--baseline-dir=value]
+backup disk-store --dir=value [--baseline-dir=value]
[--include-disk-stores=value(,value)*]
```
<a
id="topic_E74ED23CB60342538B2175C326E7D758__table_2277A2CE8F6E4731B45FEFA2B1366DB6"></a>
@@ -59,6 +59,11 @@ backup disk-store --dir=value [--baseline-dir=value]
<td>Directory that contains the baseline backup used for comparison during an
incremental backup.
<p>An incremental backup operation backs up any data that is not present in
the directory specified in <span class="keyword
parmname">‑‑baseline-dir</span>. If the member cannot find
previously backed up data or if the previously backed up data is corrupt, the
command performs a full backup on that member.</p></td>
</tr>
+<tr>
+<td><span class="keyword
parmname">‑‑include-disk-stores</span></td>
+<td>List of disk-stores to include in backup.
+<p>Selective backup of disk-stores listed in <span class="keyword
parmname">‑‑include-disk-stores</span>. The specified disk-stores
must exist in the system. If this parameter is not specified, all disk-stores
are included in the backup.</p></td>
+</tr>
</tbody>
</table>
@@ -70,6 +75,9 @@ backup disk-store --dir=value [--baseline-dir=value]
backup disk-store --dir=data/backups
backup disk-store --dir=data/backup/disk-store
--baselineDir=data/backups/2012-09-24-17-08-50
+
+backup disk-store --dir=data/backups --include-disk-stores=data
+
```
**Sample Output:**
diff --git
a/geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommandDUnitTest.java
b/geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommandDUnitTest.java
new file mode 100644
index 0000000000..3bbeac66ec
--- /dev/null
+++
b/geode-gfsh/src/distributedTest/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommandDUnitTest.java
@@ -0,0 +1,273 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+
+import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.RegionShortcut;
+import org.apache.geode.management.internal.cli.result.model.ResultModel;
+import
org.apache.geode.management.internal.cli.result.model.TabularResultModel;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.apache.geode.management.internal.i18n.CliStrings;
+import org.apache.geode.test.dunit.rules.ClusterStartupRule;
+import org.apache.geode.test.dunit.rules.MemberVM;
+import org.apache.geode.test.junit.categories.PersistenceTest;
+import org.apache.geode.test.junit.rules.GfshCommandRule;
+
+@Category({PersistenceTest.class})
+public class BackupDiskStoreCommandDUnitTest {
+
+ private MemberVM locator;
+
+ @Rule
+ public TestName testName = new TestName();
+
+ @Rule
+ public ClusterStartupRule lsRule = new ClusterStartupRule();
+
+ @Rule
+ public GfshCommandRule gfshConnector = new GfshCommandRule();
+
+ @Before
+ public void before() throws Exception {
+ locator = lsRule.startLocatorVM(0);
+ gfshConnector.connect(locator);
+ assertThat(gfshConnector.isConnected()).isTrue();
+
+ // start a server so that we can execute data commands that requires at
least a server running
+ }
+
+ @Test
+ public void backupDiskStoresOfOneDiskStore() {
+ MemberVM server1 = lsRule.startServerVM(1, locator.getPort());
+ @SuppressWarnings("unused")
+ MemberVM server2 = lsRule.startServerVM(2, locator.getPort());
+ @SuppressWarnings("unused")
+
+ final String testRegionName = "regionA";
+ CommandStringBuilder csb;
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion.getCommandString())
+ .statusIsSuccess());
+
+ // Add data to the region
+ addData(server1, testRegionName);
+
+ csb = new CommandStringBuilder(CliStrings.BACKUP_DISK_STORE)
+ .addOption(CliStrings.BACKUP_DISK_STORE__DISKDIRS, "backupDir");
+
+ @SuppressWarnings("deprecation")
+ ResultModel result =
+ gfshConnector.executeCommand(csb.getCommandString()).getResultData();
+ TabularResultModel tableSection =
result.getTableSection("backed-up-diskstores");
+ List<String> list = tableSection.getValuesInColumn("UUID");
+ assertThat(list).hasSize(3);
+ }
+
+ @Test
+ public void backupDiskStoresTwoDiskStores() {
+ MemberVM server1 = lsRule.startServerVM(1, locator.getPort());
+ @SuppressWarnings("unused")
+ MemberVM server2 = lsRule.startServerVM(2, locator.getPort());
+ @SuppressWarnings("unused")
+
+ final String testRegionName = "regionA";
+ final String testRegionName2 = "regionB";
+
+ CommandStringBuilder csb;
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion.getCommandString())
+ .statusIsSuccess());
+
+
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore2")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir2");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion2 = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName2)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore2")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion2.getCommandString())
+ .statusIsSuccess());
+
+ // Add data to the region
+ addData(server1, testRegionName);
+ addData(server2, testRegionName2);
+
+ csb = new CommandStringBuilder(CliStrings.BACKUP_DISK_STORE)
+ .addOption(CliStrings.BACKUP_DISK_STORE__DISKDIRS, "backupDir");
+
+ @SuppressWarnings("deprecation")
+ ResultModel result =
+ gfshConnector.executeCommand(csb.getCommandString()).getResultData();
+ TabularResultModel tableSection =
result.getTableSection("backed-up-diskstores");
+ List<String> list = tableSection.getValuesInColumn("UUID");
+ assertThat(list).hasSize(5);
+ }
+
+ @Test
+ public void backupDiskStoresTwoDiskStoresIncludeJustOne() {
+ MemberVM server1 = lsRule.startServerVM(1, locator.getPort());
+ @SuppressWarnings("unused")
+ MemberVM server2 = lsRule.startServerVM(2, locator.getPort());
+ @SuppressWarnings("unused")
+
+ final String testRegionName = "regionA";
+ final String testRegionName2 = "regionB";
+
+ CommandStringBuilder csb;
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion.getCommandString())
+ .statusIsSuccess());
+
+
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore2")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir2");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion2 = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName2)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore2")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion2.getCommandString())
+ .statusIsSuccess());
+
+ // Add data to the region
+ addData(server1, testRegionName);
+ addData(server2, testRegionName2);
+
+ csb = new CommandStringBuilder(CliStrings.BACKUP_DISK_STORE)
+ .addOption(CliStrings.BACKUP_DISK_STORE__DISKDIRS, "backupDir")
+ .addOption(CliStrings.BACKUP_INCLUDE_DISK_STORES, "diskStore");
+
+ @SuppressWarnings("deprecation")
+ ResultModel result =
+ gfshConnector.executeCommand(csb.getCommandString()).getResultData();
+ TabularResultModel tableSection =
result.getTableSection("backed-up-diskstores");
+ List<String> list = tableSection.getValuesInColumn("UUID");
+ assertThat(list).hasSize(3);
+ }
+
+ @Test
+ public void backupDiskStoresInvalidIncludeDiskStores() {
+ MemberVM server1 = lsRule.startServerVM(1, locator.getPort());
+ @SuppressWarnings("unused")
+ MemberVM server2 = lsRule.startServerVM(2, locator.getPort());
+ @SuppressWarnings("unused")
+
+ final String testRegionName = "regionA";
+ final String testRegionName2 = "regionB";
+
+ CommandStringBuilder csb;
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion.getCommandString())
+ .statusIsSuccess());
+
+
+ csb = new CommandStringBuilder(CliStrings.CREATE_DISK_STORE)
+ .addOption(CliStrings.CREATE_DISK_STORE__NAME, "diskStore2")
+ .addOption(CliStrings.CREATE_DISK_STORE__DIRECTORY_AND_SIZE,
"diskStoreDir2");
+
gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsSuccess();
+
+ CommandStringBuilder createRegion2 = new
CommandStringBuilder(CliStrings.CREATE_REGION)
+ .addOption(CliStrings.CREATE_REGION__REGION, testRegionName2)
+ .addOption(CliStrings.CREATE_REGION__DISKSTORE, "diskStore2")
+ .addOption(CliStrings.CREATE_REGION__REGIONSHORTCUT,
+ RegionShortcut.PARTITION_PERSISTENT.toString());
+ await().untilAsserted(() ->
gfshConnector.executeAndAssertThat(createRegion2.getCommandString())
+ .statusIsSuccess());
+
+ // Add data to the region
+ addData(server1, testRegionName);
+ addData(server2, testRegionName2);
+
+ csb = new CommandStringBuilder(CliStrings.BACKUP_DISK_STORE)
+ .addOption(CliStrings.BACKUP_DISK_STORE__DISKDIRS, "backupDir")
+ .addOption(CliStrings.BACKUP_INCLUDE_DISK_STORES, "diskStore3");
+
+ gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsError()
+ .containsOutput("Specify valid include-disk-stores.");
+
+ csb = new CommandStringBuilder(CliStrings.BACKUP_DISK_STORE)
+ .addOption(CliStrings.BACKUP_DISK_STORE__DISKDIRS, "backupDir")
+ .addOption(CliStrings.BACKUP_INCLUDE_DISK_STORES,
"diskStore,diskStore4");
+
+ gfshConnector.executeAndAssertThat(csb.getCommandString()).statusIsError()
+ .containsOutput("Specify valid include-disk-stores.");
+ }
+
+ private void addData(MemberVM server1, String testRegionName) {
+ server1.invoke(() -> {
+ Region<Object, Object> region =
CacheFactory.getAnyInstance().getRegion(testRegionName);
+ for (int i = 0; i < 113; i++) {
+ region.put(i, "A");
+ }
+ });
+ }
+}
diff --git
a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommand.java
b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommand.java
index 3153d78d3a..a4850b0063 100644
---
a/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommand.java
+++
b/geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/commands/BackupDiskStoreCommand.java
@@ -15,9 +15,11 @@
package org.apache.geode.management.internal.cli.commands;
+import java.util.Arrays;
import java.util.Map;
import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.shell.core.annotation.CliCommand;
import org.springframework.shell.core.annotation.CliOption;
@@ -27,6 +29,8 @@ import
org.apache.geode.distributed.internal.DistributionManager;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.backup.BackupOperation;
import org.apache.geode.management.BackupStatus;
+import org.apache.geode.management.DistributedSystemMXBean;
+import org.apache.geode.management.ManagementService;
import org.apache.geode.management.cli.CliMetaData;
import org.apache.geode.management.cli.GfshCommand;
import org.apache.geode.management.internal.cli.result.model.ResultModel;
@@ -51,7 +55,9 @@ public class BackupDiskStoreCommand extends GfshCommand {
@CliOption(key = CliStrings.BACKUP_DISK_STORE__DISKDIRS,
help = CliStrings.BACKUP_DISK_STORE__DISKDIRS__HELP, mandatory =
true) String targetDir,
@CliOption(key = CliStrings.BACKUP_DISK_STORE__BASELINEDIR,
- help = CliStrings.BACKUP_DISK_STORE__BASELINEDIR__HELP) String
baselineDir) {
+ help = CliStrings.BACKUP_DISK_STORE__BASELINEDIR__HELP) String
baselineDir,
+ @CliOption(key = CliStrings.BACKUP_INCLUDE_DISK_STORES,
+ help = CliStrings.BACKUP_INCLUDE_DISK_STORES__HELP) String[]
includeDiskStores) {
authorize(ResourcePermission.Resource.CLUSTER,
ResourcePermission.Operation.WRITE,
ResourcePermission.Target.DISK);
@@ -62,11 +68,30 @@ public class BackupDiskStoreCommand extends GfshCommand {
DistributionManager dm = cache.getDistributionManager();
BackupStatus backupStatus;
+ String includeDiskStoresString = null;
+ if (includeDiskStores != null && includeDiskStores.length > 0) {
+ for (String name : includeDiskStores) {
+ if (name != null && !name.isEmpty()) {
+ if (!diskStoreExists(name)) {
+ return ResultModel.createError(CliStrings.format(
+
CliStrings.BACKUP_DISK_STORE__MSG__SPECIFY_VALID_INCLUDE_DISKSTORE_UNKNOWN_DISKSTORE_0,
+ new Object[] {name}));
+ }
+ } else {
+ return ResultModel.createError(CliStrings.format(
+
CliStrings.BACKUP_DISK_STORE__MSG__SPECIFY_VALID_INCLUDE_DISKSTORE_UNKNOWN_DISKSTORE_1));
+ }
+ }
+ includeDiskStoresString = StringUtils.join(includeDiskStores, ",");
+ }
+
if (baselineDir != null && !baselineDir.isEmpty()) {
backupStatus =
- new BackupOperation(dm, dm.getCache()).backupAllMembers(targetDir,
baselineDir);
+ new BackupOperation(dm, dm.getCache()).backupAllMembers(targetDir,
baselineDir,
+ includeDiskStoresString);
} else {
- backupStatus = new BackupOperation(dm,
dm.getCache()).backupAllMembers(targetDir, null);
+ backupStatus = new BackupOperation(dm,
dm.getCache()).backupAllMembers(targetDir, null,
+ includeDiskStoresString);
}
Map<DistributedMember, Set<PersistentID>> backedupMemberDiskstoreMap =
@@ -136,4 +161,13 @@ public class BackupDiskStoreCommand extends GfshCommand {
table.accumulate(CliStrings.BACKUP_DISK_STORE_MSG_DIRECTORY, directory);
table.accumulate(CliStrings.BACKUP_DISK_STORE_MSG_HOST, host);
}
+
+ private boolean diskStoreExists(String diskStoreName) {
+ ManagementService managementService = getManagementService();
+ DistributedSystemMXBean dsMXBean =
managementService.getDistributedSystemMXBean();
+
+ return Arrays.stream(dsMXBean.listMembers()).anyMatch(
+ member ->
DiskStoreCommandsUtils.diskStoreBeanAndMemberBeanDiskStoreExists(dsMXBean,
member,
+ diskStoreName));
+ }
}