Skip to content

Commit 4187f4b

Browse files
HubSpot Backport: HBASE-28568 Incremental backup set does not correctly shrink (apache#5876) (#97)
* HubSpot Backport: HBASE-28568 Incremental backup set does not correctly shrink (apache#5876) The incremental backup set is the set of tables included when an incremental backup is created, it is managed per backup root dir and contains all tables that are present in at least one backup (in that root dir). The incremental backup set can only shrink when backups are deleted. However, the implementation was incorrect, causing this set to never be able to shrink. Reviewed-by: Ray Mattingly <rmdmattingly@gmail.com> Signed-off-by: Nick Dimiduk <ndimiduk@apache.org> * HubSpot Backport: HBASE-28568 Incremental backup set does not correctly shrink (addendum) (apache#5917) Import the correct shaded Guava and run spotless:apply. Signed-off-by: Duo Zhang <zhangduo@apache.org> --------- Signed-off-by: Nick Dimiduk <ndimiduk@apache.org> Signed-off-by: Duo Zhang <zhangduo@apache.org> Co-authored-by: DieterDP <90392398+DieterDP-ng@users.noreply.github.com>
1 parent a6eaaff commit 4187f4b

3 files changed

Lines changed: 58 additions & 39 deletions

File tree

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/impl/BackupAdminImpl.java

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import java.util.ArrayList;
2222
import java.util.Arrays;
2323
import java.util.Collections;
24-
import java.util.HashMap;
2524
import java.util.HashSet;
2625
import java.util.List;
2726
import java.util.Map;
@@ -94,7 +93,6 @@ public BackupInfo getBackupInfo(String backupId) throws IOException {
9493
public int deleteBackups(String[] backupIds) throws IOException {
9594

9695
int totalDeleted = 0;
97-
Map<String, HashSet<TableName>> allTablesMap = new HashMap<>();
9896

9997
boolean deleteSessionStarted;
10098
boolean snapshotDone;
@@ -130,20 +128,16 @@ public int deleteBackups(String[] backupIds) throws IOException {
130128
}
131129
snapshotDone = true;
132130
try {
131+
List<String> affectedBackupRootDirs = new ArrayList<>();
133132
for (int i = 0; i < backupIds.length; i++) {
134133
BackupInfo info = sysTable.readBackupInfo(backupIds[i]);
135-
if (info != null) {
136-
String rootDir = info.getBackupRootDir();
137-
HashSet<TableName> allTables = allTablesMap.get(rootDir);
138-
if (allTables == null) {
139-
allTables = new HashSet<>();
140-
allTablesMap.put(rootDir, allTables);
141-
}
142-
allTables.addAll(info.getTableNames());
143-
totalDeleted += deleteBackup(backupIds[i], sysTable);
134+
if (info == null) {
135+
continue;
144136
}
137+
affectedBackupRootDirs.add(info.getBackupRootDir());
138+
totalDeleted += deleteBackup(backupIds[i], sysTable);
145139
}
146-
finalizeDelete(allTablesMap, sysTable);
140+
finalizeDelete(affectedBackupRootDirs, sysTable);
147141
// Finish
148142
sysTable.finishDeleteOperation();
149143
// delete snapshot
@@ -176,26 +170,23 @@ public int deleteBackups(String[] backupIds) throws IOException {
176170

177171
/**
178172
* Updates incremental backup set for every backupRoot
179-
* @param tablesMap map [backupRoot: {@code Set<TableName>}]
180-
* @param table backup system table
173+
* @param backupRoots backupRoots for which to revise the incremental backup set
174+
* @param table backup system table
181175
* @throws IOException if a table operation fails
182176
*/
183-
private void finalizeDelete(Map<String, HashSet<TableName>> tablesMap, BackupSystemTable table)
177+
private void finalizeDelete(List<String> backupRoots, BackupSystemTable table)
184178
throws IOException {
185-
for (String backupRoot : tablesMap.keySet()) {
179+
for (String backupRoot : backupRoots) {
186180
Set<TableName> incrTableSet = table.getIncrementalBackupTableSet(backupRoot);
187-
Map<TableName, ArrayList<BackupInfo>> tableMap =
181+
Map<TableName, List<BackupInfo>> tableMap =
188182
table.getBackupHistoryForTableSet(incrTableSet, backupRoot);
189-
for (Map.Entry<TableName, ArrayList<BackupInfo>> entry : tableMap.entrySet()) {
190-
if (entry.getValue() == null) {
191-
// No more backups for a table
192-
incrTableSet.remove(entry.getKey());
193-
}
194-
}
183+
184+
// Keep only the tables that are present in other backups
185+
incrTableSet.retainAll(tableMap.keySet());
186+
187+
table.deleteIncrementalBackupTableSet(backupRoot);
195188
if (!incrTableSet.isEmpty()) {
196189
table.addIncrementalBackupTableSet(incrTableSet, backupRoot);
197-
} else { // empty
198-
table.deleteIncrementalBackupTableSet(backupRoot);
199190
}
200191
}
201192
}

hbase-backup/src/main/java/org/apache/hadoop/hbase/backup/impl/BackupSystemTable.java

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@
8787
* <ul>
8888
* <li>1. Backup sessions rowkey= "session:"+backupId; value =serialized BackupInfo</li>
8989
* <li>2. Backup start code rowkey = "startcode:"+backupRoot; value = startcode</li>
90-
* <li>3. Incremental backup set rowkey="incrbackupset:"+backupRoot; value=[list of tables]</li>
91-
* <li>4. Table-RS-timestamp map rowkey="trslm:"+backupRoot+table_name; value = map[RS-%3E last WAL
90+
* <li>3. Incremental backup set rowkey="incrbackupset:"+backupRoot; table="meta:"+tablename of
91+
* include table; value=empty</li>
92+
* <li>4. Table-RS-timestamp map rowkey="trslm:"+backupRoot+table_name; value = map[RS-> last WAL
9293
* timestamp]</li>
9394
* <li>5. RS - WAL ts map rowkey="rslogts:"+backupRoot +server; value = last WAL timestamp</li>
9495
* <li>6. WALs recorded rowkey="wals:"+WAL unique file name; value = backupId and full WAL file
@@ -842,23 +843,25 @@ public List<BackupInfo> getBackupHistoryForTable(TableName name) throws IOExcept
842843
return tableHistory;
843844
}
844845

845-
public Map<TableName, ArrayList<BackupInfo>> getBackupHistoryForTableSet(Set<TableName> set,
846+
/**
847+
* Goes through all backup history corresponding to the provided root folder, and collects all
848+
* backup info mentioning each of the provided tables.
849+
* @param set the tables for which to collect the {@code BackupInfo}
850+
* @param backupRoot backup destination path to retrieve backup history for
851+
* @return a map containing (a subset of) the provided {@code TableName}s, mapped to a list of at
852+
* least one {@code BackupInfo}
853+
* @throws IOException if getting the backup history fails
854+
*/
855+
public Map<TableName, List<BackupInfo>> getBackupHistoryForTableSet(Set<TableName> set,
846856
String backupRoot) throws IOException {
847857
List<BackupInfo> history = getBackupHistory(backupRoot);
848-
Map<TableName, ArrayList<BackupInfo>> tableHistoryMap = new HashMap<>();
849-
for (Iterator<BackupInfo> iterator = history.iterator(); iterator.hasNext();) {
850-
BackupInfo info = iterator.next();
851-
if (!backupRoot.equals(info.getBackupRootDir())) {
852-
continue;
853-
}
858+
Map<TableName, List<BackupInfo>> tableHistoryMap = new HashMap<>();
859+
for (BackupInfo info : history) {
854860
List<TableName> tables = info.getTableNames();
855861
for (TableName tableName : tables) {
856862
if (set.contains(tableName)) {
857-
ArrayList<BackupInfo> list = tableHistoryMap.get(tableName);
858-
if (list == null) {
859-
list = new ArrayList<>();
860-
tableHistoryMap.put(tableName, list);
861-
}
863+
List<BackupInfo> list =
864+
tableHistoryMap.computeIfAbsent(tableName, k -> new ArrayList<>());
862865
list.add(info);
863866
}
864867
}

hbase-backup/src/test/java/org/apache/hadoop/hbase/backup/TestBackupDelete.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.hadoop.hbase.backup;
1919

20+
import static org.junit.Assert.assertEquals;
2021
import static org.junit.Assert.assertTrue;
2122

2223
import java.io.ByteArrayOutputStream;
@@ -39,6 +40,7 @@
3940
import org.slf4j.LoggerFactory;
4041

4142
import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
43+
import org.apache.hbase.thirdparty.com.google.common.collect.Sets;
4244

4345
@Category(LargeTests.class)
4446
public class TestBackupDelete extends TestBackupBase {
@@ -158,4 +160,27 @@ public long currentTime() {
158160
LOG.info(baos.toString());
159161
assertTrue(output.indexOf("Deleted 1 backups") >= 0);
160162
}
163+
164+
/**
165+
* Verify that backup deletion updates the incremental-backup-set.
166+
*/
167+
@Test
168+
public void testBackupDeleteUpdatesIncrementalBackupSet() throws Exception {
169+
LOG.info("Test backup delete updates the incremental backup set");
170+
BackupSystemTable backupSystemTable = new BackupSystemTable(TEST_UTIL.getConnection());
171+
172+
String backupId1 = fullTableBackup(Lists.newArrayList(table1, table2));
173+
assertTrue(checkSucceeded(backupId1));
174+
assertEquals(Sets.newHashSet(table1, table2),
175+
backupSystemTable.getIncrementalBackupTableSet(BACKUP_ROOT_DIR));
176+
177+
String backupId2 = fullTableBackup(Lists.newArrayList(table3));
178+
assertTrue(checkSucceeded(backupId2));
179+
assertEquals(Sets.newHashSet(table1, table2, table3),
180+
backupSystemTable.getIncrementalBackupTableSet(BACKUP_ROOT_DIR));
181+
182+
getBackupAdmin().deleteBackups(new String[] { backupId1 });
183+
assertEquals(Sets.newHashSet(table3),
184+
backupSystemTable.getIncrementalBackupTableSet(BACKUP_ROOT_DIR));
185+
}
161186
}

0 commit comments

Comments
 (0)