diff options
| author | Dan Engelbrecht <[email protected]> | 2023-12-01 07:57:13 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-12-01 13:57:13 +0100 |
| commit | 2755b0dbfd47237e018048598e9c85c71b9a0736 (patch) | |
| tree | ca1e55c43555fc2ff43455f8dfc4ac28daebe42b /src | |
| parent | add separate PreCache step for GcReferenceChecker (#578) (diff) | |
| download | zen-2755b0dbfd47237e018048598e9c85c71b9a0736.tar.xz zen-2755b0dbfd47237e018048598e9c85c71b9a0736.zip | |
use 32 bit offset and size in BlockStoreLocation (#581)
- Improvement: Reduce memory usage in GC and diskbucket flush
Diffstat (limited to 'src')
| -rw-r--r-- | src/zenserver/cache/cachedisklayer.cpp | 113 | ||||
| -rw-r--r-- | src/zenserver/cache/cachedisklayer.h | 6 | ||||
| -rw-r--r-- | src/zenstore/blockstore.cpp | 41 | ||||
| -rw-r--r-- | src/zenstore/compactcas.cpp | 2 | ||||
| -rw-r--r-- | src/zenstore/compactcas.h | 4 | ||||
| -rw-r--r-- | src/zenstore/include/zenstore/blockstore.h | 26 |
6 files changed, 117 insertions, 75 deletions
diff --git a/src/zenserver/cache/cachedisklayer.cpp b/src/zenserver/cache/cachedisklayer.cpp index 955ab3a04..2c344dd1d 100644 --- a/src/zenserver/cache/cachedisklayer.cpp +++ b/src/zenserver/cache/cachedisklayer.cpp @@ -255,8 +255,8 @@ public: uint64_t GetSidecarSize() const { return m_ManifestEntryCount * sizeof(ManifestData); } void WriteSidecarFile(const std::filesystem::path& SidecarPath, uint64_t SnapshotLogPosition, - ZenCacheDiskLayer::CacheBucket::IndexMap&& Index, - std::vector<AccessTime>&& AccessTimes, + const ZenCacheDiskLayer::CacheBucket::IndexMap& Index, + const std::vector<AccessTime>& AccessTimes, const std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>& Payloads, const std::vector<ZenCacheDiskLayer::CacheBucket::BucketMetaData>& MetaDatas); bool ReadSidecarFile(ZenCacheDiskLayer::CacheBucket& Bucket, @@ -265,11 +265,11 @@ public: std::vector<AccessTime>& AccessTimes, std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>& Payloads); - IoBuffer MakeManifest(const Oid& BucketId, - ZenCacheDiskLayer::CacheBucket::IndexMap&& Index, - std::vector<AccessTime>&& AccessTimes, - const std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>& Payloads, - const std::vector<ZenCacheDiskLayer::CacheBucket::BucketMetaData>& MetaDatas); + IoBuffer MakeManifest(const Oid& BucketId, + ZenCacheDiskLayer::CacheBucket::IndexMap&& Index, + std::vector<AccessTime>&& AccessTimes, + std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>&& Payloads, + std::vector<ZenCacheDiskLayer::CacheBucket::BucketMetaData>&& MetaDatas); CbObject Manifest; @@ -399,11 +399,11 @@ BucketManifestSerializer::GenerateNewManifest(std::filesystem::path ManifestPath } IoBuffer -BucketManifestSerializer::MakeManifest(const Oid& BucketId, - ZenCacheDiskLayer::CacheBucket::IndexMap&& Index, - std::vector<AccessTime>&& AccessTimes, - const std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>& Payloads, - const std::vector<ZenCacheDiskLayer::CacheBucket::BucketMetaData>& MetaDatas) +BucketManifestSerializer::MakeManifest(const Oid& BucketId, + ZenCacheDiskLayer::CacheBucket::IndexMap&& Index, + std::vector<AccessTime>&& AccessTimes, + std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>&& Payloads, + std::vector<ZenCacheDiskLayer::CacheBucket::BucketMetaData>&& MetaDatas) { using namespace std::literals; @@ -579,8 +579,8 @@ BucketManifestSerializer::ReadSidecarFile(ZenCacheDiskLayer::CacheBucket& void BucketManifestSerializer::WriteSidecarFile(const std::filesystem::path& SidecarPath, uint64_t SnapshotLogPosition, - ZenCacheDiskLayer::CacheBucket::IndexMap&& Index, - std::vector<AccessTime>&& AccessTimes, + const ZenCacheDiskLayer::CacheBucket::IndexMap& Index, + const std::vector<AccessTime>& AccessTimes, const std::vector<ZenCacheDiskLayer::CacheBucket::BucketPayload>& Payloads, const std::vector<ZenCacheDiskLayer::CacheBucket::BucketMetaData>& MetaDatas) { @@ -605,8 +605,11 @@ BucketManifestSerializer::WriteSidecarFile(const std::filesystem::path& { uint64_t WriteOffset = sizeof Header; - BasicFileWriter SidecarWriter(SidecarFile, 128 * 1024); + // BasicFileWriter SidecarWriter(SidecarFile, 128 * 1024); + std::vector<ManifestData> ManifestDataBuffer; + const size_t MaxManifestDataBufferCount = Min(Index.size(), 4096u); // 256 Kb + ManifestDataBuffer.reserve(MaxManifestDataBufferCount); for (auto& Kv : Index) { const IoHash& Key = Kv.first; @@ -621,12 +624,24 @@ BucketManifestSerializer::WriteSidecarFile(const std::filesystem::path& RawSize = MetaDatas[MetaIndex].RawSize; } - ManifestData ManifestEntry = - {.Key = Key, .Timestamp = AccessTimes[PlIndex], .RawHash = RawHash, .Padding_0 = 0, .RawSize = RawSize, .Padding_1 = 0}; - - SidecarWriter.Write(&ManifestEntry, sizeof ManifestEntry, WriteOffset); - - WriteOffset += sizeof ManifestEntry; + ManifestDataBuffer.emplace_back(ManifestData{.Key = Key, + .Timestamp = AccessTimes[PlIndex], + .RawHash = RawHash, + .Padding_0 = 0, + .RawSize = RawSize, + .Padding_1 = 0}); + if (ManifestDataBuffer.size() == MaxManifestDataBufferCount) + { + const uint64_t WriteSize = sizeof(ManifestData) * ManifestDataBuffer.size(); + SidecarFile.Write(ManifestDataBuffer.data(), WriteSize, WriteOffset); + WriteOffset += WriteSize; + ManifestDataBuffer.clear(); + ManifestDataBuffer.reserve(MaxManifestDataBufferCount); + } + } + if (ManifestDataBuffer.size() > 0) + { + SidecarFile.Write(ManifestDataBuffer.data(), sizeof(ManifestData) * ManifestDataBuffer.size(), WriteOffset); } } @@ -1380,12 +1395,12 @@ ZenCacheDiskLayer::CacheBucket::SaveSnapshot(const std::function<uint64_t()>& Cl { try { - bool UseLegacyScheme = false; - uint64_t SidecarSize = 0; + bool UseLegacyScheme = false; IoBuffer Buffer; BucketManifestSerializer ManifestWriter; + if (UseLegacyScheme) { std::vector<AccessTime> AccessTimes; std::vector<BucketPayload> Payloads; @@ -1403,16 +1418,41 @@ ZenCacheDiskLayer::CacheBucket::SaveSnapshot(const std::function<uint64_t()>& Cl MetaDatas = m_MetaDatas; } - if (UseLegacyScheme) + Buffer = ManifestWriter.MakeManifest(m_BucketId, + std::move(Index), + std::move(AccessTimes), + std::move(Payloads), + std::move(MetaDatas)); + const uint64_t RequiredSpace = Buffer.GetSize() + 1024 * 512; + + std::error_code Error; + DiskSpace Space = DiskSpaceInfo(m_BucketDir, Error); + if (Error) { - Buffer = ManifestWriter.MakeManifest(m_BucketId, std::move(Index), std::move(AccessTimes), Payloads, MetaDatas); + ZEN_WARN("get disk space in '{}' FAILED, reason: '{}'", m_BucketDir, Error.message()); + return; } - else + bool EnoughSpace = Space.Free >= RequiredSpace; + if (!EnoughSpace) { - const uint64_t EntryCount = Index.size(); - Buffer = ManifestWriter.MakeSidecarManifest(m_BucketId, EntryCount); - SidecarSize = ManifestWriter.GetSidecarSize(); + uint64_t ReclaimedSpace = ClaimDiskReserveFunc(); + EnoughSpace = (Space.Free + ReclaimedSpace) >= RequiredSpace; } + if (!EnoughSpace) + { + ZEN_WARN("not enough free disk space in '{}'. FAILED to save manifest of size {}", + m_BucketDir, + NiceBytes(Buffer.GetSize())); + return; + } + } + else + { + RwLock::SharedLockScope IndexLock(m_IndexLock); + WriteIndexSnapshot(); + const uint64_t EntryCount = m_Index.size(); + Buffer = ManifestWriter.MakeSidecarManifest(m_BucketId, EntryCount); + uint64_t SidecarSize = ManifestWriter.GetSidecarSize(); const uint64_t RequiredSpace = SidecarSize + Buffer.GetSize() + 1024 * 512; @@ -1437,15 +1477,12 @@ ZenCacheDiskLayer::CacheBucket::SaveSnapshot(const std::function<uint64_t()>& Cl return; } - if (!UseLegacyScheme) - { - ManifestWriter.WriteSidecarFile(GetMetaPath(m_BucketDir, m_BucketName), - m_LogFlushPosition, - std::move(Index), - std::move(AccessTimes), - Payloads, - MetaDatas); - } + ManifestWriter.WriteSidecarFile(GetMetaPath(m_BucketDir, m_BucketName), + m_LogFlushPosition, + m_Index, + m_AccessTimes, + m_Payloads, + m_MetaDatas); } std::filesystem::path ManifestPath = GetManifestPath(m_BucketDir, m_BucketName); diff --git a/src/zenserver/cache/cachedisklayer.h b/src/zenserver/cache/cachedisklayer.h index 55d2a98f4..11f474d5a 100644 --- a/src/zenserver/cache/cachedisklayer.h +++ b/src/zenserver/cache/cachedisklayer.h @@ -29,7 +29,7 @@ struct DiskLocation inline DiskLocation(uint64_t ValueSize, uint8_t Flags) : Flags(Flags | kStandaloneFile) { Location.StandaloneSize = ValueSize; } - inline DiskLocation(const BlockStoreLocation& Location, uint64_t PayloadAlignment, uint8_t Flags) : Flags(Flags & ~kStandaloneFile) + inline DiskLocation(const BlockStoreLocation& Location, uint32_t PayloadAlignment, uint8_t Flags) : Flags(Flags & ~kStandaloneFile) { this->Location.BlockLocation = BlockStoreDiskLocation(Location, PayloadAlignment); } @@ -47,7 +47,7 @@ struct DiskLocation return Location.BlockLocation != Rhs.Location.BlockLocation; } - inline BlockStoreLocation GetBlockLocation(uint64_t PayloadAlignment) const + inline BlockStoreLocation GetBlockLocation(uint32_t PayloadAlignment) const { ZEN_ASSERT(!(Flags & kStandaloneFile)); return Location.BlockLocation.Get(PayloadAlignment); @@ -106,7 +106,7 @@ public: struct BucketConfiguration { uint64_t MaxBlockSize = 1ull << 30; - uint64_t PayloadAlignment = 1ull << 4; + uint32_t PayloadAlignment = 1u << 4; uint64_t MemCacheSizeThreshold = 1 * 1024; uint64_t LargeObjectThreshold = 128 * 1024; bool EnableReferenceCaching = false; diff --git a/src/zenstore/blockstore.cpp b/src/zenstore/blockstore.cpp index cc727787f..918f464ac 100644 --- a/src/zenstore/blockstore.cpp +++ b/src/zenstore/blockstore.cpp @@ -384,7 +384,7 @@ BlockStore::GetFreeBlockIndex(uint32_t ProbeIndex, RwLock::ExclusiveLockScope&, } void -BlockStore::WriteChunk(const void* Data, uint64_t Size, uint64_t Alignment, const WriteChunkCallback& Callback) +BlockStore::WriteChunk(const void* Data, uint64_t Size, uint32_t Alignment, const WriteChunkCallback& Callback) { ZEN_TRACE_CPU("BlockStore::WriteChunk"); @@ -393,12 +393,14 @@ BlockStore::WriteChunk(const void* Data, uint64_t Size, uint64_t Alignment, cons ZEN_ASSERT(Size <= m_MaxBlockSize); ZEN_ASSERT(Alignment > 0u); + uint32_t ChunkSize = gsl::narrow<uint32_t>(Size); + RwLock::ExclusiveLockScope InsertLock(m_InsertLock); uint32_t WriteBlockIndex = m_WriteBlockIndex.load(std::memory_order_acquire); bool IsWriting = !!m_WriteBlock; - uint64_t AlignedInsertOffset = RoundUp(m_CurrentInsertOffset, Alignment); - if (!IsWriting || (AlignedInsertOffset + Size) > m_MaxBlockSize) + uint32_t AlignedInsertOffset = RoundUp(m_CurrentInsertOffset, Alignment); + if (!IsWriting || (AlignedInsertOffset + ChunkSize) > m_MaxBlockSize) { if (m_WriteBlock) { @@ -423,16 +425,16 @@ BlockStore::WriteChunk(const void* Data, uint64_t Size, uint64_t Alignment, cons m_CurrentInsertOffset = 0; AlignedInsertOffset = 0; } - uint64_t AlignedWriteSize = AlignedInsertOffset - m_CurrentInsertOffset + Size; - m_CurrentInsertOffset = AlignedInsertOffset + Size; + uint32_t AlignedWriteSize = AlignedInsertOffset - m_CurrentInsertOffset + ChunkSize; + m_CurrentInsertOffset = AlignedInsertOffset + ChunkSize; Ref<BlockStoreFile> WriteBlock = m_WriteBlock; m_ActiveWriteBlocks.push_back(WriteBlockIndex); InsertLock.ReleaseNow(); - WriteBlock->Write(Data, Size, AlignedInsertOffset); + WriteBlock->Write(Data, ChunkSize, AlignedInsertOffset); m_TotalSize.fetch_add(AlignedWriteSize, std::memory_order::relaxed); - Callback({.BlockIndex = WriteBlockIndex, .Offset = AlignedInsertOffset, .Size = Size}); + Callback({.BlockIndex = WriteBlockIndex, .Offset = AlignedInsertOffset, .Size = ChunkSize}); { RwLock::ExclusiveLockScope _(m_InsertLock); @@ -505,7 +507,7 @@ void BlockStore::ReclaimSpace(const ReclaimSnapshotState& Snapshot, const std::vector<BlockStoreLocation>& ChunkLocations, const ChunkIndexArray& KeepChunkIndexes, - uint64_t PayloadAlignment, + uint32_t PayloadAlignment, bool DryRun, const ReclaimCallback& ChangeCallback, const ClaimDiskReserveCallback& DiskReserveCallback) @@ -754,9 +756,9 @@ BlockStore::ReclaimSpace(const ReclaimSnapshotState& Snapshot, { const BlockStoreLocation ChunkLocation = ChunkLocations[ChunkIndex]; Chunk.resize(ChunkLocation.Size); - OldBlockFile->Read(Chunk.data(), Chunk.size(), ChunkLocation.Offset); + OldBlockFile->Read(Chunk.data(), ChunkLocation.Size, ChunkLocation.Offset); - if (!NewBlockFile || (WriteOffset + Chunk.size() > m_MaxBlockSize)) + if (!NewBlockFile || (WriteOffset + ChunkLocation.Size > m_MaxBlockSize)) { uint32_t NextBlockIndex = m_WriteBlockIndex.load(std::memory_order_relaxed); @@ -830,10 +832,12 @@ BlockStore::ReclaimSpace(const ReclaimSnapshotState& Snapshot, WriteOffset = 0; } - NewBlockFile->Write(Chunk.data(), Chunk.size(), WriteOffset); - MovedChunks.push_back({ChunkIndex, {.BlockIndex = NewBlockIndex, .Offset = WriteOffset, .Size = Chunk.size()}}); + NewBlockFile->Write(Chunk.data(), ChunkLocation.Size, WriteOffset); + MovedChunks.push_back( + {ChunkIndex, + {.BlockIndex = NewBlockIndex, .Offset = gsl::narrow<uint32_t>(WriteOffset), .Size = ChunkLocation.Size}}); uint64_t OldOffset = WriteOffset; - WriteOffset = RoundUp(WriteOffset + Chunk.size(), PayloadAlignment); + WriteOffset = RoundUp(WriteOffset + ChunkLocation.Size, PayloadAlignment); m_TotalSize.fetch_add(WriteOffset - OldOffset, std::memory_order::relaxed); } Chunk.clear(); @@ -1033,7 +1037,7 @@ BlockStore::IterateChunks(const std::vector<BlockStoreLocation>& ChunkLocations, void BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, - uint64_t PayloadAlignment, + uint32_t PayloadAlignment, const CompactCallback& ChangeCallback, const ClaimDiskReserveCallback& DiskReserveCallback) { @@ -1218,9 +1222,10 @@ BlockStore::CompactBlocks(const BlockStoreCompactState& CompactState, WriteOffset = 0; } - NewBlockFile->Write(Chunk.data(), Chunk.size(), WriteOffset); - MovedChunks.push_back({ChunkIndex, {.BlockIndex = NewBlockIndex, .Offset = WriteOffset, .Size = Chunk.size()}}); - WriteOffset = RoundUp(WriteOffset + Chunk.size(), PayloadAlignment); + NewBlockFile->Write(Chunk.data(), ChunkLocation.Size, WriteOffset); + MovedChunks.push_back( + {ChunkIndex, {.BlockIndex = NewBlockIndex, .Offset = gsl::narrow<uint32_t>(WriteOffset), .Size = ChunkLocation.Size}}); + WriteOffset = RoundUp(WriteOffset + ChunkLocation.Size, PayloadAlignment); AddedSize += Chunk.size(); } Chunk.clear(); @@ -1403,7 +1408,7 @@ TEST_CASE("blockstore.blockfile") } namespace blockstore::impl { - BlockStoreLocation WriteStringAsChunk(BlockStore& Store, std::string_view String, size_t PayloadAlignment) + BlockStoreLocation WriteStringAsChunk(BlockStore& Store, std::string_view String, uint32_t PayloadAlignment) { BlockStoreLocation Location; Store.WriteChunk(String.data(), String.length(), PayloadAlignment, [&](const BlockStoreLocation& L) { Location = L; }); diff --git a/src/zenstore/compactcas.cpp b/src/zenstore/compactcas.cpp index e9a0a437b..5de82f219 100644 --- a/src/zenstore/compactcas.cpp +++ b/src/zenstore/compactcas.cpp @@ -130,7 +130,7 @@ void CasContainerStrategy::Initialize(const std::filesystem::path& RootDirectory, const std::string_view ContainerBaseName, uint32_t MaxBlockSize, - uint64_t Alignment, + uint32_t Alignment, bool IsNewStore) { ZEN_ASSERT(IsPow2(Alignment)); diff --git a/src/zenstore/compactcas.h b/src/zenstore/compactcas.h index 3ed883801..932844da7 100644 --- a/src/zenstore/compactcas.h +++ b/src/zenstore/compactcas.h @@ -58,7 +58,7 @@ struct CasContainerStrategy final : public GcStorage, public GcReferenceStore void Initialize(const std::filesystem::path& RootDirectory, const std::string_view ContainerBaseName, uint32_t MaxBlockSize, - uint64_t Alignment, + uint32_t Alignment, bool IsNewStore); void Flush(); @@ -84,7 +84,7 @@ private: LoggerRef m_Log; GcManager& m_Gc; std::filesystem::path m_RootDirectory; - uint64_t m_PayloadAlignment = 1u << 4; + uint32_t m_PayloadAlignment = 1u << 4; uint64_t m_MaxBlockSize = 1u << 28; bool m_IsInitialized = false; TCasLogFile<CasDiskIndexEntry> m_CasLog; diff --git a/src/zenstore/include/zenstore/blockstore.h b/src/zenstore/include/zenstore/blockstore.h index dcd4b5e87..919684e41 100644 --- a/src/zenstore/include/zenstore/blockstore.h +++ b/src/zenstore/include/zenstore/blockstore.h @@ -16,8 +16,8 @@ namespace zen { struct BlockStoreLocation { uint32_t BlockIndex; - uint64_t Offset; - uint64_t Size; + uint32_t Offset; + uint32_t Size; inline auto operator<=>(const BlockStoreLocation& Rhs) const = default; }; @@ -32,19 +32,19 @@ struct BlockStoreDiskLocation constexpr static uint32_t MaxBlockIndex = (1ul << BlockStoreDiskLocation::MaxBlockIndexBits) - 1ul; constexpr static uint32_t MaxOffset = (1ul << BlockStoreDiskLocation::MaxOffsetBits) - 1ul; - BlockStoreDiskLocation(const BlockStoreLocation& Location, uint64_t OffsetAlignment) + BlockStoreDiskLocation(const BlockStoreLocation& Location, uint32_t OffsetAlignment) { Init(Location.BlockIndex, Location.Offset / OffsetAlignment, Location.Size); } BlockStoreDiskLocation() = default; - inline BlockStoreLocation Get(uint64_t OffsetAlignment) const + inline BlockStoreLocation Get(uint32_t OffsetAlignment) const { uint64_t PackedOffset = 0; memcpy(&PackedOffset, &m_Offset, sizeof m_Offset); - return {.BlockIndex = static_cast<std::uint32_t>(PackedOffset >> MaxOffsetBits), - .Offset = (PackedOffset & MaxOffset) * OffsetAlignment, + return {.BlockIndex = static_cast<uint32_t>(PackedOffset >> MaxOffsetBits), + .Offset = static_cast<uint32_t>((PackedOffset & MaxOffset) * OffsetAlignment), .Size = GetSize()}; } @@ -55,14 +55,14 @@ struct BlockStoreDiskLocation return static_cast<std::uint32_t>(PackedOffset >> MaxOffsetBits); } - inline uint64_t GetOffset(uint64_t OffsetAlignment) const + inline uint32_t GetOffset(uint32_t OffsetAlignment) const { uint64_t PackedOffset = 0; memcpy(&PackedOffset, &m_Offset, sizeof m_Offset); - return (PackedOffset & MaxOffset) * OffsetAlignment; + return static_cast<uint32_t>((PackedOffset & MaxOffset) * OffsetAlignment); } - inline uint64_t GetSize() const { return m_Size; } + inline uint32_t GetSize() const { return m_Size; } inline auto operator<=>(const BlockStoreDiskLocation& Rhs) const = default; @@ -150,7 +150,7 @@ public: void Close(); - void WriteChunk(const void* Data, uint64_t Size, uint64_t Alignment, const WriteChunkCallback& Callback); + void WriteChunk(const void* Data, uint64_t Size, uint32_t Alignment, const WriteChunkCallback& Callback); IoBuffer TryGetChunk(const BlockStoreLocation& Location) const; void Flush(bool ForceNewBlock); @@ -160,7 +160,7 @@ public: const ReclaimSnapshotState& Snapshot, const std::vector<BlockStoreLocation>& ChunkLocations, const ChunkIndexArray& KeepChunkIndexes, - uint64_t PayloadAlignment, + uint32_t PayloadAlignment, bool DryRun, const ReclaimCallback& ChangeCallback = [](const MovedChunksArray&, const ChunkIndexArray&) {}, const ClaimDiskReserveCallback& DiskReserveCallback = []() { return 0; }); @@ -171,7 +171,7 @@ public: void CompactBlocks( const BlockStoreCompactState& CompactState, - uint64_t PayloadAlignment, + uint32_t PayloadAlignment, const CompactCallback& ChangeCallback = [](const MovedChunksArray&, uint64_t) { return true; }, const ClaimDiskReserveCallback& DiskReserveCallback = []() { return 0; }); @@ -189,7 +189,7 @@ private: mutable RwLock m_InsertLock; // used to serialize inserts Ref<BlockStoreFile> m_WriteBlock; - std::uint64_t m_CurrentInsertOffset = 0; + std::uint32_t m_CurrentInsertOffset = 0; std::atomic_uint32_t m_WriteBlockIndex{}; std::vector<uint32_t> m_ActiveWriteBlocks; |