182 lines
7.0 KiB
C++
182 lines
7.0 KiB
C++
/*
|
|
* BlobRestoreController.actor.cpp
|
|
*
|
|
* This source file is part of the FoundationDB open source project
|
|
*
|
|
* Copyright 2013-2024 Apple Inc. and the FoundationDB project authors
|
|
*
|
|
* Licensed 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.
|
|
*/
|
|
#include "fdbclient/BlobGranuleCommon.h"
|
|
#include "fdbclient/BlobRestoreCommon.h"
|
|
#include "fdbclient/ClientBooleanParams.h"
|
|
#include "fdbclient/DatabaseContext.h"
|
|
#include "fdbclient/FDBTypes.h"
|
|
#include "fdbclient/SystemData.h"
|
|
#include "fdbserver/BlobGranuleServerCommon.actor.h"
|
|
|
|
#include "flow/IRandom.h"
|
|
#include "flow/actorcompiler.h" // has to be last include
|
|
|
|
//
|
|
// This module offers routines to manage blob restore state for given range.
|
|
//
|
|
|
|
// Return true if the given key range is restoring. It returns true even if part of the key range is restoring
|
|
ACTOR Future<bool> BlobRestoreController::isRestoring(Reference<BlobRestoreController> self) {
|
|
BlobRestorePhase phase = wait(BlobRestoreController::currentPhase(self));
|
|
if (!self->range_.intersects(normalKeys)) {
|
|
return false;
|
|
}
|
|
if (phase < BlobRestorePhase::INIT || phase == BlobRestorePhase::DONE) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Get restore target version. Return defaultVersion if no restore argument available for the range
|
|
ACTOR Future<Version> BlobRestoreController::getTargetVersion(Reference<BlobRestoreController> self,
|
|
Version defaultVersion) {
|
|
|
|
BlobGranuleRestoreConfig config;
|
|
Version version = wait(config.targetVersion().getD(SystemDBWriteLockedNow(self->db_.getReference())));
|
|
return version;
|
|
}
|
|
|
|
// Get current restore phase
|
|
ACTOR Future<BlobRestorePhase> BlobRestoreController::currentPhase(Reference<BlobRestoreController> self) {
|
|
BlobGranuleRestoreConfig config;
|
|
auto db = SystemDBWriteLockedNow(self->db_.getReference());
|
|
BlobRestorePhase phase = wait(config.phase().getD(db, Snapshot::False, BlobRestorePhase::UNINIT));
|
|
return phase;
|
|
}
|
|
|
|
// Set current restore phase
|
|
ACTOR Future<Void> BlobRestoreController::setPhase(Reference<BlobRestoreController> self,
|
|
BlobRestorePhase newPhase,
|
|
Optional<UID> owerId) {
|
|
state Reference<ReadYourWritesTransaction> tr(new ReadYourWritesTransaction(self->db_));
|
|
loop {
|
|
try {
|
|
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
|
|
|
|
state BlobGranuleRestoreConfig config;
|
|
state BlobRestorePhase phase = wait(config.phase().getD(tr, Snapshot::True, BlobRestorePhase::MAX));
|
|
state UID currentOwnerId = wait(config.lock().getD(tr));
|
|
// check if current phase is expected
|
|
if (owerId.present() && currentOwnerId != owerId.get()) {
|
|
CODE_PROBE(true, "Blob migrator replaced in setPhase");
|
|
TraceEvent("BlobMigratorReplaced").detail("Expected", owerId).detail("Current", currentOwnerId);
|
|
throw blob_migrator_replaced();
|
|
}
|
|
if (phase > newPhase) {
|
|
CODE_PROBE(true, "Blob migrator unexpected phase");
|
|
TraceEvent("BlobMigratorUnexpectedPhase").detail("Phase", newPhase).detail("Current", phase);
|
|
throw restore_error();
|
|
}
|
|
|
|
// update phase start timestamp
|
|
if (phase != newPhase) {
|
|
config.phaseStartTs().set(tr, newPhase, now());
|
|
config.phase().set(tr, newPhase);
|
|
}
|
|
|
|
wait(tr->commit());
|
|
TraceEvent("BlobRestoreSetPhase").detail("Phase", newPhase);
|
|
return Void();
|
|
} catch (Error& e) {
|
|
wait(tr->onError(e));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Wait on restore phase change
|
|
ACTOR Future<Void> BlobRestoreController::onPhaseChange(Reference<BlobRestoreController> self,
|
|
BlobRestorePhase expectedPhase) {
|
|
state Reference<ReadYourWritesTransaction> tr(new ReadYourWritesTransaction(self->db_));
|
|
loop {
|
|
try {
|
|
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
|
|
|
|
BlobRestorePhase phase =
|
|
wait(BlobGranuleRestoreConfig().phase().getD(tr, Snapshot::False, BlobRestorePhase::UNINIT));
|
|
if (expectedPhase == phase) {
|
|
return Void();
|
|
}
|
|
|
|
state Future<Void> watch = BlobGranuleRestoreConfig().trigger.watch(tr);
|
|
wait(tr->commit());
|
|
wait(watch);
|
|
return Void();
|
|
} catch (Error& e) {
|
|
wait(tr->onError(e));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update restore progress
|
|
ACTOR Future<Void> BlobRestoreController::setProgress(Reference<BlobRestoreController> self,
|
|
int progress,
|
|
UID ownerId) {
|
|
state Reference<ReadYourWritesTransaction> tr(new ReadYourWritesTransaction(self->db_));
|
|
loop {
|
|
try {
|
|
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
|
|
|
|
UID currentOwner = wait(BlobGranuleRestoreConfig().lock().getD(tr));
|
|
if (currentOwner != ownerId) {
|
|
CODE_PROBE(true, "Blob migrator replaced in setProgress");
|
|
TraceEvent("BlobMigratorReplaced").detail("ActiveId", currentOwner).detail("CallerId", ownerId);
|
|
throw blob_migrator_replaced();
|
|
}
|
|
BlobGranuleRestoreConfig().progress().set(tr, progress);
|
|
wait(tr->commit());
|
|
return Void();
|
|
} catch (Error& e) {
|
|
wait(tr->onError(e));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set lock owner for current restore. Owner will be checked for further updates of restore config
|
|
ACTOR Future<Void> BlobRestoreController::setLockOwner(Reference<BlobRestoreController> self, UID ownerId) {
|
|
wait(runRYWTransaction(self->db_, [=](Reference<ReadYourWritesTransaction> tr) -> Future<Void> {
|
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
|
|
tr->setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
|
|
BlobGranuleRestoreConfig().lock().set(tr, ownerId);
|
|
return Void();
|
|
}));
|
|
return Void();
|
|
}
|
|
|
|
// Fail the restore with an error message
|
|
ACTOR Future<Void> BlobRestoreController::setError(Reference<BlobRestoreController> self, std::string errorMessage) {
|
|
wait(runRYWTransaction(self->db_, [=](Reference<ReadYourWritesTransaction> tr) -> Future<Void> {
|
|
tr->setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
|
|
tr->setOption(FDBTransactionOptions::LOCK_AWARE);
|
|
BlobGranuleRestoreConfig config;
|
|
config.phase().set(tr, BlobRestorePhase::ERROR);
|
|
config.phaseStartTs().set(tr, BlobRestorePhase::ERROR, now());
|
|
config.error().set(tr, errorMessage);
|
|
return Void();
|
|
}));
|
|
return Void();
|
|
}
|