aboutsummaryrefslogtreecommitdiff
path: root/zenstore/compactcas.h
blob: 2acac7ca392d3e25e31a88d10ce6b6cce638d74d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/zencore.h>
#include <zenstore/blockstore.h>
#include <zenstore/caslog.h>
#include <zenstore/gc.h>

#include "cas.h"

#include <atomic>
#include <limits>
#include <unordered_map>

namespace spdlog {
class logger;
}

namespace zen {

//////////////////////////////////////////////////////////////////////////

#pragma pack(push)
#pragma pack(1)

struct CasDiskIndexEntry
{
	static const uint8_t kTombstone = 0x01;

	IoHash				   Key;
	BlockStoreDiskLocation Location;
	ZenContentType		   ContentType = ZenContentType::kUnknownContentType;
	uint8_t				   Flags	   = 0;
};

#pragma pack(pop)

static_assert(sizeof(CasDiskIndexEntry) == 32);

/** This implements a storage strategy for small CAS values
 *
 * New chunks are simply appended to a small object file, and an index is
 * maintained to allow chunks to be looked up within the active small object
 * files
 *
 */

struct CasContainerStrategy final : public GcStorage
{
	CasContainerStrategy(GcManager& Gc);
	~CasContainerStrategy();

	CasStore::InsertResult InsertChunk(IoBuffer Chunk, const IoHash& ChunkHash);
	IoBuffer			   FindChunk(const IoHash& ChunkHash);
	bool				   HaveChunk(const IoHash& ChunkHash);
	void				   FilterChunks(HashKeySet& InOutChunks);
	void				   Initialize(const std::filesystem::path& RootDirectory,
									  const std::string_view	   ContainerBaseName,
									  uint32_t					   MaxBlockSize,
									  uint64_t					   Alignment,
									  bool						   IsNewStore);
	void				   Flush();
	void				   Scrub(ScrubContext& Ctx);
	virtual void		   CollectGarbage(GcContext& GcCtx) override;
	virtual GcStorageSize  StorageSize() const override { return {.DiskSize = m_TotalSize.load(std::memory_order::acquire)}; }

private:
	CasStore::InsertResult InsertChunk(const void* ChunkData, size_t ChunkSize, const IoHash& ChunkHash);
	void				   MakeIndexSnapshot();
	uint64_t			   ReadIndexFile();
	uint64_t			   ReadLog(uint64_t SkipEntryCount);
	void				   OpenContainer(bool IsNewStore);

	spdlog::logger& Log() { return m_Log; }

	std::filesystem::path		   m_RootDirectory;
	spdlog::logger&				   m_Log;
	uint64_t					   m_PayloadAlignment = 1u << 4;
	uint64_t					   m_MaxBlockSize	  = 1u << 28;
	bool						   m_IsInitialized	  = false;
	TCasLogFile<CasDiskIndexEntry> m_CasLog;
	std::string					   m_ContainerBaseName;
	std::filesystem::path		   m_BlocksBasePath;
	BlockStore					   m_BlockStore;

	RwLock																	   m_LocationMapLock;
	typedef std::unordered_map<IoHash, BlockStoreDiskLocation, IoHash::Hasher> LocationMap_t;
	LocationMap_t															   m_LocationMap;

	std::atomic_uint64_t m_TotalSize{};
};

void compactcas_forcelink();

}  // namespace zen