use of com.palantir.atlasdb.backup.api.AtlasService in project atlasdb by palantir.
the class AtlasBackupService method completeBackup.
/**
* Completes backup for the given set of atlas services.
* This will store metadata about the completed backup via the BackupPersister.
* <p>
* In order to do this, we must unlock the immutable timestamp for each service. If {@link #prepareBackup(Set)}
* was not called, we will not have a record of the in-progress backup (and will not have been refreshing
* its lock anyway). Thus, we attempt to complete backup only for those atlas services where we have the in-progress
* backup stored.
*
* @return the atlas services whose backups were successfully completed
*/
public Set<AtlasService> completeBackup(Set<AtlasService> atlasServices) {
throwIfClosed(atlasServices);
AtlasServices.throwIfAtlasServicesCollide(atlasServices);
Map<AtlasService, InProgressBackupToken> knownBackups = KeyedStream.of(atlasServices).map((Function<AtlasService, InProgressBackupToken>) inProgressBackups::remove).filter(Objects::nonNull).collectToMap();
Set<InProgressBackupToken> tokens = ImmutableSet.copyOf(knownBackups.values());
if (tokens.isEmpty()) {
log.error("Complete backup called, but no in progress backups were found.", SafeArg.of("atlasServices", atlasServices));
return ImmutableSet.of();
}
lockRefresher.unregisterLocks(tokens);
Set<AtlasService> atlasServicesWithInProgressBackups = knownBackups.keySet();
if (tokens.size() < atlasServices.size()) {
Set<AtlasService> atlasServicesWithNoInProgressBackup = Sets.difference(atlasServices, atlasServicesWithInProgressBackups);
log.error("In progress backups were not found for some atlasServices. We will not complete backup for these.", SafeArg.of("numAtlasServicesWithBackup", tokens.size()), SafeArg.of("numAtlasServicesWithoutBackup", atlasServicesWithNoInProgressBackup.size()), SafeArg.of("atlasServicesWithoutBackup", atlasServicesWithNoInProgressBackup), SafeArg.of("allRequestedAtlasServices", atlasServices));
}
Map<Namespace, AtlasService> namespaceToServices = KeyedStream.of(atlasServices).mapKeys(AtlasService::getNamespace).collectToMap();
CompleteBackupRequest request = CompleteBackupRequest.of(tokens);
CompleteBackupResponse response = atlasBackupClient.completeBackup(authHeader, request);
Map<AtlasService, CompletedBackup> successfulBackups = KeyedStream.of(response.getSuccessfulBackups()).mapKeys(token -> namespaceToServices.get(token.getNamespace())).collectToMap();
Set<AtlasService> successfullyStoredBackups = storeCompletedBackups(successfulBackups);
if (successfullyStoredBackups.size() < atlasServicesWithInProgressBackups.size()) {
Set<AtlasService> failedAtlasServices = Sets.difference(atlasServicesWithInProgressBackups, successfullyStoredBackups);
log.error("Backup did not complete successfully for all atlasServices. Check TimeLock logs to debug.", SafeArg.of("failedAtlasServices", failedAtlasServices), SafeArg.of("successfulAtlasServices", successfullyStoredBackups), SafeArg.of("atlasServicesWithoutBackup", atlasServicesWithInProgressBackups));
}
return successfulBackups.keySet();
}
use of com.palantir.atlasdb.backup.api.AtlasService in project atlasdb by palantir.
the class AtlasBackupService method storeCompletedBackups.
private Set<AtlasService> storeCompletedBackups(Map<AtlasService, CompletedBackup> successfulBackups) {
ExecutorService executorService = PTExecutors.newFixedThreadPool(completeBackupNumThreads);
Map<AtlasService, ListenableFuture<Optional<Boolean>>> storedBackups = KeyedStream.stream(successfulBackups).map((atlasService, completeBackup) -> Futures.submit(() -> Optional.of(storeCompletedBackup(atlasService, completeBackup)), executorService)).collectToMap();
ListenableFuture<Map<AtlasService, Boolean>> allStorageTasks = AtlasFutures.allAsMap(storedBackups, MoreExecutors.directExecutor());
// Waits for future to complete
Map<AtlasService, Boolean> storageTaskResults = AtlasFutures.getUnchecked(allStorageTasks);
executorService.shutdown();
return KeyedStream.stream(storageTaskResults).filter(Boolean::booleanValue).keys().collect(Collectors.toSet());
}
use of com.palantir.atlasdb.backup.api.AtlasService in project atlasdb by palantir.
the class AtlasRestoreService method prepareRestore.
/**
* Disables TimeLock on all nodes for the given atlasServices.
* This will fail if any atlasService is already disabled, unless it was disabled with the provided backupId.
* AtlasServices for which we don't have a recorded backup will be ignored.
*
* @param restoreRequests the requests to prepare.
* @param backupId a unique identifier for this request (uniquely identifies the backup to which we're restoring)
*
* @return the atlasServices successfully disabled.
*/
public Set<AtlasService> prepareRestore(Set<RestoreRequest> restoreRequests, String backupId) {
validateRestoreRequests(restoreRequests);
Map<RestoreRequest, CompletedBackup> completedBackups = getCompletedBackups(restoreRequests);
Set<AtlasService> atlasServicesToRestore = getAtlasServicesToRestore(completedBackups);
Preconditions.checkArgument(atlasServicesToRestore.size() == completedBackups.size(), "Attempting to restore multiple atlasServices into the same atlasService! " + "This will cause severe data corruption.", SafeArg.of("restoreRequests", restoreRequests));
Set<Namespace> namespacesToRestore = atlasServicesToRestore.stream().map(AtlasService::getNamespace).collect(Collectors.toSet());
DisableNamespacesRequest request = DisableNamespacesRequest.of(namespacesToRestore, backupId);
DisableNamespacesResponse response = timeLockManagementService.disableTimelock(authHeader, request);
return response.accept(new DisableNamespacesResponse.Visitor<>() {
@Override
public Set<AtlasService> visitSuccessful(SuccessfulDisableNamespacesResponse value) {
return atlasServicesToRestore;
}
@Override
public Set<AtlasService> visitUnsuccessful(UnsuccessfulDisableNamespacesResponse value) {
log.error("Failed to disable namespaces prior to restore", SafeArg.of("requests", restoreRequests), SafeArg.of("response", value));
return ImmutableSet.of();
}
@Override
public Set<AtlasService> visitUnknown(String unknownType) {
throw new SafeIllegalStateException("Unknown DisableNamespacesResponse", SafeArg.of("unknownType", unknownType));
}
});
}
use of com.palantir.atlasdb.backup.api.AtlasService in project atlasdb by palantir.
the class AtlasRestoreService method repairTransactionsTables.
private void repairTransactionsTables(RestoreRequest restoreRequest, CompletedBackup completedBackup, BiConsumer<String, RangesForRepair> repairTable) {
Map<FullyBoundedTimestampRange, Integer> coordinationMap = getCoordinationMap(restoreRequest.oldAtlasService(), completedBackup);
List<TransactionsTableInteraction> transactionsTableInteractions = TransactionsTableInteraction.getTransactionTableInteractions(coordinationMap, DefaultRetryPolicy.INSTANCE);
AtlasService atlasService = restoreRequest.newAtlasService();
cassandraRepairHelper.repairTransactionsTables(atlasService, transactionsTableInteractions, repairTable);
cassandraRepairHelper.cleanTransactionsTables(atlasService, completedBackup.getBackupStartTimestamp(), transactionsTableInteractions);
}
use of com.palantir.atlasdb.backup.api.AtlasService in project atlasdb by palantir.
the class AtlasBackupServiceTest method prepareBackupThrowsIfNamespacesCollide.
@Test
public void prepareBackupThrowsIfNamespacesCollide() {
AtlasService collidingAtlasService = AtlasService.of(ServiceId.of("c"), ATLAS_SERVICE.getNamespace());
assertThatLoggableExceptionThrownBy(() -> atlasBackupService.prepareBackup(ImmutableSet.of(ATLAS_SERVICE, collidingAtlasService))).isInstanceOf(SafeIllegalArgumentException.class).hasMessageContaining("Duplicated namespaces");
}
Aggregations