Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 72 additions & 23 deletions cloud/blockstore/libs/endpoints/endpoint_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,12 +510,14 @@ class TEndpointManager final

NClient::IMetricClientPtr RestoringClient;
TSet<TString> RestoringEndpoints;
TAtomic RestoringErrors = 0;

enum {
WaitingForRestoring = 0,
ReadingStorage = 1,
StartingEndpoints = 2,
Completed = 3,
Failed = 4,
};

TAtomic RestoringStage = WaitingForRestoring;
Expand Down Expand Up @@ -628,13 +630,18 @@ class TEndpointManager final

TFuture<void> RestoreEndpoints() override
{
AtomicSet(RestoringErrors, 0);
AtomicSet(RestoringStage, ReadingStorage);
return Executor->Execute([weakSelf = weak_from_this()] () mutable {
if (auto self = weakSelf.lock()) {
auto future = self->DoRestoreEndpoints();
AtomicSet(self->RestoringStage, self->StartingEndpoints);
self->Executor->WaitFor(future);
AtomicSet(self->RestoringStage, self->Completed);
AtomicSet(
self->RestoringStage,
AtomicGet(self->RestoringErrors)
? self->Failed
: self->Completed);
}
});
}
Expand All @@ -660,10 +667,29 @@ class TEndpointManager final
case ReadingStorage: return true;
case StartingEndpoints: return RestoringEndpoints.contains(socket);
case Completed: return false;
case Failed: return false;
}
return false;
}

NProto::EEndpointRestoringState GetEndpointRestoringState()
{
switch (AtomicGet(RestoringStage)) {
case WaitingForRestoring:
return NProto::ENDPOINT_RESTORING_STATE_WAITING_FOR_RESTORING;
case ReadingStorage:
return NProto::ENDPOINT_RESTORING_STATE_READING_STORAGE;
case StartingEndpoints:
return NProto::ENDPOINT_RESTORING_STATE_STARTING_ENDPOINTS;
case Completed:
return NProto::ENDPOINT_RESTORING_STATE_COMPLETED;
case Failed:
return NProto::ENDPOINT_RESTORING_STATE_FAILED;
}

return NProto::ENDPOINT_RESTORING_STATE_FAILED;
}

NProto::TStartEndpointResponse StartEndpointImpl(
TCallContextPtr ctx,
std::shared_ptr<NProto::TStartEndpointRequest> request,
Expand Down Expand Up @@ -1243,6 +1269,7 @@ NProto::TListEndpointsResponse TEndpointManager::DoListEndpoints(
Y_UNUSED(ctx);
Y_UNUSED(request);


NProto::TListEndpointsResponse response;
auto& responseEndpoints = *response.MutableEndpoints();
responseEndpoints.Reserve(Endpoints.size());
Expand All @@ -1251,8 +1278,12 @@ NProto::TListEndpointsResponse TEndpointManager::DoListEndpoints(
responseEndpoints.Add()->CopyFrom(*endpoint->Request);
}

const auto restoringStage = AtomicGet(RestoringStage);
response.SetEndpointsWereRestored(
AtomicGet(RestoringStage) == Completed);
restoringStage == Completed || restoringStage == Failed);
response.SetEndpointRestoringState(GetEndpointRestoringState());
response.SetEndpointRestoringErrorCount(AtomicGet(RestoringErrors));

return response;
}

