diff options
-rw-r--r-- | ydb/core/cms/console/console__alter_tenant.cpp | 11 | ||||
-rw-r--r-- | ydb/core/cms/console/console__create_tenant.cpp | 2 | ||||
-rw-r--r-- | ydb/core/cms/console/console__scheme.h | 3 | ||||
-rw-r--r-- | ydb/core/cms/console/console_tenants_manager.cpp | 24 | ||||
-rw-r--r-- | ydb/core/cms/console/console_tenants_manager.h | 17 | ||||
-rw-r--r-- | ydb/core/cms/console/console_ut_tenants.cpp | 88 |
6 files changed, 126 insertions, 19 deletions
diff --git a/ydb/core/cms/console/console__alter_tenant.cpp b/ydb/core/cms/console/console__alter_tenant.cpp index dc44c25082..c0011cb68b 100644 --- a/ydb/core/cms/console/console__alter_tenant.cpp +++ b/ydb/core/cms/console/console__alter_tenant.cpp @@ -121,9 +121,14 @@ public: for (auto &unit : rec.storage_units_to_add()) { auto &kind = unit.unit_kind(); - if (Tenant->AreResourcesShared && !Tenant->StoragePools.contains(kind)) + if (Tenant->StoragePools.contains(kind)) { + if (Tenant->StoragePools.at(kind)->Borrowed) + return Error(Ydb::StatusIds::BAD_REQUEST, + Sprintf("Pool '%s' is borrowed, cannot alter", kind.data()), ctx); + } else if (Tenant->AreResourcesShared) { return Error(Ydb::StatusIds::UNSUPPORTED, Sprintf("Database '%s' is shared, cannot add new storage units", path.data()), ctx); + } if (Tenant->SharedDomainId) return Error(Ydb::StatusIds::BAD_REQUEST, @@ -235,7 +240,9 @@ public: auto &kind = pr.first; auto size = pr.second; if (Tenant->StoragePools.contains(kind)) { - pool = new TStoragePool(*Tenant->StoragePools.at(kind)); + auto cur = Tenant->StoragePools.at(kind); + Y_VERIFY(!cur->Borrowed); + pool = new TStoragePool(*cur); pool->AddRequiredGroups(size); pool->State = TStoragePool::NOT_UPDATED; } else { diff --git a/ydb/core/cms/console/console__create_tenant.cpp b/ydb/core/cms/console/console__create_tenant.cpp index 77d8166d54..2f8676de35 100644 --- a/ydb/core/cms/console/console__create_tenant.cpp +++ b/ydb/core/cms/console/console__create_tenant.cpp @@ -183,7 +183,7 @@ public: auto poolName = Tenant->MakeStoragePoolName(kind); auto &config = Self->Domain->StoragePoolTypes.at(kind); - TStoragePool::TPtr pool = new TStoragePool(poolName, kind, size, config); + TStoragePool::TPtr pool = new TStoragePool(poolName, size, kind, config, false); Tenant->StoragePools.emplace(std::make_pair(kind, pool)); } } diff --git a/ydb/core/cms/console/console__scheme.h b/ydb/core/cms/console/console__scheme.h index 29eb6c3035..c4b32b5294 100644 --- a/ydb/core/cms/console/console__scheme.h +++ b/ydb/core/cms/console/console__scheme.h @@ -63,9 +63,10 @@ struct Schema : NIceDb::Schema { struct Config : Column<3, NScheme::NTypeIds::Utf8> {}; struct AllocatedNumGroups : Column<4, NScheme::NTypeIds::Uint32> {}; struct State : Column<5, NScheme::NTypeIds::Uint32> {}; + struct Borrowed : Column<6, NScheme::NTypeIds::Bool> {}; using TKey = TableKey<Tenant, PoolType>; - using TColumns = TableColumns<Tenant, PoolType, Config, AllocatedNumGroups, State>; + using TColumns = TableColumns<Tenant, PoolType, Config, AllocatedNumGroups, State, Borrowed>; }; struct TenantUnits : Table<4> { diff --git a/ydb/core/cms/console/console_tenants_manager.cpp b/ydb/core/cms/console/console_tenants_manager.cpp index 0db3f5dced..1853394eb8 100644 --- a/ydb/core/cms/console/console_tenants_manager.cpp +++ b/ydb/core/cms/console/console_tenants_manager.cpp @@ -1719,7 +1719,7 @@ TTenantsManager::TStoragePool::TPtr TTenantsManager::MakeStoragePool(TTenant::TP auto poolName = tenant->MakeStoragePoolName(kind); auto &config = Domain->StoragePoolTypes.at(kind); - TStoragePool::TPtr pool = new TStoragePool(poolName, kind, size, config); + TStoragePool::TPtr pool = new TStoragePool(poolName, size, kind, config, false); if (tenant->HasSubDomainKey()) pool->SetScopeId(tenant->DomainId); @@ -1774,8 +1774,20 @@ void TTenantsManager::DeleteTenantPools(TTenant::TPtr tenant, const TActorContex } for (auto &pr : tenant->StoragePools) { - if (pr.second->State != TStoragePool::DELETED) + if (pr.second->State == TStoragePool::DELETED) { + continue; + } + + if (pr.second->Borrowed) { + BLOG_D("Mark borrowed pool as deleted" + << ": tenant# " << tenant->Path + << ", pool# " << pr.second->Config.GetName()); + + pr.second->Worker = SelfId(); + ctx.Send(SelfId(), new TTenantsManager::TEvPrivate::TEvPoolDeleted(tenant, pr.second)); + } else { pr.second->Worker = ctx.RegisterWithSameMailbox(new TPoolManip(SelfId(), Domain, tenant, pr.second, TPoolManip::DEALLOCATE)); + } } } @@ -2451,23 +2463,24 @@ bool TTenantsManager::DbLoadState(TTransactionContext &txc, const TActorContext while (!poolRowset.EndOfSet()) { TString path = poolRowset.GetValue<Schema::TenantPools::Tenant>(); - TString type = poolRowset.GetValue<Schema::TenantPools::PoolType>(); + TString kind = poolRowset.GetValue<Schema::TenantPools::PoolType>(); TString configVal = poolRowset.GetValue<Schema::TenantPools::Config>(); ui32 allocated = poolRowset.GetValue<Schema::TenantPools::AllocatedNumGroups>(); ui32 stateVal = poolRowset.GetValue<Schema::TenantPools::State>(); + bool borrowed = poolRowset.GetValueOrDefault<Schema::TenantPools::Borrowed>(false); TStoragePool::EState state = static_cast<TStoragePool::EState>(stateVal); NKikimrBlobStorage::TDefineStoragePool config; Y_PROTOBUF_SUPPRESS_NODISCARD config.ParseFromArray(configVal.data(), configVal.size()); - TStoragePool::TPtr pool = new TStoragePool(type, config); + TStoragePool::TPtr pool = new TStoragePool(kind, config, borrowed); pool->AllocatedNumGroups = allocated; pool->State = state; auto tenant = GetTenant(path); Y_VERIFY_DEBUG(tenant, "loaded pool for unknown tenant %s", path.data()); if (tenant) { - tenant->StoragePools[type] = pool; + tenant->StoragePools[kind] = pool; Counters.Inc(pool->Kind, COUNTER_REQUESTED_STORAGE_UNITS, pool->GetGroups()); Counters.Inc(pool->Kind, COUNTER_ALLOCATED_STORAGE_UNITS, pool->AllocatedNumGroups); @@ -3085,7 +3098,6 @@ void TTenantsManager::Handle(TEvConsole::TEvRemoveTenantRequest::TPtr &ev, const { Counters.Inc(COUNTER_REMOVE_REQUESTS); - auto path = CanonizePath(ev->Get()->Record.GetRequest().path()); TxProcessor->ProcessTx(CreateTxRemoveTenant(ev), ctx); } diff --git a/ydb/core/cms/console/console_tenants_manager.h b/ydb/core/cms/console/console_tenants_manager.h index a21615dd62..3a769a9d56 100644 --- a/ydb/core/cms/console/console_tenants_manager.h +++ b/ydb/core/cms/console/console_tenants_manager.h @@ -280,18 +280,26 @@ public: DELETED, }; - TStoragePool(const TString &kind, const NKikimrBlobStorage::TDefineStoragePool &config) + TStoragePool( + const TString &kind, + const NKikimrBlobStorage::TDefineStoragePool &config, + bool borrowed) : Kind(kind) , Config(config) , AllocatedNumGroups(0) , State(NOT_ALLOCATED) + , Borrowed(borrowed) { Config.SetKind(kind); } - TStoragePool(const TString &name, const TString &kind, ui64 size, - const NKikimrBlobStorage::TDefineStoragePool &config) - : TStoragePool(kind, config) + TStoragePool( + const TString &name, + ui64 size, + const TString &kind, + const NKikimrBlobStorage::TDefineStoragePool &config, + bool borrowed) + : TStoragePool(kind, config, borrowed) { Config.SetName(name); Config.SetNumGroups(size); @@ -337,6 +345,7 @@ public: NKikimrBlobStorage::TDefineStoragePool Config; ui64 AllocatedNumGroups; EState State; + bool Borrowed; TString Issue; TActorId Worker; size_t GroupFitErrors = 0; diff --git a/ydb/core/cms/console/console_ut_tenants.cpp b/ydb/core/cms/console/console_ut_tenants.cpp index 57e4820af7..f2709dbf6e 100644 --- a/ydb/core/cms/console/console_ut_tenants.cpp +++ b/ydb/core/cms/console/console_ut_tenants.cpp @@ -385,8 +385,7 @@ void CheckTenantGeneration(TTenantTestRuntime &runtime, UNIT_ASSERT_VALUES_EQUAL(status.generation(), generation); } -void CheckPoolScope(TTenantTestRuntime &runtime, - const TString &name) +NKikimrBlobStorage::TEvControllerConfigResponse ReadPoolState(TTenantTestRuntime &runtime, const TString &name) { auto request = MakeHolder<TEvBlobStorage::TEvControllerConfigRequest>(); auto &read = *request->Record.MutableRequest()->AddCommand()->MutableReadStoragePool(); @@ -397,9 +396,14 @@ void CheckPoolScope(TTenantTestRuntime &runtime, pipeConfig.RetryPolicy = NTabletPipe::TClientRetryPolicy::WithRetries(); runtime.SendToPipe(MakeBSControllerID(0), runtime.Sender, request.Release(), 0, pipeConfig); - TAutoPtr<IEventHandle> handle; - auto reply = runtime.GrabEdgeEventRethrow<TEvBlobStorage::TEvControllerConfigResponse>(handle); - const auto &scope = reply->Record.GetResponse().GetStatus(0).GetStoragePool(0).GetScopeId(); + auto ev = runtime.GrabEdgeEventRethrow<TEvBlobStorage::TEvControllerConfigResponse>(runtime.Sender); + return ev->Get()->Record; +} + +void CheckPoolScope(TTenantTestRuntime &runtime, const TString &name) +{ + auto response = ReadPoolState(runtime, name); + const auto &scope = response.GetResponse().GetStatus(0).GetStoragePool(0).GetScopeId(); UNIT_ASSERT(scope.GetX1() != 0); UNIT_ASSERT(scope.GetX2() != 0); } @@ -440,6 +444,27 @@ void SendCaptured(TTenantTestRuntime &runtime, TVector<TAutoPtr<IEventHandle>> & events.clear(); } +void LocalMiniKQL(TTenantTestRuntime& runtime, ui64 tabletId, const TString& query) { + auto request = MakeHolder<TEvTablet::TEvLocalMKQL>(); + request->Record.MutableProgram()->MutableProgram()->SetText(query); + ForwardToTablet(runtime, tabletId, runtime.Sender, request.Release()); + + auto ev = runtime.GrabEdgeEventRethrow<TEvTablet::TEvLocalMKQLResponse>(runtime.Sender); + const auto& response = ev->Get()->Record; + + UNIT_ASSERT_VALUES_EQUAL(response.GetStatus(), NKikimrProto::OK); +} + +void MakePoolBorrowed(TTenantTestRuntime& runtime, const TString& tenant, const TString& pool) { + LocalMiniKQL(runtime, MakeConsoleID(0), Sprintf(R"( + ( + (let key '('('Tenant (Utf8 '"%s")) '('PoolType (Utf8 '"%s")))) + (let row '('('Borrowed (Bool '1)))) + (return (AsList (UpdateRow 'TenantPools key row))) + ) + )", tenant.c_str(), pool.c_str())); +} + } // anonymous namespace Y_UNIT_TEST_SUITE(TConsoleTxProcessorTests) { @@ -1159,6 +1184,59 @@ Y_UNIT_TEST_SUITE(TConsoleTests) { RunTestAlterUnknownTenant(runtime); } + Y_UNIT_TEST(TestAlterBorrowedStorage) { + TTenantTestRuntime runtime(DefaultConsoleTestConfig(), {}, true); + + // create tenant + CheckCreateTenant(runtime, Ydb::StatusIds::SUCCESS, + TCreateTenantRequest(TENANT1_1_NAME, TCreateTenantRequest::EType::Common) + .WithPools({{"hdd", 1}}) + .WithSlots(SLOT1_TYPE, ZONE1, 1)); + + CheckTenantStatus(runtime, TENANT1_1_NAME, Ydb::StatusIds::SUCCESS, + Ydb::Cms::GetDatabaseStatusResult::RUNNING, + {{"hdd", 1, 1}}, {}, + SLOT1_TYPE, ZONE1, 1, 1); + + // mark pool as borrowed + MakePoolBorrowed(runtime, TENANT1_1_NAME, "hdd"); + // restart to changes take effect + RestartConsole(runtime); + + // trying to extend pool + CheckAlterTenantPools(runtime, TENANT1_1_NAME, Ydb::StatusIds::BAD_REQUEST, {{"hdd", 1}}, {}); + } + + Y_UNIT_TEST(TestRemoveTenantWithBorrowedStorageUnits) { + TTenantTestRuntime runtime(DefaultConsoleTestConfig(), {}, true); + runtime.SetLogPriority(NKikimrServices::CMS_TENANTS, NActors::NLog::PRI_DEBUG); + + // create tenant + CheckCreateTenant(runtime, Ydb::StatusIds::SUCCESS, + TCreateTenantRequest(TENANT1_1_NAME, TCreateTenantRequest::EType::Common) + .WithPools({{"hdd", 1}}) + .WithSlots(SLOT1_TYPE, ZONE1, 1)); + + CheckTenantStatus(runtime, TENANT1_1_NAME, Ydb::StatusIds::SUCCESS, + Ydb::Cms::GetDatabaseStatusResult::RUNNING, + {{"hdd", 1, 1}}, {}, + SLOT1_TYPE, ZONE1, 1, 1); + + // mark pool as borrowed + MakePoolBorrowed(runtime, TENANT1_1_NAME, "hdd"); + // restart to changes take effect + RestartConsole(runtime); + + // remove tenant + CheckRemoveTenant(runtime, TENANT1_1_NAME, Ydb::StatusIds::SUCCESS); + CheckTenantStatus(runtime, TENANT1_1_NAME, Ydb::StatusIds::NOT_FOUND, + Ydb::Cms::GetDatabaseStatusResult::STATE_UNSPECIFIED, {}, {}); + + // check pool (should be alive) + auto poolState = ReadPoolState(runtime, TENANT1_1_NAME + ":hdd"); + UNIT_ASSERT_VALUES_EQUAL(poolState.GetResponse().GetStatus(0).StoragePoolSize(), 1); + } + Y_UNIT_TEST(TestAlterStorageUnitsOfSharedTenant) { TTenantTestRuntime runtime(DefaultConsoleTestConfig(), {}, true); // create shared tenant |