foundationdb/fdbserver/BlobRestoreController.actor...

196 lines
7.5 KiB
C++

/*
* BlobRestoreController.actor.cpp
*
* This source file is part of the FoundationDB open source project
*
* Copyright 2013-2022 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 "fdbserver/BlobGranuleServerCommon.actor.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) {
BlobRestoreRangeState rangeState = wait(BlobRestoreController::getRangeState(self));
return !rangeState.first.empty() && rangeState.second.phase != BlobRestorePhase::DONE;
}
// Check the given key range and return subrange that is restoring. Returns empty range if no restoring
// for any portion of the given range. Note that it's possible that only partial of the range is restoring.
ACTOR Future<BlobRestoreRangeState> BlobRestoreController::getRangeState(Reference<BlobRestoreController> self) {
state Transaction tr(self->db_);
loop {
tr.setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
tr.setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
tr.setOption(FDBTransactionOptions::LOCK_AWARE);
try {
state GetRangeLimits limits(SERVER_KNOBS->BLOB_MANIFEST_RW_ROWS);
limits.minRows = 0;
state KeySelectorRef begin = firstGreaterOrEqual(blobRestoreCommandKeys.begin);
state KeySelectorRef end = firstGreaterOrEqual(blobRestoreCommandKeys.end);
loop {
RangeResult ranges = wait(tr.getRange(begin, end, limits, Snapshot::True));
for (auto& r : ranges) {
KeyRange keyRange = decodeBlobRestoreCommandKeyFor(r.key);
if (self->range_.intersects(keyRange)) {
Standalone<BlobRestoreState> restoreState = decodeBlobRestoreState(r.value);
KeyRangeRef intersected(std::max(self->range_.begin, keyRange.begin),
std::min(self->range_.end, keyRange.end));
return std::make_pair(intersected, restoreState);
}
}
if (!ranges.more) {
break;
}
if (ranges.readThrough.present()) {
begin = firstGreaterOrEqual(ranges.readThrough.get());
} else {
begin = firstGreaterThan(ranges.end()[-1].key);
}
}
return std::make_pair(KeyRangeRef(), BlobRestoreState(BlobRestorePhase::DONE));
} catch (Error& e) {
wait(tr.onError(e));
}
}
}
ACTOR Future<Void> BlobRestoreController::updateState(Reference<BlobRestoreController> self,
Standalone<BlobRestoreState> newState,
Optional<BlobRestorePhase> expectedPhase) {
state Transaction tr(self->db_);
loop {
try {
tr.setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
tr.setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
tr.setOption(FDBTransactionOptions::LOCK_AWARE);
state Key key = blobRestoreCommandKeyFor(self->range_);
Optional<Value> oldValue = wait(tr.get(key));
if (oldValue.present()) {
Standalone<BlobRestoreState> oldState = decodeBlobRestoreState(oldValue.get());
// check if current phase is expected
if (expectedPhase.present() && oldState.phase != expectedPhase.get()) {
TraceEvent("BlobRestoreUnexpectedPhase")
.detail("Expected", expectedPhase.get())
.detail("Current", oldState.phase);
throw restore_error();
}
newState.phaseStartTs = VectorRef<int64_t>(newState.arena(), oldState.phaseStartTs);
if (newState.phase != oldState.phase) {
newState.phaseStartTs.resize(newState.arena(), BlobRestorePhase::MAX);
newState.phaseStartTs[newState.phase] = now();
}
}
Value value = blobRestoreCommandValueFor(newState);
tr.set(key, value);
wait(tr.commit());
TraceEvent("BlobRestoreUpdatePhase").detail("Phase", newState.phase);
return Void();
} catch (Error& e) {
wait(tr.onError(e));
}
}
}
ACTOR Future<Void> BlobRestoreController::updateState(Reference<BlobRestoreController> self,
BlobRestorePhase newPhase,
Optional<BlobRestorePhase> expectedPhase) {
Standalone<BlobRestoreState> newState;
newState.phase = newPhase;
wait(BlobRestoreController::updateState(self, newState, expectedPhase));
return Void();
}
ACTOR Future<Void> BlobRestoreController::updateError(Reference<BlobRestoreController> self,
Standalone<StringRef> errorMessage) {
Standalone<BlobRestoreState> newState;
newState.error = StringRef(newState.arena(), errorMessage);
newState.phase = BlobRestorePhase::ERROR;
wait(BlobRestoreController::updateState(self, newState, {}));
return Void();
}
ACTOR Future<Optional<BlobRestoreState>> BlobRestoreController::getState(Reference<BlobRestoreController> self) {
std::pair<KeyRange, BlobRestoreState> rangeStatus = wait(BlobRestoreController::getRangeState(self));
Optional<BlobRestoreState> result;
if (!rangeStatus.first.empty()) {
result = rangeStatus.second;
}
return result;
}
// Get restore argument
ACTOR Future<Optional<BlobRestoreArg>> BlobRestoreController::getArgument(Reference<BlobRestoreController> self) {
state Transaction tr(self->db_);
state Optional<BlobRestoreArg> result;
loop {
try {
tr.setOption(FDBTransactionOptions::PRIORITY_SYSTEM_IMMEDIATE);
tr.setOption(FDBTransactionOptions::ACCESS_SYSTEM_KEYS);
tr.setOption(FDBTransactionOptions::LOCK_AWARE);
try {
state GetRangeLimits limits(SERVER_KNOBS->BLOB_MANIFEST_RW_ROWS);
limits.minRows = 0;
state KeySelectorRef begin = firstGreaterOrEqual(blobRestoreArgKeys.begin);
state KeySelectorRef end = firstGreaterOrEqual(blobRestoreArgKeys.end);
loop {
RangeResult ranges = wait(tr.getRange(begin, end, limits, Snapshot::True));
for (auto& r : ranges) {
KeyRange keyRange = decodeBlobRestoreArgKeyFor(r.key);
if (self->range_.intersects(keyRange)) {
Standalone<BlobRestoreArg> arg = decodeBlobRestoreArg(r.value);
result = arg;
return result;
}
}
if (!ranges.more) {
break;
}
if (ranges.readThrough.present()) {
begin = firstGreaterOrEqual(ranges.readThrough.get());
} else {
begin = firstGreaterThan(ranges.back().key);
}
}
return result;
} catch (Error& e) {
wait(tr.onError(e));
}
} catch (Error& e) {
wait(tr.onError(e));
}
}
}
// Get restore target version. Return defaultVersion if no restore argument available for the range
ACTOR Future<Version> BlobRestoreController::getTargetVersion(Reference<BlobRestoreController> self,
Version defaultVersion) {
Optional<BlobRestoreArg> arg = wait(BlobRestoreController::getArgument(self));
if (arg.present()) {
if (arg.get().version.present()) {
return arg.get().version.get();
}
}
return defaultVersion;
}