Skip to content
Merged
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
47 changes: 40 additions & 7 deletions ydb/apps/dstool/lib/dstool_cmd_group_decommit.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
import ydb.apps.dstool.lib.common as common
import ydb.core.protos.blob_depot_config_pb2 as blob_depot_config
import sys
import time

description = 'Decommit physical group'


def add_options(p):
common.add_group_ids_option(p, required=True)
g = p.add_mutually_exclusive_group(required=True)
g.add_argument('--hive-id', type=int, help='tablet id of containing hive')
g.add_argument('--database', type=str, help='database path of containing hive')
g.add_argument('--database', type=str, required=True, help='database path for storage pools with groups being decommitted')
p.add_argument('--log-channel-sp', type=str, metavar='POOL_NAME', help='channel 0 specifier')
p.add_argument('--snapshot-channel-sp', type=str, metavar='POOL_NAME', help='channel 1 specifier (defaults to channel 0)')
p.add_argument('--data-channel-sp', type=str, metavar='POOL_NAME[*COUNT]', nargs='*', help='data channel specifier')
p.add_argument('--wait', action='store_true', help='wait until group decommission is started')


def do(args):
request = common.create_bsc_request(args)
cmd = request.Command.add().DecommitGroups
cmd.GroupIds.extend(args.group_ids)
if args.hive_id is not None:
cmd.HiveId = args.hive_id
if args.database is not None:
cmd.Database = args.database
cmd.Database = args.database

if args.log_channel_sp or args.snapshot_channel_sp or args.data_channel_sp:
if args.log_channel_sp is None:
Expand All @@ -44,4 +42,39 @@ def do(args):
cmd.ChannelProfiles.add(StoragePoolName=pool_name, ChannelKind=blob_depot_config.TChannelKind.Data, Count=count)

response = common.invoke_bsc_request(request)
common.print_request_result(args, request, response)

if args.wait and response.Success:
groups_of_interest = set(args.group_ids)

