aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2023-05-15 14:08:48 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2023-05-15 14:08:48 +0300
commitac809add0f42f933c8a966c3309997d8563aa168 (patch)
tree016bd4489b23b6e2237875b5068b5b32488d09b0
parent6247839c1bd9fd6a2d540ebba3eb28b42f7e2b4f (diff)
downloadydb-ac809add0f42f933c8a966c3309997d8563aa168.tar.gz
Intermediate changes
-rw-r--r--ydb/core/base/blobstorage.h1
-rw-r--r--ydb/core/blobstorage/base/blobstorage_events.h5
-rw-r--r--ydb/core/blobstorage/dsproxy/dsproxy_blackboard.h1
-rw-r--r--ydb/core/blobstorage/dsproxy/dsproxy_get_impl.cpp4
-rw-r--r--ydb/core/blobstorage/dsproxy/dsproxy_strategy_get_m3dc_basic.h1
-rw-r--r--ydb/core/blobstorage/nodewarden/node_warden_impl.cpp11
-rw-r--r--ydb/core/blobstorage/nodewarden/node_warden_impl.h2
-rw-r--r--ydb/core/blobstorage/vdisk/repl/blobstorage_hullrepljob.cpp13
-rw-r--r--ydb/core/blobstorage/vdisk/repl/blobstorage_repl.cpp35
-rw-r--r--ydb/core/blobstorage/vdisk/repl/blobstorage_repl.h1
-rw-r--r--ydb/core/blobstorage/vdisk/repl/blobstorage_replrecoverymachine.h22
-rw-r--r--ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeleton.cpp28
-rw-r--r--ydb/core/blobstorage/vdisk/skeleton/blobstorage_skeletonfront.cpp3
-rw-r--r--ydb/core/cms/console/configs_dispatcher.cpp32
-rw-r--r--ydb/core/cms/console/configs_dispatcher_ut.cpp24
-rw-r--r--ydb/core/cms/console/immediate_controls_configurator_ut.cpp4
-rw-r--r--ydb/core/cms/console/log_settings_configurator_ut.cpp4
-rw-r--r--ydb/core/cms/console/util.cpp12
-rw-r--r--ydb/core/cms/console/util.h6
-rw-r--r--ydb/core/mind/address_classification/net_classifier_ut.cpp4
-rw-r--r--ydb/core/mind/bscontroller/impl.h13
-rw-r--r--ydb/core/mind/bscontroller/register_node.cpp4
-rw-r--r--ydb/core/mind/bscontroller/self_heal.cpp10
-rw-r--r--ydb/core/mind/bscontroller/self_heal.h3
-rw-r--r--ydb/core/protos/blobstorage.proto1
-rw-r--r--ydb/core/testlib/test_client.cpp7
-rw-r--r--ydb/core/tx/columnshard/engines/columns_table.h6
-rw-r--r--ydb/docs/ru/core/_assets/embedded-storage.svg1
-rw-r--r--ydb/docs/ru/core/_includes/fault-tolerance.md5
-rw-r--r--ydb/docs/ru/core/_includes/warning-configuration-error.md5
-rw-r--r--ydb/docs/ru/core/administration/state-storage-move.md46
-rw-r--r--ydb/docs/ru/core/administration/static-group-move.md69
-rw-r--r--ydb/docs/ru/core/administration/ydb-dstool-device-list.md51
-rw-r--r--ydb/docs/ru/core/administration/ydb-dstool-global-options.md19
-rw-r--r--ydb/docs/ru/core/administration/ydb-dstool-overview.md1
-rw-r--r--ydb/docs/ru/core/maintenance/embedded_monitoring/ydb_monitoring.md6
-rw-r--r--ydb/docs/ru/core/maintenance/manual/cluster_expansion.md6
-rw-r--r--ydb/docs/ru/core/maintenance/manual/index.md2
-rw-r--r--ydb/docs/ru/core/maintenance/manual/stat_group_move.md42
-rw-r--r--ydb/docs/ru/core/maintenance/manual/state_storage_move.md36
-rw-r--r--ydb/docs/ru/core/maintenance/manual/toc_i.yaml10
-rw-r--r--ydb/tests/functional/cms_config_cache/main.py9
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}
+
+Чтобы проверить статус статической группы, перейдите на панель ![embedded-storage](../../_assets/embedded-storage.svg) **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):