aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIlia Shakhov <pixcc@ydb.tech>2025-03-14 11:33:25 +0300
committerGitHub <noreply@github.com>2025-03-14 11:33:25 +0300
commit3917ee3bf8708df6c1f97e3f5659c44272961fd3 (patch)
treee31c9d02614be6339437b11f88acd6081377a460
parentd843851178e39f1c590e0b4fe5adb96a4eaee240 (diff)
downloadydb-3917ee3bf8708df6c1f97e3f5659c44272961fd3.tar.gz
Add create_time & last_refresh_time to Task in Maintenance API (#15690)
-rw-r--r--ydb/core/cms/api_adapters.cpp17
-rw-r--r--ydb/core/cms/cms_maintenance_api_ut.cpp64
-rw-r--r--ydb/core/cms/cms_state.h4
-rw-r--r--ydb/core/cms/cms_tx_load_state.cpp6
-rw-r--r--ydb/core/cms/cms_tx_store_permissions.cpp17
-rw-r--r--ydb/core/cms/cms_ut_common.h36
-rw-r--r--ydb/core/cms/scheme.h11
-rw-r--r--ydb/public/api/protos/draft/ydb_maintenance.proto8
8 files changed, 159 insertions, 4 deletions
diff --git a/ydb/core/cms/api_adapters.cpp b/ydb/core/cms/api_adapters.cpp
index cf416d3e88..0b2ebb8199 100644
--- a/ydb/core/cms/api_adapters.cpp
+++ b/ydb/core/cms/api_adapters.cpp
@@ -109,6 +109,11 @@ namespace {
ConvertPermission(taskUid, protoPermission, actionState);
}
+ void ConvertInstant(const TInstant& instant, google::protobuf::Timestamp& protoValue) {
+ protoValue.set_seconds(instant.Seconds());
+ protoValue.set_nanos(instant.NanoSecondsOfSecond());
+ }
+
} // anonymous
template <typename TDerived, typename TEvRequest, typename TEvResponse>
@@ -312,6 +317,10 @@ public:
// performed actions: existing permissions
if (cmsState->MaintenanceTasks.contains(taskUid)) {
const auto& task = cmsState->MaintenanceTasks.at(taskUid);
+
+ ConvertInstant(task.CreateTime, *result.mutable_create_time());
+ ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time());
+
for (const auto& id : task.Permissions) {
if (!cmsState->Permissions.contains(id) || permissionsSeen.contains(id)) {
continue;
@@ -501,6 +510,8 @@ public:
auto& result = *response->Record.MutableResult();
result.set_task_uid(taskUid);
+ ConvertInstant(task.CreateTime, *result.mutable_create_time());
+ ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time());
// performed actions
for (const auto& id : task.Permissions) {
@@ -566,6 +577,8 @@ public:
auto& result = *response->Record.MutableResult();
result.mutable_task_options()->set_task_uid(taskUid);
+ ConvertInstant(task.CreateTime, *result.mutable_create_time());
+ ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time());
// performed actions
for (const auto& id : task.Permissions) {
@@ -633,6 +646,10 @@ public:
// performed actions
if (cmsState->MaintenanceTasks.contains(taskUid)) {
const auto& task = cmsState->MaintenanceTasks.at(taskUid);
+
+ ConvertInstant(task.CreateTime, *result.mutable_create_time());
+ ConvertInstant(task.LastRefreshTime, *result.mutable_last_refresh_time());
+
for (const auto& id : task.Permissions) {
if (!cmsState->Permissions.contains(id)) {
continue;
diff --git a/ydb/core/cms/cms_maintenance_api_ut.cpp b/ydb/core/cms/cms_maintenance_api_ut.cpp
index 52b8b37f81..823311191d 100644
--- a/ydb/core/cms/cms_maintenance_api_ut.cpp
+++ b/ydb/core/cms/cms_maintenance_api_ut.cpp
@@ -116,6 +116,70 @@ Y_UNIT_TEST_SUITE(TMaintenanceApiTest) {
const auto &a = response.action_group_states(0).action_states(0);
UNIT_ASSERT_VALUES_EQUAL(a.status(), ActionState::ACTION_STATUS_PERFORMED);
}
+
+ Y_UNIT_TEST(CreateTime) {
+ TCmsTestEnv env(8);
+
+ // Move time to make it different from initial time
+ env.AdvanceCurrentTime(TDuration::MilliSeconds(5500));
+
+ // Create sets create time
+ auto createResult = env.CheckMaintenanceTaskCreate("task-1", Ydb::StatusIds::SUCCESS,
+ MakeActionGroup(
+ MakeLockAction(env.GetNodeId(0), TDuration::Minutes(10))
+ ),
+ MakeActionGroup(
+ MakeLockAction(env.GetNodeId(1), TDuration::Minutes(10))
+ )
+ );
+ UNIT_ASSERT_VALUES_UNEQUAL(createResult.create_time().seconds(), 0);
+ UNIT_ASSERT_VALUES_UNEQUAL(createResult.create_time().nanos(), 0);
+
+ // Move time to make it different from create time
+ env.AdvanceCurrentTime(TDuration::MilliSeconds(5500));
+
+ // Get doesn't update create time
+ auto getResult = env.CheckMaintenanceTaskGet("task-1", Ydb::StatusIds::SUCCESS);
+ UNIT_ASSERT_VALUES_EQUAL(getResult.create_time().seconds(), createResult.create_time().seconds());
+ UNIT_ASSERT_VALUES_EQUAL(getResult.create_time().nanos(), createResult.create_time().nanos());
+
+ // Refresh doesn't update create time
+ auto refreshResult = env.CheckMaintenanceTaskRefresh("task-1", Ydb::StatusIds::SUCCESS);
+ UNIT_ASSERT_VALUES_EQUAL(refreshResult.create_time().seconds(), createResult.create_time().seconds());
+ UNIT_ASSERT_VALUES_EQUAL(refreshResult.create_time().nanos(), createResult.create_time().nanos());
+ }
+
+ Y_UNIT_TEST(LastRefreshTime) {
+ TCmsTestEnv env(8);
+
+ // Move time to make it different from initial time
+ env.AdvanceCurrentTime(TDuration::MilliSeconds(5500));
+
+ // Create includes refresh, so create sets last refresh time
+ auto createResult = env.CheckMaintenanceTaskCreate("task-1", Ydb::StatusIds::SUCCESS,
+ MakeActionGroup(
+ MakeLockAction(env.GetNodeId(0), TDuration::Minutes(10))
+ ),
+ MakeActionGroup(
+ MakeLockAction(env.GetNodeId(1), TDuration::Minutes(10))
+ )
+ );
+ UNIT_ASSERT_VALUES_UNEQUAL(createResult.last_refresh_time().seconds(), 0);
+ UNIT_ASSERT_VALUES_UNEQUAL(createResult.last_refresh_time().nanos(), 0);
+
+ // Move time to make it different from create time
+ env.AdvanceCurrentTime(TDuration::MilliSeconds(5500));
+
+ // Get doesn't update last refresh time
+ auto getResult = env.CheckMaintenanceTaskGet("task-1", Ydb::StatusIds::SUCCESS);
+ UNIT_ASSERT_VALUES_EQUAL(getResult.last_refresh_time().seconds(), createResult.last_refresh_time().seconds());
+ UNIT_ASSERT_VALUES_EQUAL(getResult.last_refresh_time().nanos(), createResult.last_refresh_time().nanos());
+
+ // Refresh updates last refresh time
+ auto refreshResult = env.CheckMaintenanceTaskRefresh("task-1", Ydb::StatusIds::SUCCESS);
+ UNIT_ASSERT_VALUES_UNEQUAL(refreshResult.last_refresh_time().seconds(), createResult.last_refresh_time().seconds());
+ UNIT_ASSERT_VALUES_UNEQUAL(refreshResult.last_refresh_time().nanos(), createResult.last_refresh_time().nanos());
+ }
}
} // namespace NKikimr::NCmsTest
diff --git a/ydb/core/cms/cms_state.h b/ydb/core/cms/cms_state.h
index c6b5e5ba4d..328ba32719 100644
--- a/ydb/core/cms/cms_state.h
+++ b/ydb/core/cms/cms_state.h
@@ -16,6 +16,8 @@ struct TTaskInfo {
TString Owner;
TSet<TString> Permissions;
bool HasSingleCompositeActionGroup = false;
+ TInstant CreateTime;
+ TInstant LastRefreshTime;
TString ToString() const {
return TStringBuilder() << "{"
@@ -24,6 +26,8 @@ struct TTaskInfo {
<< " Owner: " << Owner
<< " Permissions: [" << JoinSeq(", ", Permissions) << "]"
<< " HasSingleCompositeActionGroup: " << HasSingleCompositeActionGroup
+ << " CreateTime: " << CreateTime
+ << " LastRefreshTime: " << LastRefreshTime
<< " }";
}
};
diff --git a/ydb/core/cms/cms_tx_load_state.cpp b/ydb/core/cms/cms_tx_load_state.cpp
index 5df136c557..62a8ad3019 100644
--- a/ydb/core/cms/cms_tx_load_state.cpp
+++ b/ydb/core/cms/cms_tx_load_state.cpp
@@ -135,13 +135,17 @@ public:
TString requestId = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::RequestID>();
TString owner = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::Owner>();
bool hasSingleCompositeActionGroup = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::HasSingleCompositeActionGroup>();
+ ui64 createTime = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::CreateTime>();
+ ui64 lastRefreshTime = maintenanceTasksRowset.GetValue<Schema::MaintenanceTasks::LastRefreshTime>();
state->MaintenanceRequests.emplace(requestId, taskId);
state->MaintenanceTasks.emplace(taskId, TTaskInfo{
.TaskId = taskId,
.RequestId = requestId,
.Owner = owner,
- .HasSingleCompositeActionGroup = hasSingleCompositeActionGroup
+ .HasSingleCompositeActionGroup = hasSingleCompositeActionGroup,
+ .CreateTime = TInstant::MicroSeconds(createTime),
+ .LastRefreshTime = TInstant::MicroSeconds(lastRefreshTime)
});
LOG_DEBUG(ctx, NKikimrServices::CMS, "Loaded maintenance task %s mapped to request %s",
diff --git a/ydb/core/cms/cms_tx_store_permissions.cpp b/ydb/core/cms/cms_tx_store_permissions.cpp
index b85160bac4..fd6086c3d6 100644
--- a/ydb/core/cms/cms_tx_store_permissions.cpp
+++ b/ydb/core/cms/cms_tx_store_permissions.cpp
@@ -31,6 +31,7 @@ public:
const auto &rec = Response->Get<TEvCms::TEvPermissionResponse>()->Record;
+ auto now = ctx.Now();
if (MaintenanceTaskId) {
Y_ABORT_UNLESS(Scheduled);
@@ -39,13 +40,25 @@ public:
.TaskId = *MaintenanceTaskId,
.RequestId = Scheduled->RequestId,
.Owner = Scheduled->Owner,
- .HasSingleCompositeActionGroup = !Scheduled->Request.GetPartialPermissionAllowed()
+ .HasSingleCompositeActionGroup = !Scheduled->Request.GetPartialPermissionAllowed(),
+ .CreateTime = now,
+ .LastRefreshTime = now
});
db.Table<Schema::MaintenanceTasks>().Key(*MaintenanceTaskId).Update(
NIceDb::TUpdate<Schema::MaintenanceTasks::RequestID>(Scheduled->RequestId),
NIceDb::TUpdate<Schema::MaintenanceTasks::Owner>(Scheduled->Owner),
- NIceDb::TUpdate<Schema::MaintenanceTasks::HasSingleCompositeActionGroup>(!Scheduled->Request.GetPartialPermissionAllowed())
+ NIceDb::TUpdate<Schema::MaintenanceTasks::HasSingleCompositeActionGroup>(!Scheduled->Request.GetPartialPermissionAllowed()),
+ NIceDb::TUpdate<Schema::MaintenanceTasks::CreateTime>(now.MicroSeconds()),
+ NIceDb::TUpdate<Schema::MaintenanceTasks::LastRefreshTime>(now.MicroSeconds())
+ );
+ } else if (Scheduled != nullptr && Self->State->MaintenanceRequests.contains(Scheduled->RequestId)) {
+ const auto& taskId = Self->State->MaintenanceRequests[Scheduled->RequestId];
+ auto& task = Self->State->MaintenanceTasks.at(taskId);
+
+ task.LastRefreshTime = now;
+ db.Table<Schema::MaintenanceTasks>().Key(taskId).Update(
+ NIceDb::TUpdate<Schema::MaintenanceTasks::LastRefreshTime>(now.MicroSeconds())
);
}
diff --git a/ydb/core/cms/cms_ut_common.h b/ydb/core/cms/cms_ut_common.h
index 9e502d59e2..f06fe90b79 100644
--- a/ydb/core/cms/cms_ut_common.h
+++ b/ydb/core/cms/cms_ut_common.h
@@ -407,6 +407,42 @@ public:
return CheckResetMarker(req, code);
}
+ Ydb::Maintenance::MaintenanceTaskResult CheckMaintenanceTaskRefresh(
+ const TString &taskUid,
+ Ydb::StatusIds::StatusCode code)
+ {
+ auto ev = std::make_unique<NCms::TEvCms::TEvRefreshMaintenanceTaskRequest>();
+
+ auto *req = ev->Record.MutableRequest();
+ req->set_task_uid(taskUid);
+
+ SendToPipe(CmsId, Sender, ev.release(), 0, GetPipeConfigWithRetries());
+ TAutoPtr<IEventHandle> handle;
+ auto reply = GrabEdgeEventRethrow<NCms::TEvCms::TEvMaintenanceTaskResponse>(handle);
+
+ const auto &rec = reply->Record;
+ UNIT_ASSERT_VALUES_EQUAL(rec.GetStatus(), code);
+ return rec.GetResult();
+ }
+
+ Ydb::Maintenance::GetMaintenanceTaskResult CheckMaintenanceTaskGet(
+ const TString &taskUid,
+ Ydb::StatusIds::StatusCode code)
+ {
+ auto ev = std::make_unique<NCms::TEvCms::TEvGetMaintenanceTaskRequest>();
+
+ auto *req = ev->Record.MutableRequest();
+ req->set_task_uid(taskUid);
+
+ SendToPipe(CmsId, Sender, ev.release(), 0, GetPipeConfigWithRetries());
+ TAutoPtr<IEventHandle> handle;
+ auto reply = GrabEdgeEventRethrow<NCms::TEvCms::TEvGetMaintenanceTaskResponse>(handle);
+
+ const auto &rec = reply->Record;
+ UNIT_ASSERT_VALUES_EQUAL(rec.GetStatus(), code);
+ return rec.GetResult();
+ }
+
template <typename... Ts>
Ydb::Maintenance::MaintenanceTaskResult CheckMaintenanceTaskCreate(
const TString &taskUid,
diff --git a/ydb/core/cms/scheme.h b/ydb/core/cms/scheme.h
index bd9a4f38f2..672bac94fe 100644
--- a/ydb/core/cms/scheme.h
+++ b/ydb/core/cms/scheme.h
@@ -135,9 +135,18 @@ struct Schema : NIceDb::Schema {
struct RequestID : Column<2, NScheme::NTypeIds::Utf8> {};
struct Owner : Column<3, NScheme::NTypeIds::Utf8> {};
struct HasSingleCompositeActionGroup : Column<4, NScheme::NTypeIds::Bool> {};
+ struct CreateTime : Column<5, NScheme::NTypeIds::Uint64> {};
+ struct LastRefreshTime : Column<6, NScheme::NTypeIds::Uint64> {};
using TKey = TableKey<TaskID>;
- using TColumns = TableColumns<TaskID, RequestID, Owner, HasSingleCompositeActionGroup>;
+ using TColumns = TableColumns<
+ TaskID,
+ RequestID,
+ Owner,
+ HasSingleCompositeActionGroup,
+ CreateTime,
+ LastRefreshTime
+ >;
};
using TTables = SchemaTables<Param, Permission, Request, WalleTask, Notification, NodeTenant,
diff --git a/ydb/public/api/protos/draft/ydb_maintenance.proto b/ydb/public/api/protos/draft/ydb_maintenance.proto
index 371f35db07..a77de97337 100644
--- a/ydb/public/api/protos/draft/ydb_maintenance.proto
+++ b/ydb/public/api/protos/draft/ydb_maintenance.proto
@@ -182,6 +182,10 @@ message MaintenanceTaskResult {
repeated ActionGroupStates action_group_states = 2;
// Try again after this deadline. Specified if there are no performed actions.
optional google.protobuf.Timestamp retry_after = 3;
+ // The time when the mainteance task was created.
+ google.protobuf.Timestamp create_time = 4;
+ // The last time when the mainteance task was refreshed. Initially equals to create_time.
+ google.protobuf.Timestamp last_refresh_time = 5;
}
message MaintenanceTaskResponse {
@@ -197,6 +201,10 @@ message GetMaintenanceTaskRequest {
message GetMaintenanceTaskResult {
MaintenanceTaskOptions task_options = 1;
repeated ActionGroupStates action_group_states = 2;
+ // The time when the mainteance task was created.
+ google.protobuf.Timestamp create_time = 3;
+ // The last time when the mainteance task was refreshed. Initially equals to create_time.
+ google.protobuf.Timestamp last_refresh_time = 4;
}
message GetMaintenanceTaskResponse {