-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reveal hook to allow operators to restore just to the most recent snapshot #1035
Changes from all commits
3a98c85
352359b
a8e54b3
1000b86
fad61c8
15535f2
9c3baf0
e3e371e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,17 +30,13 @@ | |
import javax.inject.Provider; | ||
import org.apache.commons.io.FileUtils; | ||
import org.apache.commons.lang3.StringUtils; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** Created by aagrawal on 8/14/17. */ | ||
/** Helper methods applicable to both backup and restore */ | ||
public class BackupRestoreUtil { | ||
private static final Logger logger = LoggerFactory.getLogger(BackupRestoreUtil.class); | ||
private static final Pattern columnFamilyFilterPattern = Pattern.compile(".\\.."); | ||
private Map<String, List<String>> includeFilter; | ||
private Map<String, List<String>> excludeFilter; | ||
private final Map<String, List<String>> includeFilter; | ||
private final Map<String, List<String>> excludeFilter; | ||
|
||
public static final List<String> FILTER_KEYSPACE = Collections.singletonList("OpsCenter"); | ||
private static final Map<String, List<String>> FILTER_COLUMN_FAMILY = | ||
ImmutableMap.of( | ||
"system", | ||
|
@@ -49,43 +45,26 @@ public class BackupRestoreUtil { | |
|
||
@Inject | ||
public BackupRestoreUtil(String configIncludeFilter, String configExcludeFilter) { | ||
setFilters(configIncludeFilter, configExcludeFilter); | ||
} | ||
|
||
public BackupRestoreUtil setFilters(String configIncludeFilter, String configExcludeFilter) { | ||
includeFilter = getFilter(configIncludeFilter); | ||
excludeFilter = getFilter(configExcludeFilter); | ||
logger.info("Exclude filter set: {}", configExcludeFilter); | ||
logger.info("Include filter set: {}", configIncludeFilter); | ||
return this; | ||
} | ||
|
||
public static Optional<AbstractBackupPath> getLatestValidMetaPath( | ||
IMetaProxy metaProxy, DateUtil.DateRange dateRange) { | ||
// Get a list of manifest files. | ||
List<AbstractBackupPath> metas = metaProxy.findMetaFiles(dateRange); | ||
|
||
// Find a valid manifest file. | ||
for (AbstractBackupPath meta : metas) { | ||
BackupVerificationResult result = metaProxy.isMetaFileValid(meta); | ||
if (result.valid) { | ||
return Optional.of(meta); | ||
} | ||
} | ||
|
||
return Optional.empty(); | ||
return metaProxy | ||
.findMetaFiles(dateRange) | ||
.stream() | ||
.filter(meta -> metaProxy.isMetaFileValid(meta).valid) | ||
.findFirst(); | ||
} | ||
|
||
public static List<AbstractBackupPath> getAllFiles( | ||
public static List<AbstractBackupPath> getMostRecentSnapshotPaths( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. renaming the method was a great idea, makes it more precise (now that it's different) and also makes it impossible to forget to update a callsite |
||
AbstractBackupPath latestValidMetaFile, | ||
DateUtil.DateRange dateRange, | ||
IMetaProxy metaProxy, | ||
Provider<AbstractBackupPath> pathProvider) | ||
throws Exception { | ||
// Download the meta.json file. | ||
Path metaFile = metaProxy.downloadMetaFile(latestValidMetaFile); | ||
// Parse meta.json file to find the files required to download from this snapshot. | ||
List<AbstractBackupPath> allFiles = | ||
List<AbstractBackupPath> snapshotPaths = | ||
metaProxy | ||
.getSSTFilesFromMeta(metaFile) | ||
.stream() | ||
|
@@ -96,50 +75,43 @@ public static List<AbstractBackupPath> getAllFiles( | |
return path; | ||
}) | ||
.collect(Collectors.toList()); | ||
|
||
FileUtils.deleteQuietly(metaFile.toFile()); | ||
return snapshotPaths; | ||
} | ||
|
||
// Download incremental SSTables after the snapshot meta file. | ||
public static List<AbstractBackupPath> getIncrementalPaths( | ||
AbstractBackupPath latestValidMetaFile, | ||
DateUtil.DateRange dateRange, | ||
IMetaProxy metaProxy) { | ||
Instant snapshotTime; | ||
if (metaProxy instanceof MetaV2Proxy) snapshotTime = latestValidMetaFile.getLastModified(); | ||
else snapshotTime = latestValidMetaFile.getTime().toInstant(); | ||
|
||
DateUtil.DateRange incrementalDateRange = | ||
new DateUtil.DateRange(snapshotTime, dateRange.getEndTime()); | ||
Iterator<AbstractBackupPath> incremental = metaProxy.getIncrementals(incrementalDateRange); | ||
while (incremental.hasNext()) allFiles.add(incremental.next()); | ||
|
||
return allFiles; | ||
List<AbstractBackupPath> incrementalPaths = new ArrayList<>(); | ||
metaProxy.getIncrementals(incrementalDateRange).forEachRemaining(incrementalPaths::add); | ||
return incrementalPaths; | ||
} | ||
|
||
public static final Map<String, List<String>> getFilter(String inputFilter) | ||
public static Map<String, List<String>> getFilter(String inputFilter) | ||
throws IllegalArgumentException { | ||
if (StringUtils.isEmpty(inputFilter)) return null; | ||
|
||
final Map<String, List<String>> columnFamilyFilter = | ||
new HashMap<>(); // key: keyspace, value: a list of CFs within the keyspace | ||
|
||
final Map<String, List<String>> columnFamilyFilter = new HashMap<>(); | ||
String[] filters = inputFilter.split(","); | ||
for (String cfFilter : | ||
filters) { // process filter of form keyspace.* or keyspace.columnfamily | ||
for (String cfFilter : filters) { | ||
if (columnFamilyFilterPattern.matcher(cfFilter).find()) { | ||
|
||
String[] filter = cfFilter.split("\\."); | ||
String keyspaceName = filter[0]; | ||
String columnFamilyName = filter[1]; | ||
|
||
if (columnFamilyName.contains("-")) | ||
columnFamilyName = columnFamilyName.substring(0, columnFamilyName.indexOf("-")); | ||
|
||
List<String> existingCfs = | ||
columnFamilyFilter.getOrDefault(keyspaceName, new ArrayList<>()); | ||
if (!columnFamilyName.equalsIgnoreCase("*")) existingCfs.add(columnFamilyName); | ||
columnFamilyFilter.put(keyspaceName, existingCfs); | ||
|
||
} else { | ||
throw new IllegalArgumentException( | ||
"Column family filter format is not valid. Format needs to be \"keyspace.columnfamily\". Invalid input: " | ||
+ cfFilter); | ||
"Invalid format: " + cfFilter + ". \"keyspace.columnfamily\" is required."); | ||
} | ||
} | ||
return columnFamilyFilter; | ||
|
@@ -154,34 +126,19 @@ public static final Map<String, List<String>> getFilter(String inputFilter) | |
*/ | ||
public final boolean isFiltered(String keyspace, String columnFamilyDir) { | ||
if (StringUtils.isEmpty(keyspace) || StringUtils.isEmpty(columnFamilyDir)) return false; | ||
|
||
String columnFamilyName = columnFamilyDir.split("-")[0]; | ||
// column family is in list of global CF filter | ||
if (FILTER_COLUMN_FAMILY.containsKey(keyspace) | ||
&& FILTER_COLUMN_FAMILY.get(keyspace).contains(columnFamilyName)) return true; | ||
|
||
if (excludeFilter != null) | ||
if (excludeFilter.containsKey(keyspace) | ||
&& (excludeFilter.get(keyspace).isEmpty() | ||
|| excludeFilter.get(keyspace).contains(columnFamilyName))) { | ||
logger.debug( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I suppose it's fine and you have a better understanding around whether or not we ever need those log messages but in general I'm not opposed to debug logs that I can enable to help debug an issue |
||
"Skipping: keyspace: {}, CF: {} is part of exclude list.", | ||
keyspace, | ||
columnFamilyName); | ||
return true; | ||
} | ||
|
||
if (includeFilter != null) | ||
if (!(includeFilter.containsKey(keyspace) | ||
return !(includeFilter.containsKey(keyspace) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor nit: could collapse this further, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is a good point. However, I wanted to leave code in methods unrelated to the goal of the PR unchanged. I accepted this because it was done automatically by Intellij. If I change this I'd need to add the appropriate tests and I think that is beyond scope and best left to a follow-up. |
||
&& (includeFilter.get(keyspace).isEmpty() | ||
|| includeFilter.get(keyspace).contains(columnFamilyName)))) { | ||
logger.debug( | ||
"Skipping: keyspace: {}, CF: {} is not part of include list.", | ||
keyspace, | ||
columnFamilyName); | ||
return true; | ||
} | ||
|
||
|| includeFilter.get(keyspace).contains(columnFamilyName))); | ||
return false; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,10 +114,6 @@ public static final boolean isRestoreEnabled(IConfiguration conf, InstanceInfo i | |
return (isRestoreMode && isBackedupRac); | ||
} | ||
|
||
public void setRestoreConfiguration(String restoreIncludeCFList, String restoreExcludeCFList) { | ||
backupRestoreUtil.setFilters(restoreIncludeCFList, restoreExcludeCFList); | ||
} | ||
|
||
private List<Future<Path>> download( | ||
Iterator<AbstractBackupPath> fsIterator, boolean waitForCompletion) throws Exception { | ||
List<Future<Path>> futureList = new ArrayList<>(); | ||
|
@@ -247,8 +243,13 @@ public void restore(DateUtil.DateRange dateRange) throws Exception { | |
.setSnapshotMetaFile(latestValidMetaFile.get().getRemotePath()); | ||
|
||
List<AbstractBackupPath> allFiles = | ||
BackupRestoreUtil.getAllFiles( | ||
latestValidMetaFile.get(), dateRange, metaProxy, pathProvider); | ||
BackupRestoreUtil.getMostRecentSnapshotPaths( | ||
latestValidMetaFile.get(), metaProxy, pathProvider); | ||
if (!config.skipIncrementalRestore()) { | ||
allFiles.addAll( | ||
BackupRestoreUtil.getIncrementalPaths( | ||
latestValidMetaFile.get(), dateRange, metaProxy)); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I take it we don't have to update the callsite in BackupServletV2? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I updated it there as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm confused - do we need to use |
||
|
||
// Download snapshot which is listed in the meta file. | ||
List<Future<Path>> futureList = new ArrayList<>(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beautiful