Expand Down Expand Up @@ -1826,10 +1857,14 @@ TFuture<NProto::TError> TEndpointManager::SwitchEndpointIfNeeded(
TFuture<void> TEndpointManager::DoRestoreEndpoints()
{
auto [endpointIds, error] = EndpointStorage->GetEndpointIds();
if (HasError(error) && !HasProtoFlag(error.GetFlags(), NProto::EF_SILENT)) {
ReportEndpointRestoringError(
TStringBuilder()
<< "Failed to get endpoints from storage: " << FormatError(error));
if (HasError(error)) {
AtomicIncrement(RestoringErrors);
if (!HasProtoFlag(error.GetFlags(), NProto::EF_SILENT)) {
ReportEndpointRestoringError(
TStringBuilder()
<< "Failed to get endpoints from storage: "
<< FormatError(error));
}
return MakeFuture();
}

Expand All @@ -1844,15 +1879,22 @@ TFuture<void> TEndpointManager::DoRestoreEndpoints()
if (HasError(error)
&& !HasProtoFlag(error.GetFlags(), NProto::EF_SILENT))
{
AtomicIncrement(RestoringErrors);
// NBS-3678
STORAGE_WARN("Failed to restore endpoint. ID: " << endpointId
<< ", error: " << FormatError(error));
continue;
}

if (HasError(error)) {
AtomicIncrement(RestoringErrors);
continue;
}

auto request = DeserializeEndpoint<NProto::TStartEndpointRequest>(str);

if (!request) {
AtomicIncrement(RestoringErrors);
ReportEndpointRestoringError(
TStringBuilder() << "Failed to deserialize request, error: "
<< FormatError(error),
Expand All @@ -1867,6 +1909,7 @@ TFuture<void> TEndpointManager::DoRestoreEndpoints()
auto error = NbdDeviceManager.AcquireDevice(nbdDevice);

if (HasError(error)) {
AtomicIncrement(RestoringErrors);
ReportEndpointRestoringError(
TStringBuilder()
<< "Failed to acquire nbd device, error: "
Expand Down Expand Up @@ -1897,25 +1940,31 @@ TFuture<void> TEndpointManager::DoRestoreEndpoints()
std::move(request));

auto weakPtr = weak_from_this();
future.Subscribe([weakPtr, socketPath, endpointId] (const auto& f) {
const auto& response = f.GetValue();
if (HasError(response)) {
ReportEndpointRestoringError(
TStringBuilder() << "Endpoint restoring error occurred for "
"endpoint, error: "
<< FormatError(response.GetError()),
{{"endpointId", endpointId}, {"socketPath", socketPath}});
}
auto handledFuture = future.Apply(
[weakPtr, socketPath, endpointId] (const auto& f) {
const auto& response = f.GetValue();
if (HasError(response)) {
ReportEndpointRestoringError(
TStringBuilder()
<< "Endpoint restoring error occurred for "
"endpoint, error: "
<< FormatError(response.GetError()),
{{"endpointId", endpointId},
{"socketPath", socketPath}});
}

if (auto ptr = weakPtr.lock()) {
ptr->HandleRestoredEndpoint(
socketPath,
endpointId,
response.GetError());
}
});
if (auto ptr = weakPtr.lock()) {
if (HasError(response)) {
AtomicIncrement(ptr->RestoringErrors);
}
ptr->HandleRestoredEndpoint(
socketPath,
endpointId,
response.GetError());
}
});

futures.push_back(future.IgnoreResult());
futures.push_back(std::move(handledFuture));
}

return WaitAll(futures);
Expand Down
11 changes: 11 additions & 0 deletions cloud/blockstore/libs/endpoints/endpoint_manager_ut.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1758,6 +1758,17 @@ Y_UNIT_TEST_SUITE(TEndpointManagerTest)

UNIT_ASSERT(wrongCount != correctCount);
UNIT_ASSERT_VALUES_EQUAL(wrongCount, static_cast<int>(*configCounter));

auto response =
ListEndpoints(*manager).GetValue(TDuration::Seconds(5));
UNIT_ASSERT(!HasError(response));
UNIT_ASSERT(response.GetEndpointsWereRestored());
UNIT_ASSERT_VALUES_EQUAL(
static_cast<int>(NProto::ENDPOINT_RESTORING_STATE_FAILED),
static_cast<int>(response.GetEndpointRestoringState()));
UNIT_ASSERT_VALUES_EQUAL(
wrongCount,
response.GetEndpointRestoringErrorCount());
}

Y_UNIT_TEST(ShouldRemoveEndpointForNotFoundVolume)
Expand Down
15 changes: 15 additions & 0 deletions cloud/blockstore/public/api/protos/endpoints.proto
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ message TListEndpointsRequest
THeaders Headers = 1;
}

enum EEndpointRestoringState
{
ENDPOINT_RESTORING_STATE_WAITING_FOR_RESTORING = 0;
ENDPOINT_RESTORING_STATE_READING_STORAGE = 1;
ENDPOINT_RESTORING_STATE_STARTING_ENDPOINTS = 2;
ENDPOINT_RESTORING_STATE_COMPLETED = 3;
ENDPOINT_RESTORING_STATE_FAILED = 4;
}

message TListEndpointsResponse
{
// Optional error, set only if error happened.
Expand All @@ -145,6 +154,12 @@ message TListEndpointsResponse

// Endpoints restoring status.
bool EndpointsWereRestored = 3;

// Endpoint restoring stage.
EEndpointRestoringState EndpointRestoringState = 4;

// Number of endpoint restoring errors.
uint32 EndpointRestoringErrorCount = 5;
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
Loading