diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2023-05-15 14:08:48 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2023-05-15 14:08:48 +0300 |
commit | ac809add0f42f933c8a966c3309997d8563aa168 (patch) | |
tree | 016bd4489b23b6e2237875b5068b5b32488d09b0 | |
parent | 6247839c1bd9fd6a2d540ebba3eb28b42f7e2b4f (diff) | |
download | ydb-ac809add0f42f933c8a966c3309997d8563aa168.tar.gz |
Intermediate changes
42 files changed, 392 insertions, 173 deletions
diff --git a/ydb/core/base/blobstorage.h b/ydb/core/base/blobstorage.h index 42e27b391f2..781207a7564 100644 --- a/ydb/core/base/blobstorage.h +++ b/ydb/core/base/blobstorage.h @@ -1198,6 +1198,7 @@ struct TEvBlobStorage { TVector<TPartMapItem> PartMap; bool Keep = false; bool DoNotKeep = false; + bool LooksLikePhantom = false; // filled only when PhantomCheck is true TResponse() : Status(NKikimrProto::UNKNOWN) diff --git a/ydb/core/blobstorage/base/blobstorage_events.h b/ydb/core/blobstorage/base/blobstorage_events.h index f4921e65d60..14b07bf363b 100644 --- a/ydb/core/blobstorage/base/blobstorage_events.h +++ b/ydb/core/blobstorage/base/blobstorage_events.h @@ -560,12 +560,15 @@ namespace NKikimr { ui32 PDiskId; ui32 VSlotId; NKikimrBlobStorage::EVDiskStatus Status; + bool OnlyPhantomsRemain; - TEvStatusUpdate(ui32 nodeId, ui32 pdiskId, ui32 vslotId, NKikimrBlobStorage::EVDiskStatus status) + TEvStatusUpdate(ui32 nodeId, ui32 pdiskId, ui32 vslotId, NKikimrBlobStorage::EVDiskStatus status, + bool onlyPhantomsRemain) : NodeId(nodeId) , PDiskId(pdiskId) , VSlotId(vslotId) , Status(status) + , OnlyPhantomsRemain(onlyPhantomsRemain) {} }; diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h b/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h index 3108cf0b691..d5a265b396d 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h @@ -85,6 +85,7 @@ struct TBlobState { NWilson::TSpan *Span = nullptr; bool Keep = false; bool DoNotKeep = false; + bool LooksLikePhantom = false; void Init(const TLogoBlobID &id, const TBlobStorageGroupInfo &Info); void AddNeeded(ui64 begin, ui64 size); diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_get_impl.cpp b/ydb/core/blobstorage/dsproxy/dsproxy_get_impl.cpp index e69b245aa04..d2343acc539 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_get_impl.cpp +++ b/ydb/core/blobstorage/dsproxy/dsproxy_get_impl.cpp @@ -42,11 +42,15 @@ void TGetImpl::PrepareReply(NKikimrProto::EReplyStatus status, TString errorReas outResponse.PartMap = blobState.PartMap; outResponse.Keep = blobState.Keep; outResponse.DoNotKeep = blobState.DoNotKeep; + outResponse.LooksLikePhantom = blobState.LooksLikePhantom; + if (blobState.WholeSituation == TBlobState::ESituation::Absent) { bool okay = true; // extra validation code for phantom logic if (PhantomCheck) { + outResponse.LooksLikePhantom = true; + TSubgroupPartLayout possiblyWritten; for (ui32 idxInSubgroup = 0; idxInSubgroup < blobState.Disks.size(); ++idxInSubgroup) { diff --git a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h index c6476c941fb..a065f01362a 100644 --- a/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h +++ b/ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h @@ -205,6 +205,7 @@ namespace NKikimr { // we haven't requested anything, but there is no required data in buffer, so blob is lost R_LOG_WARN_SX(logCtx, "BPG48", "missing blob# " << state.Id.ToString() << " state# " << state.ToString()); state.WholeSituation = TBlobState::ESituation::Absent; + state.LooksLikePhantom = true; if (PhantomCheck || info.GetQuorumChecker().CheckQuorumForSubgroup(possiblyWritten)) { // this blob is either: // 1. Has full quorum of Lost & Error replies diff --git a/ydb/core/blobstorage/nodewarden/node_warden_impl.cpp b/ydb/core/blobstorage/nodewarden/node_warden_impl.cpp index 3dcb9d6b85f..2359bd8e3e3 100644 --- a/ydb/core/blobstorage/nodewarden/node_warden_impl.cpp +++ b/ydb/core/blobstorage/nodewarden/node_warden_impl.cpp @@ -411,9 +411,11 @@ void TNodeWarden::Handle(TEvStatusUpdate::TPtr ev) { STLOG(PRI_DEBUG, BS_NODE, NW47, "Handle(TEvStatusUpdate)"); auto *msg = ev->Get(); const TVSlotId vslotId(msg->NodeId, msg->PDiskId, msg->VSlotId); - if (const auto it = LocalVDisks.find(vslotId); it != LocalVDisks.end() && it->second.Status != msg->Status) { + if (const auto it = LocalVDisks.find(vslotId); it != LocalVDisks.end() && (it->second.Status != msg->Status || + it->second.OnlyPhantomsRemain != msg->OnlyPhantomsRemain)) { auto& vdisk = it->second; vdisk.Status = msg->Status; + vdisk.OnlyPhantomsRemain = msg->OnlyPhantomsRemain; SendDiskMetrics(false); if (msg->Status == NKikimrBlobStorage::EVDiskStatus::READY && vdisk.WhiteboardVDiskId) { @@ -428,7 +430,10 @@ void TNodeWarden::FillInVDiskStatus(google::protobuf::RepeatedPtrField<NKikimrBl const NKikimrBlobStorage::EVDiskStatus status = vdisk.RuntimeData ? vdisk.Status : NKikimrBlobStorage::EVDiskStatus::ERROR; - if (initial || status != vdisk.ReportedVDiskStatus) { + + const bool onlyPhantomsRemain = status == NKikimrBlobStorage::EVDiskStatus::REPLICATING ? vdisk.OnlyPhantomsRemain : false; + + if (initial || status != vdisk.ReportedVDiskStatus || onlyPhantomsRemain != vdisk.ReportedOnlyPhantomsRemain) { auto *item = pb->Add(); VDiskIDFromVDiskID(vdisk.GetVDiskId(), item->MutableVDiskId()); item->SetNodeId(vslotId.NodeId); @@ -436,7 +441,9 @@ void TNodeWarden::FillInVDiskStatus(google::protobuf::RepeatedPtrField<NKikimrBl item->SetVSlotId(vslotId.VDiskSlotId); item->SetPDiskGuid(vdisk.Config.GetVDiskLocation().GetPDiskGuid()); item->SetStatus(status); + item->SetOnlyPhantomsRemain(onlyPhantomsRemain); vdisk.ReportedVDiskStatus = status; + vdisk.ReportedOnlyPhantomsRemain = onlyPhantomsRemain; } } } diff --git a/ydb/core/blobstorage/nodewarden/node_warden_impl.h b/ydb/core/blobstorage/nodewarden/node_warden_impl.h index fb329fc516f..acda31d3194 100644 --- a/ydb/core/blobstorage/nodewarden/node_warden_impl.h +++ b/ydb/core/blobstorage/nodewarden/node_warden_impl.h @@ -262,7 +262,9 @@ namespace NKikimr::NStorage { ui64 WhiteboardInstanceGuid; NKikimrBlobStorage::EVDiskStatus Status = NKikimrBlobStorage::EVDiskStatus::INIT_PENDING; + bool OnlyPhantomsRemain = false; std::optional<NKikimrBlobStorage::EVDiskStatus> ReportedVDiskStatus; // last reported to BSC + std::optional<bool> ReportedOnlyPhantomsRemain; enum EScrubState : ui32 { IDLE, diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_hullrepljob.cpp b/ydb/core/blobstorage/vdisk/repl/blobstorage_hullrepljob.cpp index add5430b892..30363347fa3 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_hullrepljob.cpp +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_hullrepljob.cpp @@ -695,21 +695,20 @@ namespace NKikimr { auto [begin, end] = PhantomChecksInFlight.equal_range(ev->Cookie); Y_VERIFY(begin != end); - std::unordered_map<TLogoBlobID, bool> isPhantom; + std::unordered_map<TLogoBlobID, std::tuple<bool, bool>> isPhantom; auto *msg = ev->Get(); for (size_t i = 0; i < msg->ResponseSz; ++i) { auto& r = msg->Responses[i]; - isPhantom.emplace(r.Id, r.Status == NKikimrProto::NODATA); + isPhantom.try_emplace(r.Id, r.Status == NKikimrProto::NODATA, r.LooksLikePhantom); } for (auto it = begin; it != end; ++it) { const auto& [_, item] = *it; const auto& [id, parts] = item; - const auto isPhantomIt = isPhantom.find(id); - Y_VERIFY(isPhantomIt != isPhantom.end()); - const bool phantom = isPhantomIt->second; - isPhantom.erase(isPhantomIt); - RecoveryMachine->ProcessPhantomBlob(id, parts, phantom); + auto node = isPhantom.extract(id); + Y_VERIFY(node); + auto [phantom, looksLikePhantom] = node.mapped(); + RecoveryMachine->ProcessPhantomBlob(id, parts, phantom, looksLikePhantom); if (phantom) { Phantoms.push_back(id); } diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp index a58f42690d4..edac5f87336 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp @@ -67,6 +67,7 @@ namespace NKikimr { PARAM(Duration, End - Start); PARAM_V(KeyPos); PARAM_V(Eof); + PARAM_V(UnrecoveredNonphantomBlobs); PARAM_V(DonorVDiskId); PARAM_V(DropDonor); GROUP("Plan Generation Stats") { @@ -169,6 +170,7 @@ namespace NKikimr { std::set<TVDiskID> ConnectedPeerDisks, ConnectedDonorDisks; TEvResumeForce *ResumeForceToken = nullptr; TInstant ReplicationEndTime; + bool UnrecoveredNonphantomBlobs = false; friend class TActorBootstrapped<TReplScheduler>; @@ -256,6 +258,7 @@ namespace NKikimr { ReplCtx->MonGroup.ReplWorkUnitsDone() = 0; ReplCtx->MonGroup.ReplItemsRemaining() = 0; ReplCtx->MonGroup.ReplItemsDone() = 0; + UnrecoveredNonphantomBlobs = false; Become(&TThis::StateRepl); @@ -339,6 +342,8 @@ namespace NKikimr { STLOG(PRI_DEBUG, BS_REPL, BSVR16, VDISKP(ReplCtx->VCtx->VDiskLogPrefix, "QUANTUM COMPLETED"), (Info, *info)); LastReplQuantumEnd = now; + UnrecoveredNonphantomBlobs |= info->UnrecoveredNonphantomBlobs; + bool finished = false; if (info->Eof) { // when it is the last quantum for some donor, rotate the blob sets @@ -367,31 +372,6 @@ namespace NKikimr { History.Push(info); -#ifndef NDEBUG - // validate history -- work units must decrease consistently with work units processed - TEvReplFinished::TInfoPtr prev = nullptr; - for (auto it = History.Begin(); it != History.End(); ++it) { - TEvReplFinished::TInfoPtr cur = *it; - if (prev) { - Y_VERIFY_DEBUG_S( - cur->WorkUnitsTotal <= prev->WorkUnitsTotal - prev->WorkUnitsPerformed && - cur->ItemsTotal <= prev->ItemsTotal - prev->ItemsRecovered - prev->ItemsPhantom, - "cur.WorkUnits# " << cur->WorkUnits() - << " prev.WorkUnits# " << prev->WorkUnits() - << " cur.Items# " << cur->Items() - << " prev.Items# " << prev->Items()); - } - Y_VERIFY_DEBUG_S( - cur->WorkUnitsPlanned <= cur->WorkUnitsTotal && - cur->WorkUnitsPerformed <= cur->WorkUnitsPlanned && - cur->ItemsPlanned <= cur->ItemsTotal && - cur->ItemsPlanned == cur->ItemsRecovered + cur->ItemsNotRecovered + cur->ItemsException + - cur->ItemsPartiallyRecovered + cur->ItemsPhantom + cur->ItemsNonPhantom, - "WorkUnits# " << cur->WorkUnits() << " Items# " << cur->Items()); - prev = cur; - } -#endif - TDuration timeRemaining; if (finished) { @@ -409,6 +389,11 @@ namespace NKikimr { // try again for unreplicated blobs in some future State = Relaxation; Schedule(ReplCtx->VDiskCfg->ReplTimeInterval, new TEvents::TEvWakeup); + if (!UnrecoveredNonphantomBlobs) { + // semi-finished replication -- we have only phantom-like unreplicated blobs + TActivationContext::Send(new IEventHandle(TEvBlobStorage::EvReplDone, 0, ReplCtx->SkeletonId, + SelfId(), nullptr, 1)); + } } else { // no more blobs to replicate; replication will not resume State = Finished; diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h index 3942c4d6046..31f28ce80a5 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h @@ -26,6 +26,7 @@ namespace NKikimr { TInstant End; TLogoBlobID KeyPos; bool Eof; + bool UnrecoveredNonphantomBlobs = false; TVDiskID DonorVDiskId; bool DropDonor = false; diff --git a/ydb/core/blobstorage/vdisk/repl/blobstorage_replrecoverymachine.h b/ydb/core/blobstorage/vdisk/repl/blobstorage_replrecoverymachine.h index 64dd28a3f5b..420ec299f49 100644 --- a/ydb/core/blobstorage/vdisk/repl/blobstorage_replrecoverymachine.h +++ b/ydb/core/blobstorage/vdisk/repl/blobstorage_replrecoverymachine.h @@ -173,7 +173,7 @@ namespace NKikimr { (BlobId, id), (NumPresentParts, presentParts), (MinParts, groupType.DataParts()), (PartSet, item.ToString()), (Ingress, lost.Ingress.ToString(ReplCtx->VCtx->Top.get(), ReplCtx->VCtx->ShortSelfVDisk, id))); - BlobDone(id, false, &TEvReplFinished::TInfo::ItemsNotRecovered); + BlobDone(id, false, true, &TEvReplFinished::TInfo::ItemsNotRecovered); } } else { // recover @@ -222,20 +222,20 @@ namespace NKikimr { ReplInfo->BytesRecovered += partsSize; if (!numMissingParts) { - BlobDone(id, true, &TEvReplFinished::TInfo::ItemsRecovered); + BlobDone(id, true, false, &TEvReplFinished::TInfo::ItemsRecovered); if (lost.PossiblePhantom) { ++ReplCtx->MonGroup.ReplPhantomLikeRecovered(); } } else if (lost.PossiblePhantom) { nonPhantom = false; // run phantom check for this blob } else { - BlobDone(id, false, &TEvReplFinished::TInfo::ItemsPartiallyRecovered); + BlobDone(id, false, true, &TEvReplFinished::TInfo::ItemsPartiallyRecovered); } } catch (const std::exception& ex) { ++ReplCtx->MonGroup.ReplRecoveryGroupTypeErrors(); STLOG(PRI_ERROR, BS_REPL, BSVR29, VDISKP(ReplCtx->VCtx->VDiskLogPrefix, "recovery exception"), (BlobId, id), (Error, TString(ex.what()))); - BlobDone(id, false, &TEvReplFinished::TInfo::ItemsException); + BlobDone(id, false, true, &TEvReplFinished::TInfo::ItemsException); } } @@ -243,20 +243,23 @@ namespace NKikimr { return nonPhantom; } - void ProcessPhantomBlob(const TLogoBlobID& id, NMatrix::TVectorType parts, bool isPhantom) { + void ProcessPhantomBlob(const TLogoBlobID& id, NMatrix::TVectorType parts, bool isPhantom, bool looksLikePhantom) { STLOG(PRI_INFO, BS_REPL, BSVR00, VDISKP(ReplCtx->VCtx->VDiskLogPrefix, "phantom check completed"), - (BlobId, id), (Parts, parts), (IsPhantom, isPhantom)); + (BlobId, id), (Parts, parts), (IsPhantom, isPhantom), (LooksLikePhantom, looksLikePhantom)); - ++(isPhantom + const bool success = isPhantom; // confirmed phantom blob + Y_VERIFY_DEBUG(isPhantom <= looksLikePhantom); + + ++(success ? ReplCtx->MonGroup.ReplPhantomLikeDropped() : ReplCtx->MonGroup.ReplPhantomLikeUnrecovered()); - BlobDone(id, isPhantom, isPhantom + BlobDone(id, success, !looksLikePhantom, looksLikePhantom ? &TEvReplFinished::TInfo::ItemsPhantom : &TEvReplFinished::TInfo::ItemsNonPhantom); } - void BlobDone(TLogoBlobID id, bool success, ui64 TEvReplFinished::TInfo::*counter) { + void BlobDone(TLogoBlobID id, bool success, bool unrecovered, ui64 TEvReplFinished::TInfo::*counter) { STLOG(PRI_DEBUG, BS_REPL, BSVR35, VDISKP(ReplCtx->VCtx->VDiskLogPrefix, "BlobDone"), (BlobId, id), (Success, success)); @@ -271,6 +274,7 @@ namespace NKikimr { } ++((*ReplInfo).*counter); + ReplInfo->UnrecoveredNonphantomBlobs |= unrecovered; } // finish work diff --git a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp index 502bae6e396..a3828f3147a 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp @@ -1751,7 +1751,7 @@ namespace NKikimr { if (!runRepl) { ReplDone = true; } - UpdateReplState(ctx); + UpdateReplState(); } void SkeletonErrorState(const TActorContext &ctx, @@ -1768,7 +1768,7 @@ namespace NKikimr { Db->GetVDiskIncarnationGuid()); ctx.Send(*SkeletonFrontIDPtr, msg.release()); // push the status - UpdateVDiskStatus(NKikimrBlobStorage::ERROR, ctx); + UpdateVDiskStatus(NKikimrBlobStorage::ERROR); } void Handle(TEvBlobStorage::TEvLocalRecoveryDone::TPtr &ev, const TActorContext &ctx) { @@ -2306,17 +2306,22 @@ namespace NKikimr { // FIXME: reconfigure handoff } - void HandleReplDone(const TActorContext& ctx) { - ReplDone = true; - UpdateReplState(ctx); + void HandleReplDone(STFUNC_SIG) { + if (ev->Cookie) { // semi-finished replication, only phantom blobs + ReplOnlyPhantomsRemain = true; + } else { + ReplDone = true; + } + UpdateReplState(); } void Ignore(const TActorContext&) {} - void UpdateVDiskStatus(NKikimrBlobStorage::EVDiskStatus status, const TActorContext& ctx) { + void UpdateVDiskStatus(NKikimrBlobStorage::EVDiskStatus status) { const auto& base = Db->Config->BaseInfo; - Send(NodeWardenServiceId, new TEvStatusUpdate(ctx.SelfID.NodeId(), base.PDiskId, base.VDiskSlotId, status)); + Send(NodeWardenServiceId, new TEvStatusUpdate(SelfId().NodeId(), base.PDiskId, base.VDiskSlotId, status, + ReplOnlyPhantomsRemain)); } //////////////////////////////////////////////////////////////////////// @@ -2366,13 +2371,13 @@ namespace NKikimr { void Handle(TEvReportScrubStatus::TPtr ev, const TActorContext& ctx) { HasUnreadableBlobs = ev->Get()->HasUnreadableBlobs; - UpdateReplState(ctx); + UpdateReplState(); ctx.Send(ev->Forward(*SkeletonFrontIDPtr)); } - void UpdateReplState(const TActorContext& ctx) { + void UpdateReplState() { const bool ready = ReplDone && !HasUnreadableBlobs; - UpdateVDiskStatus(ready ? NKikimrBlobStorage::READY : NKikimrBlobStorage::REPLICATING, ctx); + UpdateVDiskStatus(ready ? NKikimrBlobStorage::READY : NKikimrBlobStorage::REPLICATING); } void Handle(TEvRestoreCorruptedBlob::TPtr ev, const TActorContext& ctx) { @@ -2619,7 +2624,7 @@ namespace NKikimr { HFunc(TEvVGenerationChange, Handle) HFunc(TEvents::TEvPoisonPill, HandlePoison) HFunc(TEvents::TEvActorDied, Handle) - CFunc(TEvBlobStorage::EvReplDone, HandleReplDone) + fFunc(TEvBlobStorage::EvReplDone, HandleReplDone) CFunc(TEvBlobStorage::EvCommenceRepl, HandleCommenceRepl) fFunc(TEvBlobStorage::EvControllerScrubStartQuantum, ForwardToScrubActor) fFunc(TEvBlobStorage::EvScrubAwait, ForwardToScrubActor) @@ -2731,6 +2736,7 @@ namespace NKikimr { NMonGroup::TSyncLogIFaceGroup SyncLogIFaceGroup; std::shared_ptr<NMonGroup::TVDiskIFaceGroup> IFaceMonGroup; bool ReplDone = false; + bool ReplOnlyPhantomsRemain = false; TInstant WhiteboardUpdateTimestamp = TInstant::Zero(); std::shared_ptr<std::atomic_uint64_t> PDiskWriteBytes = std::make_shared<std::atomic_uint64_t>(); TLoggedRecsVault LoggedRecsVault; diff --git a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp index 0e7bbca3a6e..aa3a6c63ff2 100644 --- a/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp +++ b/ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp @@ -1589,7 +1589,8 @@ namespace NKikimr { // update status in NodeWarden const TActorId& warden = MakeBlobStorageNodeWardenID(SelfId().NodeId()); const auto& base = Config->BaseInfo; - ctx.Send(warden, new TEvStatusUpdate(ctx.SelfID.NodeId(), base.PDiskId, base.VDiskSlotId, NKikimrBlobStorage::EVDiskStatus::ERROR)); + ctx.Send(warden, new TEvStatusUpdate(ctx.SelfID.NodeId(), base.PDiskId, base.VDiskSlotId, + NKikimrBlobStorage::EVDiskStatus::ERROR, false)); // drop messages in internal queues for (auto *q : {&IntQueueAsyncGets, &IntQueueFastGets, &IntQueueDiscover, &IntQueueLowGets, &IntQueueLogPuts, &IntQueueHugePutsForeground, &IntQueueHugePutsBackground}) { diff --git a/ydb/core/cms/console/configs_dispatcher.cpp b/ydb/core/cms/console/configs_dispatcher.cpp index 833547d3fd4..ffb3affe67a 100644 --- a/ydb/core/cms/console/configs_dispatcher.cpp +++ b/ydb/core/cms/console/configs_dispatcher.cpp @@ -82,7 +82,7 @@ private: using TPtr = TIntrusivePtr<TSubscription>; TDynBitMap Kinds; - THashSet<TActorId> Subscribers; + THashMap<TActorId, ui64> Subscribers; // Set to true for all yaml kinds. // Some 'legacy' kinds, which is usually managed by some automation e.g. NetClassifierDistributableConfigItem @@ -106,7 +106,6 @@ private: // Subscribers who didn't respond yet to the latest config update. THashSet<TActorId> SubscribersToUpdate; - bool FirstUpdate = false; }; /** @@ -234,6 +233,7 @@ private: TString ResolvedJsonConfig; NKikimrConfig::TAppConfig YamlProtoConfig; bool YamlConfigEnabled = false; + }; TConfigsDispatcher::TConfigsDispatcher( @@ -473,8 +473,9 @@ void TConfigsDispatcher::Handle(TEvInterconnect::TEvNodesInfo::TPtr &ev) << " Subscription: " << Endl << " Yaml: " << subscription->Yaml << Endl << " Subscribers: " << Endl; - for (auto &id : subscription->Subscribers) { + for (auto &[id, updates] : subscription->Subscribers) { str << " - Actor: " << id << Endl; + str << " UpdatesSent: " << updates << Endl; } if (subscription->YamlVersion) { str << " YamlVersion: " << subscription->YamlVersion->Version << ".["; @@ -672,7 +673,7 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvConfigSubscriptionNotification::T bool hasAffectedKinds = false; if (subscription->Yaml && YamlConfigEnabled) { - ReplaceConfigItems(YamlProtoConfig, trunc, subscription->Kinds); + ReplaceConfigItems(YamlProtoConfig, trunc, subscription->Kinds, InitialConfig); } else { Y_FOR_EACH_BIT(kind, kinds) { if (affectedKinds.contains(kind)) { @@ -681,17 +682,14 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvConfigSubscriptionNotification::T } // we try resend all configs if yaml config was turned off - if (!hasAffectedKinds && !yamlConfigTurnedOff) { + if (!hasAffectedKinds && !yamlConfigTurnedOff && CurrentStateFunc() != &TThis::StateInit) { continue; } - ReplaceConfigItems(ev->Get()->Record.GetConfig(), trunc, kinds); + ReplaceConfigItems(ev->Get()->Record.GetConfig(), trunc, kinds, InitialConfig); } - subscription->FirstUpdate = true; - - if (hasAffectedKinds || !CompareConfigs(subscription->CurrentConfig.Config, trunc)) - { + if (hasAffectedKinds || !CompareConfigs(subscription->CurrentConfig.Config, trunc) || CurrentStateFunc() == &TThis::StateInit) { subscription->UpdateInProcess = MakeHolder<TEvConsole::TEvConfigNotificationRequest>(); subscription->UpdateInProcess->Record.MutableConfig()->CopyFrom(trunc); subscription->UpdateInProcess->Record.SetLocal(true); @@ -705,10 +703,11 @@ void TConfigsDispatcher::Handle(TEvConsole::TEvConfigSubscriptionNotification::T UpdateYamlVersion(subscription); } - for (auto &subscriber : subscription->Subscribers) { + for (auto &[subscriber, updates] : subscription->Subscribers) { auto k = kinds; BLOG_TRACE("Sending for kinds: " << KindsToString(k)); SendUpdateToSubscriber(subscription, subscriber); + ++updates; } } else if (YamlConfigEnabled && subscription->Yaml) { UpdateYamlVersion(subscription); @@ -754,7 +753,7 @@ void TConfigsDispatcher::Handle(TEvConfigsDispatcher::TEvGetConfigRequest::TPtr } auto trunc = std::make_shared<NKikimrConfig::TAppConfig>(); - ReplaceConfigItems(CurrentConfig, *trunc, KindsToBitMap(ev->Get()->ConfigItemKinds)); + ReplaceConfigItems(CurrentConfig, *trunc, KindsToBitMap(ev->Get()->ConfigItemKinds), InitialConfig); resp->Config = trunc; BLOG_TRACE("Send TEvConfigsDispatcher::TEvGetConfigResponse" @@ -796,7 +795,7 @@ void TConfigsDispatcher::Handle(TEvConfigsDispatcher::TEvSetConfigSubscriptionRe SubscriptionsByKinds.emplace(kinds, subscription); } - subscription->Subscribers.insert(subscriberActor); + auto [subscriberIt, _] = subscription->Subscribers.emplace(subscriberActor, 0); SubscriptionsBySubscriber.emplace(subscriberActor, subscription); auto subscriber = FindSubscriber(subscriberActor); @@ -810,15 +809,15 @@ void TConfigsDispatcher::Handle(TEvConfigsDispatcher::TEvSetConfigSubscriptionRe // We don't care about versions and kinds here Send(ev->Sender, new TEvConfigsDispatcher::TEvSetConfigSubscriptionResponse); - if (subscription->FirstUpdate) { + if (CurrentStateFunc() != &TThis::StateInit) { // first time we send even empty config if (!subscription->UpdateInProcess) { subscription->UpdateInProcess = MakeHolder<TEvConsole::TEvConfigNotificationRequest>(); NKikimrConfig::TAppConfig trunc; if (YamlConfigEnabled) { - ReplaceConfigItems(YamlProtoConfig, trunc, kinds); + ReplaceConfigItems(YamlProtoConfig, trunc, kinds, InitialConfig); } else { - ReplaceConfigItems(CurrentConfig, trunc, kinds); + ReplaceConfigItems(CurrentConfig, trunc, kinds, InitialConfig); } subscription->UpdateInProcess->Record.MutableConfig()->CopyFrom(trunc); Y_FOR_EACH_BIT(kind, kinds) { @@ -829,6 +828,7 @@ void TConfigsDispatcher::Handle(TEvConfigsDispatcher::TEvSetConfigSubscriptionRe } BLOG_TRACE("Sending for kinds: " << KindsToString(kinds)); SendUpdateToSubscriber(subscription, subscriber->Subscriber); + ++(subscriberIt->second); } } diff --git a/ydb/core/cms/console/configs_dispatcher_ut.cpp b/ydb/core/cms/console/configs_dispatcher_ut.cpp index 681f4a95d60..bd32d5569f0 100644 --- a/ydb/core/cms/console/configs_dispatcher_ut.cpp +++ b/ydb/core/cms/console/configs_dispatcher_ut.cpp @@ -478,6 +478,9 @@ Y_UNIT_TEST_SUITE(TConfigsDispatcherTests) { auto reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); NKikimrConfig::TAppConfig expectedConfig; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); auto *ncdConfig = expectedConfig.MutableNetClassifierDistributableConfig(); ncdConfig->SetLastUpdateTimestamp(1); UNIT_ASSERT(notifications > 0); @@ -612,6 +615,9 @@ selector_config: [] subscriber = AddSubscriber(runtime, {(ui32)NKikimrConsole::TConfigItem::LogConfigItem}); auto reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); NKikimrConfig::TAppConfig expectedConfig; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); auto *logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster1"); logConfig->SetDefaultLevel(5); @@ -690,6 +696,9 @@ selector_config: [] reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); expectedConfig = {}; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster3"); logConfig->SetDefaultLevel(5); @@ -757,6 +766,9 @@ selector_config: reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); expectedConfig = {}; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster3"); logConfig->SetDefaultLevel(5); @@ -770,6 +782,9 @@ selector_config: CheckDropConfig(runtime, Ydb::StatusIds::SUCCESS, "", 5); reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); expectedConfig = {}; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster2"); logConfig->SetDefaultLevel(5); @@ -812,6 +827,9 @@ selector_config: reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); expectedConfig = {}; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster3"); logConfig->SetDefaultLevel(5); @@ -857,6 +875,9 @@ selector_config: reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); expectedConfig = {}; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster3"); logConfig->SetDefaultLevel(5); @@ -892,6 +913,9 @@ selector_config: reply = runtime.GrabEdgeEventRethrow<TEvPrivate::TEvGotNotification>(handle); expectedConfig = {}; + label = expectedConfig.AddLabels(); + label->SetName("test"); + label->SetValue("true"); logConfig = expectedConfig.MutableLogConfig(); logConfig->SetClusterName("cluster2"); logConfig->SetDefaultLevel(5); diff --git a/ydb/core/cms/console/immediate_controls_configurator_ut.cpp b/ydb/core/cms/console/immediate_controls_configurator_ut.cpp index 921bb10b9c9..7e40db01f84 100644 --- a/ydb/core/cms/console/immediate_controls_configurator_ut.cpp +++ b/ydb/core/cms/console/immediate_controls_configurator_ut.cpp @@ -211,6 +211,7 @@ Y_UNIT_TEST_SUITE(TImmediateControlsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); InitImmediateControlsConfigurator(runtime); + WaitForUpdate(runtime); // initial update CompareControls(runtime, ITEM_CONTROLS_DEFAULT.GetConfig().GetImmediateControlsConfig()); } @@ -219,6 +220,7 @@ Y_UNIT_TEST_SUITE(TImmediateControlsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); InitImmediateControlsConfigurator(runtime); + WaitForUpdate(runtime); // initial update ConfigureAndWaitUpdate(runtime, MakeAddAction(ITEM_CONTROLS1)); @@ -229,6 +231,7 @@ Y_UNIT_TEST_SUITE(TImmediateControlsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); InitImmediateControlsConfigurator(runtime); + WaitForUpdate(runtime); // initial update ConfigureAndWaitUpdate(runtime, MakeAddAction(ITEM_CONTROLS1)); @@ -249,6 +252,7 @@ Y_UNIT_TEST_SUITE(TImmediateControlsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); InitImmediateControlsConfigurator(runtime); + WaitForUpdate(runtime); // initial update ConfigureAndWaitUpdate(runtime, MakeAddAction(ITEM_CONTROLS_EXCEED_MAX)); diff --git a/ydb/core/cms/console/log_settings_configurator_ut.cpp b/ydb/core/cms/console/log_settings_configurator_ut.cpp index caba3bf5ae4..f5b705092a8 100644 --- a/ydb/core/cms/console/log_settings_configurator_ut.cpp +++ b/ydb/core/cms/console/log_settings_configurator_ut.cpp @@ -235,6 +235,7 @@ Y_UNIT_TEST_SUITE(TLogSettingsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); auto settings = InitLogSettingsConfigurator(runtime); + WaitForUpdate(runtime); // initial update SetDefaultLogConfig(ITEM_DOMAIN_LOG_1); ConfigureAndWaitUpdate(runtime, @@ -246,6 +247,7 @@ Y_UNIT_TEST_SUITE(TLogSettingsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); auto settings = InitLogSettingsConfigurator(runtime); + WaitForUpdate(runtime); // initial update SetDefaultLogConfig(ITEM_DOMAIN_LOG_1); AddEntry(ITEM_DOMAIN_LOG_1, "CMS_CLUSTER", 5, Max<ui32>(), Max<ui32>()); @@ -263,6 +265,7 @@ Y_UNIT_TEST_SUITE(TLogSettingsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); auto settings = InitLogSettingsConfigurator(runtime); + WaitForUpdate(runtime); // initial update SetDefaultLogConfig(ITEM_DOMAIN_LOG_1); AddEntry(ITEM_TENANT1_LOG_1, "CMS_CLUSTER", 5, Max<ui32>(), Max<ui32>()); @@ -291,6 +294,7 @@ Y_UNIT_TEST_SUITE(TLogSettingsConfiguratorTests) { TTenantTestRuntime runtime(DefaultConsoleTestConfig()); auto settings = InitLogSettingsConfigurator(runtime); + WaitForUpdate(runtime); // initial update SetDefaultLogConfig(ITEM_DOMAIN_LOG_1); SetDefaults(ITEM_TENANT1_LOG_1, PRI_ALERT, PRI_ALERT, 10); diff --git a/ydb/core/cms/console/util.cpp b/ydb/core/cms/console/util.cpp index c43a8f19a71..d898275ab83 100644 --- a/ydb/core/cms/console/util.cpp +++ b/ydb/core/cms/console/util.cpp @@ -51,9 +51,14 @@ TDynBitMap KindsToBitMap(const TVector<ui32> &kinds) return result; } -void ReplaceConfigItems(const NKikimrConfig::TAppConfig &from, NKikimrConfig::TAppConfig &to, const TDynBitMap &kinds) +void ReplaceConfigItems( + const NKikimrConfig::TAppConfig &from, + NKikimrConfig::TAppConfig &to, + const TDynBitMap &kinds, + const NKikimrConfig::TAppConfig &fallback) { NKikimrConfig::TAppConfig fromCopy = from; + NKikimrConfig::TAppConfig fallbackCopy = fallback; auto *desc = to.GetDescriptor(); auto *reflection = to.GetReflection(); @@ -66,10 +71,14 @@ void ReplaceConfigItems(const NKikimrConfig::TAppConfig &from, NKikimrConfig::TA if (reflection->HasField(to, field)) { reflection->ClearField(&to, field); } + if (reflection->HasField(fromCopy, field)) { + reflection->ClearField(&fallbackCopy, field); + } } else { if (reflection->HasField(fromCopy, field)) { reflection->ClearField(&fromCopy, field); } + reflection->ClearField(&fallbackCopy, field); } } else { reflection->ClearField(&to, field); @@ -78,6 +87,7 @@ void ReplaceConfigItems(const NKikimrConfig::TAppConfig &from, NKikimrConfig::TA } to.MergeFrom(fromCopy); + to.MergeFrom(fallbackCopy); } bool CompareConfigs(const NKikimrConfig::TAppConfig &lhs, const NKikimrConfig::TAppConfig &rhs) diff --git a/ydb/core/cms/console/util.h b/ydb/core/cms/console/util.h index 0b992d46156..8ec1ef5eb83 100644 --- a/ydb/core/cms/console/util.h +++ b/ydb/core/cms/console/util.h @@ -21,7 +21,11 @@ TDynBitMap KindsToBitMap(const TVector<ui32> &kinds); * Replace 'kinds' in 'to' from 'from' * repeated items are removed */ -void ReplaceConfigItems(const NKikimrConfig::TAppConfig &from, NKikimrConfig::TAppConfig &to, const TDynBitMap &kinds); +void ReplaceConfigItems( + const NKikimrConfig::TAppConfig &from, + NKikimrConfig::TAppConfig &to, + const TDynBitMap &kinds, + const NKikimrConfig::TAppConfig &fallback = {}); bool CompareConfigs(const NKikimrConfig::TAppConfig &lhs, const NKikimrConfig::TAppConfig &rhs); diff --git a/ydb/core/mind/address_classification/net_classifier_ut.cpp b/ydb/core/mind/address_classification/net_classifier_ut.cpp index 80654535755..e5d0e3df92e 100644 --- a/ydb/core/mind/address_classification/net_classifier_ut.cpp +++ b/ydb/core/mind/address_classification/net_classifier_ut.cpp @@ -97,7 +97,7 @@ Y_UNIT_TEST_SUITE(TNetClassifierTest) { UNIT_ASSERT_VALUES_EQUAL(counters->SubscribersCount->GetAtomic(), 1); UNIT_ASSERT_VALUES_EQUAL(counters->GoodConfigNotificationsCount->GetAtomic(), 0); - UNIT_ASSERT_VALUES_EQUAL(counters->BrokenConfigNotificationsCount->GetAtomic(), 1); + UNIT_ASSERT_VALUES_EQUAL(counters->BrokenConfigNotificationsCount->GetAtomic(), 2); UNIT_ASSERT_VALUES_EQUAL(counters->NetDataSourceType->GetAtomic(), ENetDataSourceType::File); const auto prevLagSeconds = AtomicGet(counters->NetDataUpdateLagSeconds->GetAtomic()); @@ -130,7 +130,7 @@ Y_UNIT_TEST_SUITE(TNetClassifierTest) { UNIT_ASSERT_VALUES_EQUAL(counters->SubscribersCount->GetAtomic(), 1); UNIT_ASSERT_VALUES_EQUAL(counters->GoodConfigNotificationsCount->GetAtomic(), 0); - UNIT_ASSERT_VALUES_EQUAL(counters->BrokenConfigNotificationsCount->GetAtomic(), 1); + UNIT_ASSERT_VALUES_EQUAL(counters->BrokenConfigNotificationsCount->GetAtomic(), 2); UNIT_ASSERT_VALUES_EQUAL(counters->NetDataSourceType->GetAtomic(), ENetDataSourceType::None); } } diff --git a/ydb/core/mind/bscontroller/impl.h b/ydb/core/mind/bscontroller/impl.h index d4f36f53487..917cd87f7eb 100644 --- a/ydb/core/mind/bscontroller/impl.h +++ b/ydb/core/mind/bscontroller/impl.h @@ -127,9 +127,10 @@ public: public: NKikimrBlobStorage::EVDiskStatus Status = NKikimrBlobStorage::EVDiskStatus::INIT_PENDING; bool IsReady = false; + bool OnlyPhantomsRemain = false; public: - void SetStatus(NKikimrBlobStorage::EVDiskStatus status, TMonotonic now, TInstant instant) { + void SetStatus(NKikimrBlobStorage::EVDiskStatus status, TMonotonic now, TInstant instant, bool onlyPhantomsRemain) { if (status != Status) { if (status == NKikimrBlobStorage::EVDiskStatus::REPLICATING) { // became "replicating" LastGotReplicating = instant; @@ -154,6 +155,9 @@ public: } const_cast<TGroupInfo&>(*Group).CalculateGroupStatus(); } + if (status == NKikimrBlobStorage::EVDiskStatus::REPLICATING) { + OnlyPhantomsRemain = onlyPhantomsRemain; + } } void PutInVSlotReadyTimestampQ(TMonotonic now) { @@ -287,7 +291,12 @@ public: } TString GetStatusString() const { - return NKikimrBlobStorage::EVDiskStatus_Name(Status); + TStringStream s; + s << NKikimrBlobStorage::EVDiskStatus_Name(Status); + if (Status == NKikimrBlobStorage::REPLICATING && OnlyPhantomsRemain) { + s << "/p"; + } + return s.Str(); } bool IsOperational() const { diff --git a/ydb/core/mind/bscontroller/register_node.cpp b/ydb/core/mind/bscontroller/register_node.cpp index 1620238affa..2110073a4a5 100644 --- a/ydb/core/mind/bscontroller/register_node.cpp +++ b/ydb/core/mind/bscontroller/register_node.cpp @@ -520,9 +520,9 @@ void TBlobStorageController::OnWardenDisconnected(TNodeId nodeId) { if (it->second->IsReady) { NotReadyVSlotIds.insert(it->second->VSlotId); } - it->second->SetStatus(NKikimrBlobStorage::EVDiskStatus::ERROR, mono, now); + it->second->SetStatus(NKikimrBlobStorage::EVDiskStatus::ERROR, mono, now, false); timingQ.emplace_back(*it->second); - sh->VDiskStatusUpdate.emplace_back(it->second->GetVDiskId(), it->second->Status); + sh->VDiskStatusUpdate.emplace_back(it->second->GetVDiskId(), it->second->Status, false); ScrubState.UpdateVDiskState(&*it->second); } } diff --git a/ydb/core/mind/bscontroller/self_heal.cpp b/ydb/core/mind/bscontroller/self_heal.cpp index 4f657e28598..095efb5b5fa 100644 --- a/ydb/core/mind/bscontroller/self_heal.cpp +++ b/ydb/core/mind/bscontroller/self_heal.cpp @@ -323,11 +323,12 @@ namespace NKikimr::NBsController { Groups.erase(it); } } - for (const auto& [vdiskId, status] : ev->Get()->VDiskStatusUpdate) { + for (const auto& [vdiskId, status, onlyPhantomsRemain] : ev->Get()->VDiskStatusUpdate) { if (const auto it = Groups.find(vdiskId.GroupID); it != Groups.end()) { auto& group = it->second; if (const auto it = group.Content.VDisks.find(vdiskId); it != group.Content.VDisks.end()) { it->second.VDiskStatus = status; + it->second.OnlyPhantomsRemain = onlyPhantomsRemain; group.VDiskStatus[vdiskId].Update(status, now); } } @@ -760,6 +761,7 @@ namespace NKikimr::NBsController { slot->PDisk->ShouldBeSettledBySelfHeal(), slot->PDisk->BadInTermsOfSelfHeal(), slot->PDisk->Decommitted(), + slot->OnlyPhantomsRemain, slot->Status, }; } @@ -784,8 +786,8 @@ namespace NKikimr::NBsController { const bool was = slot->IsOperational(); if (const TGroupInfo *group = slot->Group) { const bool wasReady = slot->IsReady; - if (slot->Status != m.GetStatus()) { - slot->SetStatus(m.GetStatus(), mono, now); + if (slot->Status != m.GetStatus() || slot->OnlyPhantomsRemain != m.GetOnlyPhantomsRemain()) { + slot->SetStatus(m.GetStatus(), mono, now, m.GetOnlyPhantomsRemain()); if (slot->IsReady != wasReady) { ScrubState.UpdateVDiskState(slot); if (wasReady) { @@ -794,7 +796,7 @@ namespace NKikimr::NBsController { } timingQ.emplace_back(*slot); } - ev->VDiskStatusUpdate.emplace_back(vdiskId, m.GetStatus()); + ev->VDiskStatusUpdate.emplace_back(vdiskId, m.GetStatus(), m.GetOnlyPhantomsRemain()); if (!was && slot->IsOperational() && !group->SeenOperational) { groups.insert(const_cast<TGroupInfo*>(group)); } diff --git a/ydb/core/mind/bscontroller/self_heal.h b/ydb/core/mind/bscontroller/self_heal.h index 38d9c0657ef..c0fe040b754 100644 --- a/ydb/core/mind/bscontroller/self_heal.h +++ b/ydb/core/mind/bscontroller/self_heal.h @@ -15,6 +15,7 @@ namespace NKikimr::NBsController { bool Faulty; bool Bad; bool Decommitted; + bool OnlyPhantomsRemain; NKikimrBlobStorage::EVDiskStatus VDiskStatus; }; ui32 Generation; @@ -24,7 +25,7 @@ namespace NKikimr::NBsController { }; THashMap<TGroupId, std::optional<TGroupContent>> GroupsToUpdate; // groups with faulty groups that are changed or got faulty PDisks for the first time - TVector<std::pair<TVDiskID, NKikimrBlobStorage::EVDiskStatus>> VDiskStatusUpdate; + TVector<std::tuple<TVDiskID, NKikimrBlobStorage::EVDiskStatus, bool>> VDiskStatusUpdate; std::optional<bool> GroupLayoutSanitizerEnabled; }; diff --git a/ydb/core/protos/blobstorage.proto b/ydb/core/protos/blobstorage.proto index a2943ca9869..cfb4904a031 100644 --- a/ydb/core/protos/blobstorage.proto +++ b/ydb/core/protos/blobstorage.proto @@ -1255,6 +1255,7 @@ message TVDiskStatus { // payload optional EVDiskStatus Status = 6; + optional bool OnlyPhantomsRemain = 7; // substate of REPLICATING status } message TEvControllerUpdateDiskStatus { diff --git a/ydb/core/testlib/test_client.cpp b/ydb/core/testlib/test_client.cpp index a9f9b5d54f1..38172f02dc4 100644 --- a/ydb/core/testlib/test_client.cpp +++ b/ydb/core/testlib/test_client.cpp @@ -713,7 +713,12 @@ namespace Tests { TMailboxType::Revolving, 0); Runtime->RegisterService(MakeTenantPoolRootID(), poolId, nodeIdx); if (Settings->EnableConfigsDispatcher) { - auto *dispatcher = NConsole::CreateConfigsDispatcher(Settings->AppConfig, {}); + // We overwrite icb settings here to save behavior when configs dispatcher are enabled + NKikimrConfig::TAppConfig initial = Settings->AppConfig; + if (!initial.HasImmediateControlsConfig()) { + initial.MutableImmediateControlsConfig()->CopyFrom(Settings->Controls); + } + auto *dispatcher = NConsole::CreateConfigsDispatcher(initial, {}); auto aid = Runtime->Register(dispatcher, nodeIdx, appData.SystemPoolId, TMailboxType::Revolving, 0); Runtime->RegisterService(NConsole::MakeConfigsDispatcherID(Runtime->GetNodeId(nodeIdx)), aid, nodeIdx); } diff --git a/ydb/core/tx/columnshard/engines/columns_table.h b/ydb/core/tx/columnshard/engines/columns_table.h index b98a57c0c47..4be4a052b2d 100644 --- a/ydb/core/tx/columnshard/engines/columns_table.h +++ b/ydb/core/tx/columnshard/engines/columns_table.h @@ -9,13 +9,13 @@ namespace NKikimr::NOlap { struct TColumnRecord { ui64 Granule; - ui32 ColumnId{0}; ui64 PlanStep; // {PlanStep, TxId} is min snapshot for {Granule, Portion} ui64 TxId; ui64 Portion; // Id of independent (overlayed by PK) portion of data in granule - ui16 Chunk; // Number of blob for column ColumnName in Portion ui64 XPlanStep{0}; // {XPlanStep, XTxId} is snapshot where the blob has been removed (i.e. compacted into another one) ui64 XTxId{0}; + ui32 ColumnId{0}; + ui16 Chunk; // Number of blob for column ColumnName in Portion TBlobRange BlobRange; TString Metadata; @@ -63,10 +63,10 @@ struct TColumnRecord { static TColumnRecord Make(ui64 granule, ui32 columnId, const TSnapshot& minSnapshot, ui64 portion, ui16 chunk = 0) { TColumnRecord row; row.Granule = granule; - row.ColumnId = columnId; row.PlanStep = minSnapshot.GetPlanStep(); row.TxId = minSnapshot.GetTxId(); row.Portion = portion; + row.ColumnId = columnId; row.Chunk = chunk; //row.BlobId //row.Metadata diff --git a/ydb/docs/ru/core/_assets/embedded-storage.svg b/ydb/docs/ru/core/_assets/embedded-storage.svg new file mode 100644 index 00000000000..0c10c2bcf7a --- /dev/null +++ b/ydb/docs/ru/core/_assets/embedded-storage.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" xmlns:xlink="http://www.w3.org/1999/xlink" class="yc-icon nv-composite-bar__menu-icon" fill="currentColor" stroke="none" aria-hidden="true"><svg aria-hidden="true" data-prefix="fas" data-icon="database" class="storage_svg__svg-inline--fa storage_svg__fa-database" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M448 73.12v45.75C448 159.1 347.6 192 224 192S0 159.1 0 118.9V73.12C0 32.88 100.4 0 224 0s224 32.88 224 73.12zM448 176v102.9c0 40.2-100.4 73.1-224 73.1S0 319.1 0 278.9V176c48.12 33.12 136.2 48.62 224 48.62S399.9 209.1 448 176zm0 160v102.9c0 40.2-100.4 73.1-224 73.1S0 479.12 0 438.87V336c48.12 33.13 136.2 48.63 224 48.63S399.9 369.1 448 336z"/></svg></svg>
\ No newline at end of file diff --git a/ydb/docs/ru/core/_includes/fault-tolerance.md b/ydb/docs/ru/core/_includes/fault-tolerance.md new file mode 100644 index 00000000000..e3e7bcb26d2 --- /dev/null +++ b/ydb/docs/ru/core/_includes/fault-tolerance.md @@ -0,0 +1,5 @@ +{% note info %} + +Кластер YDB является отказоустойчивым. Временное выключение узла не приводит к недоступности кластера. Подробнее см. [{#T}](../cluster/topology.md). + +{% endnote %} diff --git a/ydb/docs/ru/core/_includes/warning-configuration-error.md b/ydb/docs/ru/core/_includes/warning-configuration-error.md new file mode 100644 index 00000000000..a906200a703 --- /dev/null +++ b/ydb/docs/ru/core/_includes/warning-configuration-error.md @@ -0,0 +1,5 @@ +{% note warning %} + +Неправильная последовательность действий или ошибка в конфигурации могут привести к недоступности кластера {{ ydb-short-name }}. + +{% endnote %} diff --git a/ydb/docs/ru/core/administration/state-storage-move.md b/ydb/docs/ru/core/administration/state-storage-move.md new file mode 100644 index 00000000000..3512144bd10 --- /dev/null +++ b/ydb/docs/ru/core/administration/state-storage-move.md @@ -0,0 +1,46 @@ +# Перемещение State Storage + +Если нужно вывести из эксплуатации хост кластера {{ ydb-short-name }}, на котором располагается часть [State Storage](../deploy/configuration/config.md#domains-state), необходимо переместить ее на другой хост. + +{% include [warning-configuration-error](../_includes/warning-configuration-error.md) %} + +В качестве примера рассмотрим кластер {{ ydb-short-name }} со следующей конфигурацией State Storage: + +```yaml +... +domains_config: + ... + state_storage: + - ring: + node: [1, 2, 3, 4, 5, 6, 7, 8, 9] + nto_select: 9 + ssid: 1 + ... +... +``` + +На хосте с `node_id:1` сконфигурирован и запущен [статический узел](../deploy/configuration/config.md#hosts) кластера, который обслуживает часть State Storage. Предположим, нам нужно вывести из эксплуатации этот хост. + +Для замены `node_id:1` мы [добавили](../maintenance/manual/cluster_expansion.md#add-host) в кластер новый хост с `node_id:10` и [развернули](../maintenance/manual/cluster_expansion.md#add-static-node) на нем статический узел. + +Чтобы переместить State Storage с хоста `node_id:1` на `node_id:10`: + +1. Остановите статические узлы кластера на хостах с `node_id:1` и `node_id:10`. + + {% include [fault-tolerance](../_includes/fault-tolerance.md) %} +1. В конфигурационном файле `config.yaml` измените список хостов `node`, заменив идентификатор удаляемого хоста на идентификатор добавляемого: + + ```yaml + domains_config: + ... + state_storage: + - ring: + node: [2, 3, 4, 5, 6, 7, 8, 9, 10] + nto_select: 9 + ssid: 1 + ... + ``` + +1. Обновите конфигурационные файлы `config.yaml` для всех узлов кластера, в том числе и динамических. +1. С помощью процедуры [rolling-restart](../maintenance/manual/node_restarting.md) перезапустите все узлы кластера, включая динамические, кроме статических узлов на хостах с `node_id:1` и `node_id:10`. +1. Запустите статические узлы кластера на хостах `node_id:1` и `node_id:10`. diff --git a/ydb/docs/ru/core/administration/static-group-move.md b/ydb/docs/ru/core/administration/static-group-move.md new file mode 100644 index 00000000000..41a432b675b --- /dev/null +++ b/ydb/docs/ru/core/administration/static-group-move.md @@ -0,0 +1,69 @@ +# Перемещение статической группы + +Если нужно вывести из эксплуатации хост кластера {{ ydb-short-name }}, на котором располагается часть [статической группы](../deploy/configuration/config.md#blob_storage_config), необходимо переместить ее на другой хост. + +{% include [warning-configuration-error](../_includes/warning-configuration-error.md) %} + +В качестве примера рассмотрим кластер {{ ydb-short-name }}, в котором на хосте с `node_id:1` сконфигурирован и запущен [статический узел](../deploy/configuration/config.md#hosts). Этот узел обслуживает часть статической группы. + +Фрагмент конфигурации статической группы: + +```yaml +... +blob_storage_config: + ... + service_set: + ... + groups: + ... + rings: + ... + fail_domains: + - vdisk_locations: + - node_id: 1 + path: /dev/vda + pdisk_category: SSD + ... + ... + ... + ... +... +``` + +Для замены `node_id:1` мы [добавили](../maintenance/manual/cluster_expansion.md#add-host) в кластер новый хост с `node_id:10` и [развернули](../maintenance/manual/cluster_expansion.md#add-static-node) на нем статический узел. + +Чтобы переместить часть статической группы с хоста `node_id:1` на `node_id:10`: + +1. Остановите статический узел кластера на хосте с `node_id:1`. + + {% include [fault-tolerance](../_includes/fault-tolerance.md) %} +1. В конфигурационном файле `config.yaml` измените значение `node_id`, заменив идентификатор удаляемого хоста на идентификатор добавляемого: + + ```yaml + ... + blob_storage_config: + ... + service_set: + ... + groups: + ... + rings: + ... + fail_domains: + - vdisk_locations: + - node_id: 10 + path: /dev/vda + pdisk_category: SSD + ... + ... + ... + ... + ... + ``` + + Измените путь `path` и категорию `pdisk_category` диска, если на хосте с `node_id: 10` они отличаются. + +1. Обновите конфигурационные файлы `config.yaml` для всех узлов кластера, в том числе и динамических. +1. С помощью процедуры [rolling-restart](../maintenance/manual/node_restarting.md) перезапустите все статические узлы кластера. +1. Перейдите на страницу мониторинга Embedded UI и убедитесь, что VDisk статической группы появился на целевом физическом диске и реплицируется. Подробнее см. [{#T}](../maintenance/embedded_monitoring/ydb_monitoring.md#static-group). +1. С помощью процедуры [rolling-restart](../maintenance/manual/node_restarting.md) перезапустите все динамические узлы кластера. diff --git a/ydb/docs/ru/core/administration/ydb-dstool-device-list.md b/ydb/docs/ru/core/administration/ydb-dstool-device-list.md new file mode 100644 index 00000000000..b276d18848e --- /dev/null +++ b/ydb/docs/ru/core/administration/ydb-dstool-device-list.md @@ -0,0 +1,51 @@ +# device list + +С помощью подкоманды `device list` вы можете вывести список устройств хранения, доступных на кластере {{ ydb-short-name }}. + +{% include [trunk](../_includes/trunk.md) %} + +Общий вид команды: + +```bash +ydb-dstool [global options ...] device list [list options ...] +``` + +* `global options` — [глобальные параметры](./ydb-dstool-global-options.md). +* `list options` — [параметры подкоманды](#options). + +Посмотрите описание команды вывода списка устройств: + +```bash +ydb-dstool device list --help +``` + +## Параметры подкоманды {#options} + +Параметр | Описание +---|--- +`-H`, `--human-readable` | Вывести данные в человекочитаемом формате. +`--sort-by` | Колонка сортировки.<br>Одно из значений: `SerialNumber`, `FQDN`, `Path`, `Type`, `StorageStatus`, `NodeId:PDiskId`. +`--reverse` | Использовать обратный порядок сортировки. +`--format` | Формат вывода.<br>Одно из значений: `pretty`, `json`, `tsv`, `csv`. +`--no-header` | Не выводить строку с именами колонок. +`--columns` | Список колонок, которые нужно вывести.<br>Одно или комбинация значений: `SerialNumber`, `FQDN`, `Path`, `Type`, `StorageStatus`, `NodeId:PDiskId`. +`-A`, `--all-columns` | Вывести все колонки. + +## Примеры {#examples} + +Следующая команда выведет список устройств, доступных на кластере: + +```bash +ydb-dstool -e node-5.example.com device list +``` + +Результат: + +```text +┌────────────────────┬────────────────────┬────────────────────────────────┬──────┬───────────────────────────┬────────────────┐ +│ SerialNumber │ FQDN │ Path │ Type │ StorageStatus │ NodeId:PDiskId │ +├────────────────────┼────────────────────┼────────────────────────────────┼──────┼───────────────────────────┼────────────────┤ +│ PHLN123301H41P2BGN │ node-1.example.com │ /dev/disk/by-partlabel/nvme_04 │ NVME │ FREE │ NULL │ +│ PHLN123301A62P2BGN │ node-6.example.com │ /dev/disk/by-partlabel/nvme_03 │ NVME │ PDISK_ADDED_BY_DEFINE_BOX │ [6:1001] │ +... +``` diff --git a/ydb/docs/ru/core/administration/ydb-dstool-global-options.md b/ydb/docs/ru/core/administration/ydb-dstool-global-options.md new file mode 100644 index 00000000000..342c4026828 --- /dev/null +++ b/ydb/docs/ru/core/administration/ydb-dstool-global-options.md @@ -0,0 +1,19 @@ +# Глобальные параметры + +Глобальные параметры являются общими для всех подкоманд утилиты {{ ydb-short-name }} DSTool. + +Параметр | Описание +---|--- +`-?`, `-h`, `--help` | Вывести встроенную справку. +`-v`, `--verbose` | Получить подробный вывод при выполнении команды. +`-q`, `--quiet` | Подавить вывод несущественных сообщений при выполнении команды. +`-n`, `--dry-run` | Выполнить пробный запуск команды. +`-e`, `--endpoint` | Эндпоинт для подключения к кластеру {{ ydb-short-name }} в формате `[PROTOCOL://]HOST[:PORT]`.<br>Значения по умолчанию: протокол — `http`, порт — `8765`. +`--grpc-port` | gRPC-порт для вызова процедур. +`--mon-port` | Порт для просмотра данных HTTP-мониторинга в формате JSON. +`--mon-protocol` | Если протокол для подключения к кластеру не задан явно в эндпоинте, то используется указанное здесь значение. +`--token-file` | Путь к файлу с [Access Token](../concepts/auth.md#iam). +`--ca-file` | Путь к файлу корневого PEM-сертификата для TLS-соединения. +`--http` | Использовать HTTP для подключения к Blob Storage вместо gRPC. +`--http-timeout` | Тайм-аут на операции ввода-вывода сокета во время HTTP(s)-запросов. +`--insecure` | Разрешить небезопасную передачу данных по HTTPS. В этом режиме не проверяются SSL-сертификат и имя хоста. diff --git a/ydb/docs/ru/core/administration/ydb-dstool-overview.md b/ydb/docs/ru/core/administration/ydb-dstool-overview.md index 53c443a79f2..ee76338a8eb 100644 --- a/ydb/docs/ru/core/administration/ydb-dstool-overview.md +++ b/ydb/docs/ru/core/administration/ydb-dstool-overview.md @@ -6,6 +6,7 @@ Команда | Описание --- | --- +[device list](./ydb-dstool-device-list.md) | Вывести список устройств хранения. pdisk add-by-serial | Добавить PDisk в набор по серийному номеру. pdisk remove-by-serial | Удалить PDisk из набора по серийному номеру. pdisk set | Задать параметры PDisk'а. diff --git a/ydb/docs/ru/core/maintenance/embedded_monitoring/ydb_monitoring.md b/ydb/docs/ru/core/maintenance/embedded_monitoring/ydb_monitoring.md index aa3c1d3c3a7..8f6ce7b2a33 100644 --- a/ydb/docs/ru/core/maintenance/embedded_monitoring/ydb_monitoring.md +++ b/ydb/docs/ru/core/maintenance/embedded_monitoring/ydb_monitoring.md @@ -214,6 +214,12 @@ http://<ендпоинт>:8765/monitoring/tenant/healthcheck?name=<tenant-path> При отметке чекбоксов ID и Racks будут также отображены ID узлов и их расположение по стойкам. +## Мониторинг статической группы {#static-group} + +Чтобы проверить статус статической группы, перейдите на панель  **Storage**. По умолчанию отображается список групп, имеющих какие-либо проблемы. + +В поисковой строке введите `static`. Если результат пуст, то статическая группа не имеет проблем. Если же в выдаче присутствует группа **static**, то необходимо проверить статус VDisk'ов в ней. Допустимы зеленый (проблем нет) и синий (VDisk реплицируется) состояния. Красный индикатор сигнализирует о проблеме. Наведите курсор на индикатор чтобы получить текстовое описание проблемы. + ## Индикаторы состояний {#colored_indicator} Слева от названия конкретного компонента может находится цветовой индикатор его состояния. diff --git a/ydb/docs/ru/core/maintenance/manual/cluster_expansion.md b/ydb/docs/ru/core/maintenance/manual/cluster_expansion.md index a8a69b1386e..22deedf7b92 100644 --- a/ydb/docs/ru/core/maintenance/manual/cluster_expansion.md +++ b/ydb/docs/ru/core/maintenance/manual/cluster_expansion.md @@ -4,7 +4,7 @@ Расширение кластера {{ ydb-short-name }} не требует приостановки доступа пользователей к базам данных. При расширении кластера выполняется перезапуск его компонент для применения изменений в конфигурации, что, в свою очередь, может привести к необходимости повтора выполняемых на кластере транзакций. Повторы транзакций выполняются автоматически за счет использования приложениями возможностей SDK {{ ydb-short-name }} по контролю ошибок и повтору операций. -## Подготовка новых серверов +## Подготовка новых серверов {#add-host} В случае размещения новых статических или динамических узлов кластера на новых серверах, не входивших ранее в состав расширяемого кластера {{ ydb-short-name }}, на каждом новом сервере необходимо выполнить установку программного обеспечения {{ ydb-short-name }} в соответствии с процедурами, описанными в [инструкции по развертыванию кластеров](../../deploy/manual/deploy-ydb-on-premises.md). В частности, необходимо: @@ -15,7 +15,7 @@ Используемые на новых серверах сертификаты TLS должны соответствовать [требованиям к заполнению полей](../../deploy/manual/deploy-ydb-on-premises.md#tls-certificates), и быть подписаны доверенным центром регистрации, используемым на уже существующих серверах расширяемого кластера {{ ydb-short-name }}. -## Добавление динамических узлов +## Добавление динамических узлов {#add-dynamic-node} Добавление динамических узлов позволяет увеличить доступные вычислительные ресурсы (процессорные ядра и оперативную память) для выполнения пользовательских запросов кластером {{ ydb-short-name }}. @@ -25,7 +25,7 @@ Для вывода динамического узла из кластера достаточно выполнить остановку процесса динамического узла. -## Добавление статических узлов +## Добавление статических узлов {#add-static-node} Добавление статических узлов позволяет увеличить пропускную способность при выполнении операций ввода-вывода и увеличить доступную емкость для хранения данных в кластере {{ ydb-short-name }}. diff --git a/ydb/docs/ru/core/maintenance/manual/index.md b/ydb/docs/ru/core/maintenance/manual/index.md index 50751779f6f..aebbf029365 100644 --- a/ydb/docs/ru/core/maintenance/manual/index.md +++ b/ydb/docs/ru/core/maintenance/manual/index.md @@ -6,6 +6,8 @@ * [{#T}](cluster_expansion.md). * [{#T}](adding_storage_groups.md). + * [{#T}](../../administration/state-storage-move.md) + * [{#T}](../../administration/static-group-move.md) * Обслуживание: diff --git a/ydb/docs/ru/core/maintenance/manual/stat_group_move.md b/ydb/docs/ru/core/maintenance/manual/stat_group_move.md deleted file mode 100644 index b2e628018fa..00000000000 --- a/ydb/docs/ru/core/maintenance/manual/stat_group_move.md +++ /dev/null @@ -1,42 +0,0 @@ -# Миграция статической группы - -## Миграция статической группы между двумя хостами кластера -**Данная процедура может потребоваться в случае, когда текущий хост кластера полностью выводится из эксплуатации.** - -{% note alert %} - -Процедура является потенциально опасной, будьте внимательны. - -{% endnote %} - -Для замены одной ноды **статической** группы в кластере на другую, необходимо проделать следующие действия: - -Предположим осуществляется миграция части статической группы с ноды с id:1 на ноду с id:10 и у нас уже нода с id:10 описана в конфигурационном файле `config.yaml` - -Шаги: -* Остановить процесс `ydb server` на ноде, с которой будет увезен кусок статической группы. -* Отредактировать конфигурационный файл `config.yaml`, поменяв в секции настройки статической группы node_id сервера, с которого будет переноситься статическая группа на node_id конечного сервера: -```yaml -blob_storage_config: - service_set: - ... - - vdisk_locations: - - node_id: 1 #-> меняем на 10 - path: /dev/vda #-> меняем имя диска, если оно отличается - pdisk_category: SSD #-> меняем категорию диска, если она отличается (SSD/ROT/NVME) - - vdisk_locations: - ... -``` -* Нужно выложить измененный конфигурационный файл ydb на все ноды кластера -* Провести процесс [роллинг-рестарта](node_restarting.md) `ydb server` на всех storage нодах кластера -* Убедиться, что виртуальный диск статической группы появился и реплицируется на целевом физическом диске с помощью [мониторинга](#stat_group_web_mon) -* Провести процесс [роллинг-рестарта](node_restarting.md) динамических нод ydb (всех) - -### Web monitoring статической группы {#stat_group_web_mon} -Основное описание Web monitoring'а ydb: [Web Monitoring](../embedded_monitoring/ydb_monitoring.md) - -1. Проверить статус статической группы можно перейдя на вкладку `Storage` (слева в панели). По умолчанию открывается список групп с проблемами. -2. В появившейся поисковой строке (Group ID, Pool name) ввести "static", если результат пустой, значит со статической группой все в порядке. -3. Если в выдаче видно группу **static**, то нужно проверить статус **Vdisk**'ов (справа). -4. В статусах (цветах) Vdisk'ов допускаются **зеленый** и **синий**(репликация в процессе). -5. Если присутствует красный цвет в статусе Vdisk'а, то нужно навести на него курсор и попытаться понять проблему по текстовому описанию diff --git a/ydb/docs/ru/core/maintenance/manual/state_storage_move.md b/ydb/docs/ru/core/maintenance/manual/state_storage_move.md deleted file mode 100644 index 1d0f1188986..00000000000 --- a/ydb/docs/ru/core/maintenance/manual/state_storage_move.md +++ /dev/null @@ -1,36 +0,0 @@ -# Миграция State Storage - -## Миграция State Storage с одного хоста кластера на другой -**Данная процедура может потребоваться в случае, когда текущий хост кластера полностью выводится из эксплуатации.** - -{% note alert %} - -Процедура является потенциально опасной, будьте внимательны. - -{% endnote %} - -Если у вас появилась потребность перевезти часть `State Storage` с одной ноды кластера на другую, то нужно выполнить -действия, описанные ниже (предполагаем, что новая нода с id:10 уже заведена в `config.yaml`). - -Перевоз части `State Storage` с ноды с id:1 на ноду с id:10: -* Погасить процессы `ydb server` на нодах с id:1 и id:10 -* В конфигурационном файле `config.yaml` сделать изменения в секции `state_storage` -``` - state_storage: - - ring: - node: [1, 2, 3, 4, 5, 6...] <массив узлов State Storage> - nto_select: <количество реплик данных в State Storage> - ssid: 1 -``` -меняем `1` на `10` и получаем: -``` - state_storage: - - ring: - node: [10, 2, 3, 4, 5, 6...] <массив узлов State Storage> - nto_select: <количество реплик данных в State Storage> - ssid: 1 -``` -* Выкладываем измененный `config.yaml` на все ноды кластера, включая динамические (обслуживающие базы кластера) -* Перезапускаем [rolling-restart'ом](node_restarting.md) процессы `ydb server` на всех нодах (включая динамические), кроме нод с id:1 и id:10 -* Запускаем процессы `ydb server` на нодах с id:1 и id:10 ---- diff --git a/ydb/docs/ru/core/maintenance/manual/toc_i.yaml b/ydb/docs/ru/core/maintenance/manual/toc_i.yaml index dd8085ea785..bdf085ee67f 100644 --- a/ydb/docs/ru/core/maintenance/manual/toc_i.yaml +++ b/ydb/docs/ru/core/maintenance/manual/toc_i.yaml @@ -1,14 +1,22 @@ items: -- name: "{{ ydb-short-name }} DSTool" +- name: "Утилита {{ ydb-short-name }} DSTool" items: - name: Обзор href: ../../administration/ydb-dstool-overview.md - name: Установка href: ../../administration/ydb-dstool-setup.md + - name: Глобальные параметры + href: ../../administration/ydb-dstool-global-options.md + - name: device list + href: ../../administration/ydb-dstool-device-list.md - name: Расширение кластера href: cluster_expansion.md - name: Добавление групп хранения href: adding_storage_groups.md +- name: Перемещение State Storage + href: ../../administration/state-storage-move.md +- name: Перемещение статической группы + href: ../../administration/static-group-move.md - name: Безопасный рестарт и выключение узлов href: node_restarting.md - name: Включение и выключение Scrubbing diff --git a/ydb/tests/functional/cms_config_cache/main.py b/ydb/tests/functional/cms_config_cache/main.py index 8df6cd3ad2c..ec624b9a8c0 100644 --- a/ydb/tests/functional/cms_config_cache/main.py +++ b/ydb/tests/functional/cms_config_cache/main.py @@ -46,6 +46,11 @@ LogConfig { } """ + log_entry = """Entry { + Component: "FLAT_TX_SCHEMESHARD" + Level: 7 + }""" + @classmethod def setup_class(cls): configurator = KikimrConfigGenerator() @@ -69,7 +74,7 @@ LogConfig { def test_cache_log_settings(self): with open(self._cms_config_cache_file_path(), 'r') as file: - assert 'LogConfig' not in file.read(), "initial node config should not contain LogConfig items" + assert self.log_entry not in file.read(), "initial node config should not contain LogConfig items" self.cluster.client.add_config_item(self.sample_log_config) timeout = 60 step = 1 @@ -79,7 +84,7 @@ LogConfig { time.sleep(step) cur += step with open(self._cms_config_cache_file_path(), 'r') as file: - config_updated = 'LogConfig' in file.read() + config_updated = self.log_entry in file.read() assert config_updated, "log config wasn't updated" def test_cms_config_cache(self): |