aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authora-sumin <a-sumin@yandex-team.com>2023-05-16 18:00:55 +0300
committera-sumin <a-sumin@yandex-team.com>2023-05-16 18:00:55 +0300
commitbb8a7d33d7bcc9d3bdd0c640d6c007f0e6610f57 (patch)
tree7849a87d62849c1e3f12a898d366a02973c1b9b0
parent60f98737b9ee6b8fc0db0144b24ed03867a81135 (diff)
downloadydb-bb8a7d33d7bcc9d3bdd0c640d6c007f0e6610f57.tar.gz
Introduce dedicated NPDisk::TLogCache
-rw-r--r--ydb/core/blobstorage/pdisk/CMakeLists.darwin-x86_64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/CMakeLists.linux-aarch64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/CMakeLists.linux-x86_64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/CMakeLists.windows-x86_64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice.h7
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp90
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_driveestimator.cpp2
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp2
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp6
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp82
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.h54
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp126
-rw-r--r--ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp16
-rw-r--r--ydb/core/blobstorage/pdisk/ut/CMakeLists.darwin-x86_64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-aarch64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-x86_64.txt1
-rw-r--r--ydb/core/blobstorage/pdisk/ut/CMakeLists.windows-x86_64.txt1
17 files changed, 339 insertions, 54 deletions
diff --git a/ydb/core/blobstorage/pdisk/CMakeLists.darwin-x86_64.txt b/ydb/core/blobstorage/pdisk/CMakeLists.darwin-x86_64.txt
index 378ee761763..69594119e22 100644
--- a/ydb/core/blobstorage/pdisk/CMakeLists.darwin-x86_64.txt
+++ b/ydb/core/blobstorage/pdisk/CMakeLists.darwin-x86_64.txt
@@ -56,6 +56,7 @@ target_sources(core-blobstorage-pdisk PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_internal_interface.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_params.cpp
diff --git a/ydb/core/blobstorage/pdisk/CMakeLists.linux-aarch64.txt b/ydb/core/blobstorage/pdisk/CMakeLists.linux-aarch64.txt
index 1fd378a19b2..14483b3155f 100644
--- a/ydb/core/blobstorage/pdisk/CMakeLists.linux-aarch64.txt
+++ b/ydb/core/blobstorage/pdisk/CMakeLists.linux-aarch64.txt
@@ -57,6 +57,7 @@ target_sources(core-blobstorage-pdisk PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_internal_interface.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_params.cpp
diff --git a/ydb/core/blobstorage/pdisk/CMakeLists.linux-x86_64.txt b/ydb/core/blobstorage/pdisk/CMakeLists.linux-x86_64.txt
index 1fd378a19b2..14483b3155f 100644
--- a/ydb/core/blobstorage/pdisk/CMakeLists.linux-x86_64.txt
+++ b/ydb/core/blobstorage/pdisk/CMakeLists.linux-x86_64.txt
@@ -57,6 +57,7 @@ target_sources(core-blobstorage-pdisk PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_internal_interface.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_params.cpp
diff --git a/ydb/core/blobstorage/pdisk/CMakeLists.windows-x86_64.txt b/ydb/core/blobstorage/pdisk/CMakeLists.windows-x86_64.txt
index 378ee761763..69594119e22 100644
--- a/ydb/core/blobstorage/pdisk/CMakeLists.windows-x86_64.txt
+++ b/ydb/core/blobstorage/pdisk/CMakeLists.windows-x86_64.txt
@@ -56,6 +56,7 @@ target_sources(core-blobstorage-pdisk PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_http.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_internal_interface.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_mon.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_params.cpp
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice.h
index 7469ec76d8a..1388ec92fa4 100644
--- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice.h
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice.h
@@ -47,6 +47,7 @@ public:
virtual void CachedPreadAsync(void *data, ui32 size, ui64 offset, TCompletionAction *completionAction,
TReqId reqId, NWilson::TTraceId *traceId) = 0;
virtual void ClearCache() = 0;
+ virtual void EraseCacheRange(ui64 begin, ui64 end) = 0; // erases offsets range [begin, end)
virtual void FlushAsync(TCompletionAction *completionAction, TReqId reqId) = 0;
virtual void NoopAsync(TCompletionAction *completionAction, TReqId reqId) = 0;
virtual void NoopAsyncHackForLogReader(TCompletionAction *completionAction, TReqId reqId) = 0;
@@ -61,11 +62,13 @@ public:
virtual TString DebugInfo() = 0;
};
+class TPDisk;
+
IBlockDevice* CreateRealBlockDevice(const TString &path, ui32 pDiskId, TPDiskMon &mon,
ui64 reorderingCycles, ui64 seekCostNs, ui64 deviceInFlight, TDeviceMode::TFlags flags,
- ui32 maxQueuedCompletionActions, TIntrusivePtr<TSectorMap> sectorMap);
+ ui32 maxQueuedCompletionActions, TIntrusivePtr<TSectorMap> sectorMap, TPDisk * const pdisk = nullptr);
IBlockDevice* CreateRealBlockDeviceWithDefaults(const TString &path, TPDiskMon &mon, TDeviceMode::TFlags flags,
- TIntrusivePtr<TSectorMap> sectorMap, TActorSystem *actorSystem);
+ TIntrusivePtr<TSectorMap> sectorMap, TActorSystem *actorSystem, TPDisk * const pdisk = nullptr);
} // NPDisk
} // NKikimr
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp
index a66a3f911e1..6a53d162b12 100644
--- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_async.cpp
@@ -1,6 +1,8 @@
#include "blobstorage_pdisk_blockdevice.h"
#include <ydb/library/pdisk_io/buffers.h>
#include "blobstorage_pdisk_completion_impl.h"
+#include "blobstorage_pdisk_impl.h"
+#include "blobstorage_pdisk_log_cache.h"
#include "blobstorage_pdisk_mon.h"
#include "blobstorage_pdisk_util_atomicblockcounter.h"
#include "blobstorage_pdisk_util_countedqueuemanyone.h"
@@ -11,7 +13,6 @@
#include <ydb/core/base/appdata.h>
#include <ydb/core/blobstorage/lwtrace_probes/blobstorage_probes.h>
#include <ydb/core/protos/services.pb.h>
-#include <ydb/core/util/cache.h>
#include <ydb/core/util/yverify_stream.h>
#include <ydb/library/pdisk_io/aio.h>
#include <ydb/library/pdisk_io/spdk_state.h>
@@ -1198,48 +1199,29 @@ class TCachedBlockDevice : public TRealBlockDevice {
}
};
- struct TCacheRecord : public TThrRefBase {
- char *Data;
- ui64 Size;
- TVector<ui64> BadOffsets;
-
- TCacheRecord(TCachedReadCompletion *source)
- : Data(static_cast<char*>(malloc(source->GetSize())))
- , Size(source->GetSize())
- , BadOffsets(std::move(source->GetBadOffsets()))
- {
- memcpy(Data, source->GetData(), source->GetSize());
- }
-
- ~TCacheRecord() {
- free(Data);
- }
- };
-
static constexpr ui64 MaxCount = 500ull;
static constexpr ui64 MaxReadsInFly = 2;
TMutex CacheMutex;
- NCache::TLruCache<ui64, TIntrusivePtr<TCacheRecord>> Cache;
+ TLogCache Cache; // cache records MUST NOT cross chunk boundaries
TMultiMap<ui64, TRead> ReadsForOffset;
TMap<ui64, TCachedReadCompletion*> CurrentReads;
ui64 ReadsInFly;
+ TPDisk * const PDisk;
void UpdateReads() {
auto nextIt = ReadsForOffset.begin();
for (auto it = ReadsForOffset.begin(); it != ReadsForOffset.end(); it = nextIt) {
nextIt++;
TRead &read = it->second;
- TIntrusivePtr<TCacheRecord> *found;
- bool isFound = Cache.Find(read.Offset, found);
- if (isFound) {
- TCacheRecord &cached = *found->Get();
- if (read.Size <= cached.Size) {
- memcpy(read.Data, cached.Data, read.Size);
+ const TLogCache::TCacheRecord* cached = Cache.Find(read.Offset);
+ if (cached) {
+ if (read.Size <= cached->Data.Size()) {
+ memcpy(read.Data, cached->Data.GetData(), read.Size);
Mon.DeviceReadCacheHits->Inc();
Y_VERIFY(read.CompletionAction);
- for (size_t i = 0; i < cached.BadOffsets.size(); ++i) {
- read.CompletionAction->RegisterBadOffset(cached.BadOffsets[i]);
+ for (size_t i = 0; i < cached->BadOffsets.size(); ++i) {
+ read.CompletionAction->RegisterBadOffset(cached->BadOffsets[i]);
}
NoopAsyncHackForLogReader(read.CompletionAction, read.ReqId);
ReadsForOffset.erase(it);
@@ -1270,13 +1252,14 @@ class TCachedBlockDevice : public TRealBlockDevice {
public:
TCachedBlockDevice(const TString &path, ui32 pDiskId, TPDiskMon &mon, ui64 reorderingCycles,
ui64 seekCostNs, ui64 deviceInFlight, TDeviceMode::TFlags flags, ui32 maxQueuedCompletionActions,
- TIntrusivePtr<TSectorMap> sectorMap)
+ TIntrusivePtr<TSectorMap> sectorMap, TPDisk * const pdisk)
: TRealBlockDevice(path, pDiskId, mon, reorderingCycles, seekCostNs, deviceInFlight, flags,
maxQueuedCompletionActions, sectorMap)
- , ReadsInFly(0)
+ , ReadsInFly(0), PDisk(pdisk)
{}
void ExecRead(TCachedReadCompletion *completion, TActorSystem *actorSystem) {
+ Y_ASSERT(PDisk);
TStackVec<TCompletionAction*, 32> pendingActions;
{
TGuard<TMutex> guard(CacheMutex);
@@ -1284,28 +1267,42 @@ public:
auto currentReadIt = CurrentReads.find(offset);
Y_VERIFY(currentReadIt != CurrentReads.end());
auto range = ReadsForOffset.equal_range(offset);
- if (Cache.GetCount() >= MaxCount) {
- Cache.Pop();
+
+ ui64 chunkIdx = offset / PDisk->Format.ChunkSize;
+ Y_VERIFY(chunkIdx < PDisk->ChunkState.size());
+ if (TChunkState::DATA_COMMITTED == PDisk->ChunkState[chunkIdx].CommitState) {
+ if ((offset % PDisk->Format.ChunkSize) + completion->GetSize() > PDisk->Format.ChunkSize) {
+ // TODO: split buffer if crossing chunk boundary instead of completely discarding it
+ LOG_INFO_S(
+ *ActorSystem, NKikimrServices::BS_DEVICE,
+ "Skip caching log read due to chunk boundary crossing");
+ } else {
+ if (Cache.Size() >= MaxCount) {
+ Cache.Pop();
+ }
+ const char* dataPtr = static_cast<const char*>(completion->GetData());
+ Cache.Insert(
+ TLogCache::TCacheRecord(
+ completion->GetOffset(),
+ TRcBuf(TString(dataPtr, dataPtr + completion->GetSize())),
+ completion->GetBadOffsets()));
+ }
}
- TIntrusivePtr<TCacheRecord> cacheRecord(new TCacheRecord(completion));
- TIntrusivePtr<TCacheRecord> *junk;
- Cache.Erase(offset);
- bool isOk = Cache.Insert(offset, cacheRecord, junk);
- Y_VERIFY(isOk);
+
auto nextIt = range.first;
for (auto it = range.first; it != range.second; it = nextIt) {
nextIt++;
TRead &read = it->second;
if (read.Size <= completion->GetSize()) {
if (read.Data != completion->GetData()) {
- memcpy(read.Data, cacheRecord->Data, read.Size);
+ memcpy(read.Data, completion->GetData(), read.Size);
Mon.DeviceReadCacheHits->Inc();
} else {
Mon.DeviceReadCacheMisses->Inc();
}
Y_VERIFY(read.CompletionAction);
- for (size_t i = 0; i < cacheRecord->BadOffsets.size(); ++i) {
- read.CompletionAction->RegisterBadOffset(cacheRecord->BadOffsets[i]);
+ for (ui64 badOffset : completion->GetBadOffsets()) {
+ read.CompletionAction->RegisterBadOffset(badOffset);
}
pendingActions.push_back(read.CompletionAction);
ReadsForOffset.erase(it);
@@ -1360,6 +1357,11 @@ public:
Cache.Clear();
}
+ virtual void EraseCacheRange(ui64 begin, ui64 end) override {
+ TGuard<TMutex> guard(CacheMutex);
+ Cache.EraseRange(begin, end);
+ }
+
void Stop() override {
TRealBlockDevice::Stop();
for (auto it = CurrentReads.begin(); it != CurrentReads.end(); ++it) {
@@ -1377,14 +1379,14 @@ public:
IBlockDevice* CreateRealBlockDevice(const TString &path, ui32 pDiskId, TPDiskMon &mon, ui64 reorderingCycles,
ui64 seekCostNs, ui64 deviceInFlight, TDeviceMode::TFlags flags, ui32 maxQueuedCompletionActions,
- TIntrusivePtr<TSectorMap> sectorMap) {
+ TIntrusivePtr<TSectorMap> sectorMap, TPDisk * const pdisk) {
return new TCachedBlockDevice(path, pDiskId, mon, reorderingCycles, seekCostNs, deviceInFlight, flags,
- maxQueuedCompletionActions, sectorMap);
+ maxQueuedCompletionActions, sectorMap, pdisk);
}
IBlockDevice* CreateRealBlockDeviceWithDefaults(const TString &path, TPDiskMon &mon, TDeviceMode::TFlags flags,
- TIntrusivePtr<TSectorMap> sectorMap, TActorSystem *actorSystem) {
- IBlockDevice *device = CreateRealBlockDevice(path, 0, mon, 0, 0, 4, flags, 8, sectorMap);
+ TIntrusivePtr<TSectorMap> sectorMap, TActorSystem *actorSystem, TPDisk * const pdisk) {
+ IBlockDevice *device = CreateRealBlockDevice(path, 0, mon, 0, 0, 4, flags, 8, sectorMap, pdisk);
device->Initialize(actorSystem, {});
return device;
}
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_driveestimator.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_driveestimator.cpp
index d4e7f0e2231..2ea7e9e61cc 100644
--- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_driveestimator.cpp
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_driveestimator.cpp
@@ -236,7 +236,7 @@ TDriveEstimator::TDriveEstimator(const TString filename)
, ActorSystemCreator(new TActorSystemCreator)
, ActorSystem(ActorSystemCreator->GetActorSystem())
, QueueDepth(4)
- , Device(CreateRealBlockDevice(filename, 0, PDiskMon, 50, 0, QueueDepth, TDeviceMode::LockFile, 128, nullptr))
+ , Device(CreateRealBlockDevice(filename, 0, PDiskMon, 50, 0, QueueDepth, TDeviceMode::LockFile, 128, nullptr, nullptr))
, BufferPool(CreateBufferPool(BufferSize, 1, false, {}))
, Buffer(BufferPool->Pop())
{
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp
index 748c7105280..5c3027d21ac 100644
--- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl.cpp
@@ -45,7 +45,7 @@ TPDisk::TPDisk(const TIntrusivePtr<TPDiskConfig> cfg, const TIntrusivePtr<::NMon
, BlockDevice(CreateRealBlockDevice(cfg->GetDevicePath(), cfg->PDiskId, Mon,
HPCyclesMs(ReorderingMs), DriveModel.SeekTimeNs(), cfg->DeviceInFlight,
TDeviceMode::LockFile | (cfg->UseSpdkNvmeDriver ? TDeviceMode::UseSpdk : 0),
- cfg->MaxQueuedCompletionActions, cfg->SectorMap))
+ cfg->MaxQueuedCompletionActions, cfg->SectorMap, this))
, Cfg(cfg)
, CreationTime(TInstant::Now())
, ExpectedSlotCount(cfg->ExpectedSlotCount)
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
index 392776190c6..74951e1676d 100644
--- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_impl_log.cpp
@@ -1137,6 +1137,12 @@ void TPDisk::OnLogCommitDone(TLogCommitDone &req) {
void TPDisk::MarkChunksAsReleased(TReleaseChunks& req) {
TGuard<TMutex> guard(StateMutex);
+ for (const auto& chunkIdx : req.ChunksToRelease) {
+ BlockDevice->EraseCacheRange(
+ Format.Offset(chunkIdx, 0),
+ Format.Offset(chunkIdx + 1, 0));
+ }
+
if (req.IsChunksFromLogSplice) {
auto *releaseReq = ReqCreator.CreateFromArgs<TReleaseChunks>(std::move(req.ChunksToRelease));
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp
new file mode 100644
index 00000000000..7d225c2efa9
--- /dev/null
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.cpp
@@ -0,0 +1,82 @@
+#include "blobstorage_pdisk_log_cache.h"
+
+namespace NKikimr {
+namespace NPDisk {
+
+TLogCache::TCacheRecord::TCacheRecord(ui64 offset, TRcBuf data, TVector<ui64> badOffsets)
+ : Offset(offset)
+ , Data(std::move(data))
+ , BadOffsets(std::move(badOffsets))
+{}
+
+TLogCache::TCacheRecord::TCacheRecord(TCacheRecord&& other)
+ : Offset(other.Offset)
+ , Data(std::move(other.Data))
+ , BadOffsets(std::move(other.BadOffsets))
+{}
+
+TLogCache::TItem::TItem(TItem&& other)
+ : Value(std::move(other.Value))
+{}
+
+TLogCache::TItem::TItem(TCacheRecord&& value)
+ : Value(std::move(value))
+{}
+
+size_t TLogCache::Size() const {
+ return Index.size();
+}
+
+const TLogCache::TCacheRecord* TLogCache::Find(ui64 offset) {
+ auto indexIt = Index.find(offset);
+ if (indexIt == Index.end()) {
+ return nullptr;
+ }
+
+ List.PushFront(&indexIt->second);
+ return &indexIt->second.Value;
+}
+
+const TLogCache::TCacheRecord* TLogCache::FindWithoutPromote(ui64 offset) const {
+ auto indexIt = Index.find(offset);
+ if (indexIt == Index.end()) {
+ return nullptr;
+ }
+
+ return &indexIt->second.Value;
+}
+
+bool TLogCache::Pop() {
+ if (Index.empty())
+ return false;
+
+ TItem* item = List.PopBack();
+ Index.erase(item->Value.Offset);
+ return true;
+}
+
+bool TLogCache::Insert(TCacheRecord&& value) {
+ auto [it, inserted] = Index.try_emplace(value.Offset, std::move(value));
+ List.PushFront(&it->second);
+ return inserted;
+}
+
+size_t TLogCache::Erase(ui64 offset) {
+ return Index.erase(offset);
+}
+
+size_t TLogCache::EraseRange(ui64 begin, ui64 end) {
+ Y_VERIFY_DEBUG(begin <= end);
+ auto beginIt = Index.lower_bound(begin);
+ auto endIt = Index.lower_bound(end);
+ size_t dist = std::distance(beginIt, endIt);
+ Index.erase(beginIt, endIt);
+ return dist;
+}
+
+void TLogCache::Clear() {
+ Index.clear();
+}
+
+} // NPDisk
+} // NKikimr
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.h b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.h
new file mode 100644
index 00000000000..c3d91dcdd2c
--- /dev/null
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache.h
@@ -0,0 +1,54 @@
+#pragma once
+#include "defs.h"
+#include <library/cpp/actors/util/rc_buf.h>
+#include <util/generic/intrlist.h>
+#include <util/generic/hash.h>
+
+namespace NKikimr {
+namespace NPDisk {
+
+/**
+ * Key-value LRU cache without automatic eviction, but able to erase range of keys.
+ **/
+class TLogCache {
+public:
+ struct TCacheRecord {
+ ui64 Offset = 0;
+ TRcBuf Data;
+ TVector<ui64> BadOffsets;
+
+ TCacheRecord() = default;
+ TCacheRecord(TCacheRecord&&);
+ TCacheRecord(ui64 offset, TRcBuf data, TVector<ui64> badOffsets);
+ };
+
+private:
+ struct TItem : public TIntrusiveListItem<TItem> {
+ TCacheRecord Value;
+
+ // custom constructors ignoring TIntrusiveListItem
+ TItem(TItem&& other);
+ explicit TItem(TCacheRecord&& value);
+ };
+
+ using TListType = TIntrusiveList<TItem>;
+ using TIndex = TMap<ui64, TItem>;
+
+public:
+ size_t Size() const;
+ const TCacheRecord* Find(ui64 offset);
+ const TCacheRecord* FindWithoutPromote(ui64 offset) const;
+
+ bool Pop();
+ bool Insert(TCacheRecord&& value);
+ size_t Erase(ui64 offset);
+ size_t EraseRange(ui64 begin, ui64 end); // erases range [begin, end)
+ void Clear();
+
+private:
+ TListType List;
+ TIndex Index;
+};
+
+} // NPDisk
+} // NKikimr
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp
new file mode 100644
index 00000000000..ba0d99e641a
--- /dev/null
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp
@@ -0,0 +1,126 @@
+#include "blobstorage_pdisk_log_cache.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+namespace NKikimr {
+namespace NPDisk {
+
+Y_UNIT_TEST_SUITE(TLogCache) {
+ TLogCache::TCacheRecord MakeRecord(ui64 offset, TString str) {
+ return TLogCache::TCacheRecord(
+ offset,
+ TRcBuf(TString(str.c_str(), str.c_str() + str.size() + 1)),
+ {});
+ }
+
+ Y_UNIT_TEST(Simple) {
+ TLogCache cache;
+
+ UNIT_ASSERT(cache.Insert(MakeRecord(1, "a")));
+ UNIT_ASSERT(cache.Insert(MakeRecord(2, "b")));
+ UNIT_ASSERT_EQUAL(cache.Size(), 2);
+ UNIT_ASSERT_STRINGS_EQUAL(cache.Find(1)->Data.GetData(), "a");
+
+ UNIT_ASSERT(cache.Insert(MakeRecord(3, "c")));
+ UNIT_ASSERT(cache.Pop()); // 2 must be evicted
+ UNIT_ASSERT_EQUAL(cache.Size(), 2);
+ UNIT_ASSERT_EQUAL(nullptr, cache.Find(2));
+ UNIT_ASSERT_STRINGS_EQUAL(cache.Find(3)->Data.GetData(), "c");
+
+ UNIT_ASSERT(cache.Pop()); // 1 must be evicted
+ UNIT_ASSERT(cache.Insert(MakeRecord(4, "d")));
+
+ UNIT_ASSERT_EQUAL(cache.Size(), 2);
+ UNIT_ASSERT_EQUAL(nullptr, cache.Find(1));
+ UNIT_ASSERT_STRINGS_EQUAL(cache.Find(4)->Data.GetData(), "d");
+
+ UNIT_ASSERT(cache.Pop()); // 3 must be evicted
+ UNIT_ASSERT_EQUAL(cache.Size(), 1);
+ UNIT_ASSERT_EQUAL(nullptr, cache.Find(3));
+ UNIT_ASSERT_STRINGS_EQUAL(cache.Find(4)->Data.GetData(), "d");
+
+ UNIT_ASSERT_EQUAL(0, cache.Erase(3));
+ UNIT_ASSERT_EQUAL(1, cache.Erase(4));
+ UNIT_ASSERT_EQUAL(cache.Size(), 0);
+ UNIT_ASSERT(!cache.Pop());
+ UNIT_ASSERT_EQUAL(cache.Size(), 0);
+ }
+
+ TLogCache SetupCache(const TVector<std::pair<ui64, TString>>& content = {{5, "x"}, {1, "y"}, {10, "z"}}) {
+ TLogCache cache;
+ for (auto pair : content) {
+ cache.Insert(MakeRecord(pair.first, pair.second));
+ }
+ return cache;
+ };
+
+ void AssertCacheContains(TLogCache& cache, const TVector<std::pair<ui64, TString>>& content = {{5, "x"}, {1, "y"}, {10, "z"}}) {
+ UNIT_ASSERT_VALUES_EQUAL(content.size(), cache.Size());
+ for (auto pair : content) {
+ UNIT_ASSERT_STRINGS_EQUAL(
+ pair.second,
+ cache.FindWithoutPromote(pair.first)->Data.GetData());
+ }
+ for (auto pair : content) {
+ UNIT_ASSERT(cache.Pop());
+ UNIT_ASSERT_EQUAL(nullptr, cache.FindWithoutPromote(pair.first));
+ }
+ }
+
+ Y_UNIT_TEST(EraseRangeOnEmpty) {
+ TLogCache cache;
+ UNIT_ASSERT_EQUAL(0, cache.EraseRange(0, 0));
+ UNIT_ASSERT_EQUAL(0, cache.EraseRange(0, 10));
+ UNIT_ASSERT_EQUAL(0, cache.EraseRange(10, 10));
+ }
+
+ Y_UNIT_TEST(EraseRangeOutsideOfData) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(3, cache.Size());
+ UNIT_ASSERT_EQUAL(0, cache.EraseRange(0, 1));
+ UNIT_ASSERT_EQUAL(3, cache.Size());
+ UNIT_ASSERT_EQUAL(0, cache.EraseRange(11, 12));
+ UNIT_ASSERT_EQUAL(3, cache.Size());
+ UNIT_ASSERT_EQUAL(0, cache.EraseRange(11, 100));
+ UNIT_ASSERT_EQUAL(3, cache.Size());
+ }
+
+ Y_UNIT_TEST(EraseRangeSingleMinElement) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(1, cache.EraseRange(1, 2));
+ AssertCacheContains(cache, {{5, "x"}, {10, "z"}});
+ }
+
+ Y_UNIT_TEST(EraseRangeSingleMidElement) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(1, cache.EraseRange(5, 6));
+ AssertCacheContains(cache, {{1, "y"}, {10, "z"}});
+ }
+
+ Y_UNIT_TEST(EraseRangeSingleMaxElement) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(1, cache.EraseRange(10, 11));
+ AssertCacheContains(cache, {{5, "x"}, {1, "y"}});
+ }
+
+ Y_UNIT_TEST(EraseRangeSample) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(2, cache.EraseRange(2, 100));
+ AssertCacheContains(cache, {{1, "y"}});
+ }
+
+ Y_UNIT_TEST(EraseRangeAllExact) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(3, cache.EraseRange(1, 11));
+ UNIT_ASSERT_EQUAL(0, cache.Size());
+ }
+
+ Y_UNIT_TEST(EraseRangeAllAmple) {
+ TLogCache cache = SetupCache();
+ UNIT_ASSERT_EQUAL(3, cache.EraseRange(0, 100));
+ UNIT_ASSERT_EQUAL(0, cache.Size());
+ }
+}
+
+} // NPDisk
+} // NKikimr
diff --git a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
index 532ad750833..add4a820ac2 100644
--- a/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
+++ b/ydb/core/blobstorage/pdisk/blobstorage_pdisk_logreader.cpp
@@ -793,11 +793,11 @@ bool TLogReader::ProcessSectorSet(TSectorData *sector) {
<< " LastGoodToWriteLogPosition# " << LastGoodToWriteLogPosition
<< " Marker# LR018");
} else {
-// Y_VERIFY_S(ChunkIdx == LogEndChunkIdx && SectorIdx >= LogEndSectorIdx, SelfInfo()
-// << " File# " << __FILE__
-// << " Line# " << __LINE__
-// << " LogEndChunkIdx# " << LogEndChunkIdx
-// << " LogEndSectorIdx# " << LogEndSectorIdx);
+ Y_VERIFY_S(ChunkIdx == LogEndChunkIdx && SectorIdx >= LogEndSectorIdx, SelfInfo()
+ << " File# " << __FILE__
+ << " Line# " << __LINE__
+ << " LogEndChunkIdx# " << LogEndChunkIdx
+ << " LogEndSectorIdx# " << LogEndSectorIdx);
if (!(ChunkIdx == LogEndChunkIdx && SectorIdx >= LogEndSectorIdx)) {
LOG_WARN_S(*PDisk->ActorSystem, NKikimrServices::BS_PDISK, SelfInfo()
<< " In ProcessSectorSet got !restorator.GoodSectorFlags outside the LogEndSector."
@@ -1147,6 +1147,11 @@ void TLogReader::Reply() {
if (IsInitial) {
PDisk->ProcessChunkOwnerMap(*ChunkOwnerMap.Get());
ChunkOwnerMap.Destroy();
+
+ PDisk->BlockDevice->EraseCacheRange(
+ PDisk->Format.Offset(ChunkIdx, 0),
+ PDisk->Format.Offset(ChunkIdx + 1, 0)
+ );
}
LOG_DEBUG(*PDisk->ActorSystem, NKikimrServices::BS_PDISK, "PDiskId# %" PRIu32 " To ownerId# %" PRIu32 " %s",
(ui32)PDisk->PDiskId, (ui32)Owner, Result->ToString().c_str());
@@ -1387,4 +1392,3 @@ void TLogReader::ReleaseUsedBadOffsets() {
} // NPDisk
} // NKikimr
-
diff --git a/ydb/core/blobstorage/pdisk/ut/CMakeLists.darwin-x86_64.txt b/ydb/core/blobstorage/pdisk/ut/CMakeLists.darwin-x86_64.txt
index 5472736fd16..95f69321e94 100644
--- a/ydb/core/blobstorage/pdisk/ut/CMakeLists.darwin-x86_64.txt
+++ b/ydb/core/blobstorage/pdisk/ut/CMakeLists.darwin-x86_64.txt
@@ -32,6 +32,7 @@ target_link_options(ydb-core-blobstorage-pdisk-ut PRIVATE
target_sources(ydb-core-blobstorage-pdisk-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_crypto_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_races.cpp
diff --git a/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-aarch64.txt b/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-aarch64.txt
index eb05ab2715d..faef05f81f8 100644
--- a/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-aarch64.txt
+++ b/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-aarch64.txt
@@ -35,6 +35,7 @@ target_link_options(ydb-core-blobstorage-pdisk-ut PRIVATE
target_sources(ydb-core-blobstorage-pdisk-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_crypto_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_races.cpp
diff --git a/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-x86_64.txt b/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-x86_64.txt
index 8ad3a8a33fb..268016dec16 100644
--- a/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-x86_64.txt
+++ b/ydb/core/blobstorage/pdisk/ut/CMakeLists.linux-x86_64.txt
@@ -36,6 +36,7 @@ target_link_options(ydb-core-blobstorage-pdisk-ut PRIVATE
target_sources(ydb-core-blobstorage-pdisk-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_crypto_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_races.cpp
diff --git a/ydb/core/blobstorage/pdisk/ut/CMakeLists.windows-x86_64.txt b/ydb/core/blobstorage/pdisk/ut/CMakeLists.windows-x86_64.txt
index 83968ce047d..0533f6adb7d 100644
--- a/ydb/core/blobstorage/pdisk/ut/CMakeLists.windows-x86_64.txt
+++ b/ydb/core/blobstorage/pdisk/ut/CMakeLists.windows-x86_64.txt
@@ -25,6 +25,7 @@ target_link_libraries(ydb-core-blobstorage-pdisk-ut PUBLIC
target_sources(ydb-core-blobstorage-pdisk-ut PRIVATE
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_blockdevice_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_crypto_ut.cpp
+ ${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_log_cache_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_util_ut.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_env.cpp
${CMAKE_SOURCE_DIR}/ydb/core/blobstorage/pdisk/blobstorage_pdisk_ut_races.cpp