Skip to content

Commit ce3201c

Browse files
authored
Optimize waiting for index creation during restore in YDB CLI (#8936)
1 parent 0766f41 commit ce3201c

File tree

2 files changed

+95
-69
lines changed

2 files changed

+95
-69
lines changed

ydb/public/lib/ydb_cli/dump/restore_impl.cpp

+39-69
Original file line numberDiff line numberDiff line change
@@ -51,60 +51,26 @@ Ydb::Scheme::ModifyPermissionsRequest ReadPermissions(const TString& fsPath) {
5151
return proto;
5252
}
5353

54-
bool HasRunningIndexBuilds(TOperationClient& client, const TString& dbPath) {
55-
const ui64 pageSize = 100;
56-
TString pageToken;
57-
58-
do {
59-
const ui32 maxRetries = 8;
60-
TDuration retrySleep = TDuration::MilliSeconds(100);
61-
62-
for (ui32 retryNumber = 0; retryNumber <= maxRetries; ++retryNumber) {
63-
auto operations = client.List<TBuildIndexOperation>(pageSize, pageToken).GetValueSync();
64-
65-
if (!operations.IsSuccess()) {
66-
if (retryNumber == maxRetries) {
67-
Y_ENSURE(false, "Cannot list operations");
68-
}
69-
70-
switch (operations.GetStatus()) {
71-
case EStatus::ABORTED:
72-
break;
54+
TStatus WaitForIndexBuild(TOperationClient& client, const TOperation::TOperationId& id) {
55+
TDuration retrySleep = TDuration::MilliSeconds(100);
56+
while (true) {
57+
auto operation = client.Get<TBuildIndexOperation>(id).GetValueSync();
58+
if (!operation.Status().IsTransportError()) {
59+
switch (operation.Status().GetStatus()) {
7360
case EStatus::OVERLOADED:
74-
case EStatus::CLIENT_RESOURCE_EXHAUSTED:
7561
case EStatus::UNAVAILABLE:
76-
case EStatus::TRANSPORT_UNAVAILABLE:
77-
NConsoleClient::ExponentialBackoff(retrySleep);
78-
break;
79-
default:
80-
Y_ENSURE(false, "Unexpected status while trying to list operations: " << operations.GetStatus());
81-
}
82-
83-
continue;
84-
}
85-
86-
for (const auto& operation : operations.GetList()) {
87-
if (operation.Metadata().Path != dbPath) {
88-
continue;
89-
}
90-
91-
switch (operation.Metadata().State) {
92-
case EBuildIndexState::Preparing:
93-
case EBuildIndexState::TransferData:
94-
case EBuildIndexState::Applying:
95-
case EBuildIndexState::Cancellation:
96-
case EBuildIndexState::Rejection:
97-
return true;
62+
case EStatus::STATUS_UNDEFINED:
63+
break; // retry
9864
default:
99-
break;
100-
}
101-
}
102-
103-
pageToken = operations.NextPageToken();
65+
return operation.Status();
66+
}
10467
}
105-
} while (pageToken != "0");
68+
NConsoleClient::ExponentialBackoff(retrySleep, TDuration::Minutes(1));
69+
}
70+
}
10671

107-
return false;
72+
bool IsOperationStarted(TStatus operationStatus) {
73+
return operationStatus.IsSuccess() || operationStatus.GetStatus() == EStatus::STATUS_UNDEFINED;
10874
}
10975

11076
} // anonymous
@@ -416,36 +382,40 @@ TRestoreResult TRestoreClient::RestoreData(const TFsPath& fsPath, const TString&
416382

417383
TRestoreResult TRestoreClient::RestoreIndexes(const TString& dbPath, const TTableDescription& desc) {
418384
TMaybe<TTableDescription> actualDesc;
385+
auto descResult = DescribeTable(TableClient, dbPath, actualDesc);
386+
if (!descResult.IsSuccess()) {
387+
return Result<TRestoreResult>(dbPath, std::move(descResult));
388+
}
419389

420390
for (const auto& index : desc.GetIndexDescriptions()) {
421-
// check (and wait) for unuexpected index buils
422-
while (HasRunningIndexBuilds(OperationClient, dbPath)) {
423-
actualDesc.Clear();
424-
Sleep(TDuration::Minutes(1));
425-
}
426-
427-
if (!actualDesc) {
428-
auto descResult = DescribeTable(TableClient, dbPath, actualDesc);
429-
if (!descResult.IsSuccess()) {
430-
return Result<TRestoreResult>(dbPath, std::move(descResult));
431-
}
432-
}
433-
434391
if (FindPtr(actualDesc->GetIndexDescriptions(), index)) {
435392
continue;
436393
}
437394

438-
auto status = TableClient.RetryOperationSync([&dbPath, &index](TSession session) {
395+
TOperation::TOperationId buildIndexId;
396+
auto buildIndexStatus = TableClient.RetryOperationSync([&, &outId = buildIndexId](TSession session) {
439397
auto settings = TAlterTableSettings().AppendAddIndexes(index);
440-
return session.AlterTableLong(dbPath, settings).GetValueSync().Status();
398+
auto result = session.AlterTableLong(dbPath, settings).GetValueSync();
399+
if (IsOperationStarted(result.Status())) {
400+
outId = result.Id();
401+
}
402+
return result.Status();
441403
});
442-
if (!status.IsSuccess() && status.GetStatus() != EStatus::STATUS_UNDEFINED) {
443-
return Result<TRestoreResult>(dbPath, std::move(status));
404+
405+
if (!IsOperationStarted(buildIndexStatus)) {
406+
return Result<TRestoreResult>(dbPath, std::move(buildIndexStatus));
407+
}
408+
409+
auto waitForIndexBuildStatus = WaitForIndexBuild(OperationClient, buildIndexId);
410+
if (!waitForIndexBuildStatus.IsSuccess()) {
411+
return Result<TRestoreResult>(dbPath, std::move(waitForIndexBuildStatus));
444412
}
445413

446-
// wait for expected index build
447-
while (HasRunningIndexBuilds(OperationClient, dbPath)) {
448-
Sleep(TDuration::Minutes(1));
414+
auto forgetStatus = NConsoleClient::RetryFunction([&]() {
415+
return OperationClient.Forget(buildIndexId).GetValueSync();
416+
});
417+
if (!forgetStatus.IsSuccess()) {
418+
return Result<TRestoreResult>(dbPath, std::move(forgetStatus));
449419
}
450420
}
451421

ydb/services/ydb/backup_ut/ydb_backup_ut.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <google/protobuf/util/message_differencer.h>
2020

2121
using namespace NYdb;
22+
using namespace NYdb::NOperation;
2223
using namespace NYdb::NTable;
2324

2425
namespace NYdb::NTable {
@@ -98,12 +99,30 @@ auto CreateMinPartitionsChecker(ui32 expectedMinPartitions, const TString& debug
9899
};
99100
}
100101

102+
auto CreateHasIndexChecker(const TString& indexName) {
103+
return [=](const TTableDescription& tableDescription) {
104+
for (const auto& indexDesc : tableDescription.GetIndexDescriptions()) {
105+
if (indexDesc.GetIndexName() == indexName) {
106+
return true;
107+
}
108+
}
109+
return false;
110+
};
111+
}
112+
101113
void CheckTableDescription(TSession& session, const TString& path, auto&& checker,
102114
const TDescribeTableSettings& settings = {}
103115
) {
104116
checker(GetTableDescription(session, path, settings));
105117
}
106118

119+
void CheckBuildIndexOperationsCleared(TDriver& driver) {
120+
TOperationClient operationClient(driver);
121+
const auto result = operationClient.List<TBuildIndexOperation>().GetValueSync();
122+
UNIT_ASSERT_C(result.IsSuccess(), "issues:\n" << result.GetIssues().ToString());
123+
UNIT_ASSERT_C(result.GetList().empty(), "Build index operations aren't cleared:\n" << result.ToJsonString());
124+
}
125+
107126
using TBackupFunction = std::function<void(const char*)>;
108127
using TRestoreFunction = std::function<void(const char*)>;
109128

@@ -417,6 +436,43 @@ Y_UNIT_TEST_SUITE(BackupRestore) {
417436
}
418437

419438
// TO DO: test index impl table split boundaries restoration from a backup
439+
440+
Y_UNIT_TEST(BasicRestoreTableWithIndex) {
441+
TKikimrWithGrpcAndRootSchema server;
442+
auto driver = TDriver(TDriverConfig().SetEndpoint(Sprintf("localhost:%d", server.GetPort())));
443+
TTableClient tableClient(driver);
444+
auto session = tableClient.GetSession().ExtractValueSync().GetSession();
445+
446+
constexpr const char* table = "/Root/table";
447+
constexpr const char* index = "byValue";
448+
ExecuteDataDefinitionQuery(session, Sprintf(R"(
449+
CREATE TABLE `%s` (
450+
Key Uint32,
451+
Value Uint32,
452+
PRIMARY KEY (Key),
453+
INDEX %s GLOBAL ON (Value)
454+
);
455+
)",
456+
table, index
457+
));
458+
459+
TTempDir tempDir;
460+
const auto& pathToBackup = tempDir.Path();
461+
// TO DO: implement NDump::TClient::Dump and call it instead of BackupFolder
462+
NYdb::NBackup::BackupFolder(driver, "/Root", ".", pathToBackup, {}, false, false);
463+
464+
NDump::TClient backupClient(driver);
465+
466+
// restore deleted table
467+
ExecuteDataDefinitionQuery(session, Sprintf(R"(
468+
DROP TABLE `%s`;
469+
)", table
470+
));
471+
Restore(backupClient, pathToBackup, "/Root");
472+
473+
CheckTableDescription(session, table, CreateHasIndexChecker(index));
474+
CheckBuildIndexOperationsCleared(driver);
475+
}
420476
}
421477

422478
Y_UNIT_TEST_SUITE(BackupRestoreS3) {

0 commit comments

Comments
 (0)