while groups_of_interest:
time.sleep(1)
base_config_and_storage_pools = common.fetch_base_config_and_storage_pools(virtualGroupsOnly=True)
base_config = base_config_and_storage_pools['BaseConfig']
group_map = common.build_group_map(base_config)
for group_id in list(groups_of_interest):
if group_id not in group_map:
print(f'Group {group_id} is missing in group list', file=sys.stderr)
groups_of_interest.remove(group_id)
continue
group = group_map[group_id]
if group.VirtualGroupInfo is None:
print(f'Group {group_id} is not virtual group', file=sys.stderr)
elif group.VirtualGroupInfo.State == common.EVirtualGroupState.WORKING:
pass
elif group.VirtualGroupInfo.State == common.EVirtualGroupState.CREATE_FAILED:
print(f'Group {group_id} decommission failed to start: {group.VirtualGroupInfo.ErrorReason}, canceling', file=sys.stderr)
request = common.kikimr_bsconfig.TConfigRequest()
cmd = request.Command.add().CancelVirtualGroup
cmd.GroupId = group_id
response = common.invoke_bsc_request(request)
if not response.Success:
print(f'Failed to cancel decommission for group {group_id}', file=sys.stderr)
elif group.VirtualGroupInfo.State == common.EVirtualGroupState.DELETING:
print(f'Group {group_id} is being deleted', file=sys.stderr)
elif group.VirtualGroupInfo.State == common.EVirtualGroupState.NEW:
continue
else:
print(f'Group {group_id} has unexpected virtual group state', file=sys.stderr)
groups_of_interest.remove(group_id)
else:
common.print_request_result(args, request, response)
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void DecommitGroup(TBlobDepotTestEnvironment& tenv, ui32 groupId) {

auto *cmd = request.AddCommand()->MutableDecommitGroups();
cmd->AddGroupIds(groupId);
cmd->SetHiveId(tenv.Env->Runtime->GetDomainsInfo()->GetHive());
cmd->SetDatabase(TStringBuilder() << '/' << tenv.Env->Runtime->GetDomainsInfo()->GetDomain()->Name);
auto *prof = cmd->AddChannelProfiles();
prof->SetStoragePoolName(blobDepotPool);
prof->SetCount(2);
Expand Down
27 changes: 14 additions & 13 deletions ydb/core/mind/bscontroller/virtual_group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,17 @@ namespace NKikimr::NBsController {
}

void TBlobStorageController::TConfigState::ExecuteStep(const NKikimrBlobStorage::TDecommitGroups& cmd, TStatus& /*status*/) {
if (cmd.GetHiveDesignatorCase() == NKikimrBlobStorage::TDecommitGroups::HIVEDESIGNATOR_NOT_SET) {
throw TExError() << "TDecommitGroups.HiveId/Database is not specified";
if (!cmd.HasDatabase()) {
throw TExError() << "TDecommitGroups.Database is not specified, but it is mandatory";
}

for (const ui32 groupId : cmd.GetGroupIds()) {
TGroupInfo *group = Groups.FindForUpdate(TGroupId::FromValue(groupId));
if (!group) {
throw TExGroupNotFound(groupId);
} else if (group->DecommitStatus != NKikimrBlobStorage::TGroupDecommitStatus::NONE) {
if (cmd.HasHiveId() && group->HiveId && *group->HiveId != cmd.GetHiveId()) {
throw TExError() << "different hive specified for decommitting group" << TErrorParams::GroupId(groupId);
} else if (cmd.HasDatabase() && group->Database && *group->Database != cmd.GetDatabase()) {
if (group->Database != cmd.GetDatabase()) {
throw TExError() << "different database specified for decommitting group" << TErrorParams::GroupId(groupId);
} else if (cmd.HasHiveId() != group->HiveId.Defined() && cmd.HasDatabase() != group->Database.Defined()) {
throw TExError() << "different hive designator specified for decommitting group" << TErrorParams::GroupId(groupId);
}
// group is already being decommitted -- make this operation idempotent
continue;
Expand All @@ -131,8 +127,7 @@ namespace NKikimr::NBsController {

group->DecommitStatus = NKikimrBlobStorage::TGroupDecommitStatus::PENDING;
group->VirtualGroupState = NKikimrBlobStorage::EVirtualGroupState::NEW;
group->HiveId = cmd.HasHiveId() ? MakeMaybe(cmd.GetHiveId()) : Nothing();
group->Database = cmd.HasDatabase() ? MakeMaybe(cmd.GetDatabase()) : Nothing();
group->Database = cmd.GetDatabase();
group->NeedAlter = true;
GroupFailureModelChanged.insert(group->ID);
group->CalculateGroupStatus();
Expand Down Expand Up @@ -428,24 +423,27 @@ namespace NKikimr::NBsController {
ui64 RootHiveId = 0;
bool TenantHiveInvalidated = false;
bool TenantHiveInvalidateInProgress = false;
bool IsDecommittingGroup = false;

void HiveCreate(TGroupInfo *group) {
auto& config = GetConfig(group);
IsDecommittingGroup = config.GetIsDecommittingGroup();

if (config.HasTabletId()) {
ConfigureBlobDepot();
} else if (!group->HiveId) {
HiveResolve(group);
} else if (TenantHiveInvalidateInProgress && TenantHivePipeId) {
// tenant hive storage pool invalidation still in progress, wait
} else if (config.GetIsDecommittingGroup() && config.HasTenantHiveId() && !TenantHiveInvalidated) {
} else if (IsDecommittingGroup && config.HasTenantHiveId() && !TenantHiveInvalidated) {
TenantHivePipeId = Register(NTabletPipe::CreateClient(SelfId(), config.GetTenantHiveId(),
NTabletPipe::TClientRetryPolicy::WithRetries()));
HiveInvalidateGroups(TenantHivePipeId, group);
TenantHiveInvalidateInProgress = true;
} else if (!HivePipeId) {
Y_ABORT_UNLESS(group->HiveId);
HivePipeId = Register(NTabletPipe::CreateClient(SelfId(), *group->HiveId, NTabletPipe::TClientRetryPolicy::WithRetries()));
if (config.GetIsDecommittingGroup()) {
if (IsDecommittingGroup) {
HiveInvalidateGroups(HivePipeId, group);
}
} else {
Expand Down Expand Up @@ -487,7 +485,10 @@ namespace NKikimr::NBsController {
(Result, response.ToString(*AppData()->TypeRegistry)));

if (item.Status != NSchemeCache::TSchemeCacheNavigate::EStatus::Ok || !domainInfo || !item.DomainDescription) {
return CreateFailed(TStringBuilder() << "failed to resolve Hive -- erroneous reply from SchemeCache or not a domain");
return CreateFailed(TStringBuilder() << "failed to resolve Hive -- erroneous reply from SchemeCache or not a domain"
<< " Response# " << response.ToString(*AppData()->TypeRegistry)
<< " DomainInfo# " << static_cast<bool>(domainInfo)
<< " DomainDescription# " << static_cast<bool>(item.DomainDescription));
} else if (const auto& params = domainInfo->Params; !params.HasHive() && !RootHiveId) {
return CreateFailed("failed to resolve Hive -- no Hive in SchemeCache reply");
} else {
Expand Down Expand Up @@ -517,7 +518,7 @@ namespace NKikimr::NBsController {
}
}

const ui64 hiveId = params.HasHive() ? params.GetHive() : RootHiveId;
const ui64 hiveId = params.HasHive() && !IsDecommittingGroup ? params.GetHive() : RootHiveId;
if (!hiveId) {
return CreateFailed("failed to resolve Hive -- Hive is zero");
}
Expand Down
6 changes: 3 additions & 3 deletions ydb/docs/ru/core/maintenance/manual/blobdepot_decommit.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
Для запуска декомиссии выполняется команда BS\_CONTROLLER, в которой нужно указать список декомиссуемых групп, а также номер таблетки Hive, которая будет управлять блобовницами декомиссуемых групп. Также можно указать список пулов, в которых блобовница будет хранить свои данные. Если этот список не указан, то BS\_CONTROLLER автоматически выбирает для хранения данных те же пулы, в которых располагаются декомиссуемые группы, а число каналов данных делается равным числу физических групп в этих пулах (но не более 250 штук).

```bash
dstool -e ... --direct group decommit --group-ids 2181038080 --database=/Root/db1 --hive-id=72057594037968897
dstool -e ... --direct group decommit --group-ids 2181038080 --database=/Root/db1 --wait
```

Параметры командной строки:

* --wait дождаться запуска декомиссии; в случае возникновения ошибки запуска ошибка выводится на экран, декомиссия отменяется автоматически (только при указании этой опции);
* --group-ids GROUP\_ID GROUP\_ID список групп, для которых можно провести декомиссию;
* --database=DB указать тенант, в котором нужно делать декомиссию;
* --hive-id=N явно указать номер таблетки Hive, которая будет управлять данной блобовницей; нельзя указывать идентификатор Hive того тенанта, которому принадлежат пулы с декомиссуемыми группами, т.к. этот Hive может хранить свои данные поверх группы, которая управляется блобовницей, что приведёт к циклической зависимости; рекомендуется указывать корневой Hive;
* --database=DB указать тенант, в котором нужно делать декомиссию (или домен, если декомиссия делается для групп внутри домена);
* --log-channel-sp=POOL\_NAME название пула, в котором будет размещён канал 0 таблетки блобовницы;
* --snapshot-channel-sp=POOL\_NAME название пула, в котором будет размещён кана 1 таблетки блобовницы; если не указан, то используется значение из --log-channel-sp;
* --data-channel-sp=POOL\_NAME[\*COUNT] название пула, в котором размещаются каналы данных; если указан параметр COUNT (после знака "звёздочка"), то создаётся COUNT каналов данных в указанном пуле.
Expand Down
Loading