Directory: | cvmfs/ |
---|---|
File: | cvmfs/kvstore.h |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 23 | 23 | 100.0% |
Branches: | 39 | 78 | 50.0% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #ifndef CVMFS_KVSTORE_H_ | ||
6 | #define CVMFS_KVSTORE_H_ | ||
7 | |||
8 | #include <pthread.h> | ||
9 | #include <unistd.h> | ||
10 | |||
11 | #include <string> | ||
12 | #include <vector> | ||
13 | |||
14 | #include "cache.h" | ||
15 | #include "lru.h" | ||
16 | #include "malloc_heap.h" | ||
17 | #include "statistics.h" | ||
18 | #include "util/async.h" | ||
19 | #include "util/single_copy.h" | ||
20 | |||
21 | using namespace std; // NOLINT | ||
22 | |||
23 | |||
24 | /** | ||
25 | * All objects in memory are prepended by an AllocHeader that allows the | ||
26 | * Key-Value store to find the pointer when the heap memory manager compacts | ||
27 | * the allocations. | ||
28 | */ | ||
29 | struct AllocHeader { | ||
30 | 254 | AllocHeader() : version(0), id() { } | |
31 | uint8_t version; | ||
32 | shash::Any id; | ||
33 | }; | ||
34 | |||
35 | |||
36 | /** | ||
37 | * A MmeoryBuffer is used in the staging phase of new objects until they are | ||
38 | * committed. | ||
39 | */ | ||
40 | struct MemoryBuffer { | ||
41 | 306086 | MemoryBuffer() | |
42 | 306086 | : address(NULL) | |
43 | 306086 | , size(0) | |
44 | 306086 | , refcount(0) | |
45 | 306086 | , object_flags(0) | |
46 | 306086 | , id() {} | |
47 | void *address; | ||
48 | size_t size; | ||
49 | unsigned int refcount; | ||
50 | int object_flags; | ||
51 | shash::Any id; | ||
52 | }; | ||
53 | |||
54 | |||
55 | /** | ||
56 | * @p MemoryKvStore provides a simple RAM-backed key/value store suited to | ||
57 | * use with @ref RamCacheManager. To insert entries, the caller must allocate | ||
58 | * some memory and can choose to set some metadata such as object type. | ||
59 | * @p MemoryKvStore takes ownership of the passed-in memory and maintains | ||
60 | * reference counts for all its objects. Callers must increment the reference | ||
61 | * count on an entry before reading to ensure that the entry is not removed | ||
62 | * mid-operation, and decrement the reference count when done. The store | ||
63 | * can attempt to reduce its size by removing the least recently used | ||
64 | * entries without any outstanding references. | ||
65 | */ | ||
66 | class MemoryKvStore : SingleCopy, public Callbackable<MallocHeap::BlockPtr> { | ||
67 | public: | ||
68 | enum MemoryAllocator { | ||
69 | kMallocLibc, | ||
70 | kMallocHeap, | ||
71 | }; | ||
72 | |||
73 | struct Counters { | ||
74 | perf::Counter *sz_size; | ||
75 | perf::Counter *n_getsize; | ||
76 | perf::Counter *n_getrefcount; | ||
77 | perf::Counter *n_incref; | ||
78 | perf::Counter *n_unref; | ||
79 | perf::Counter *n_read; | ||
80 | perf::Counter *n_commit; | ||
81 | perf::Counter *n_delete; | ||
82 | perf::Counter *n_shrinkto; | ||
83 | perf::Counter *sz_read; | ||
84 | perf::Counter *sz_committed; | ||
85 | perf::Counter *sz_deleted; | ||
86 | perf::Counter *sz_shrunk; | ||
87 | |||
88 | 63 | explicit Counters(perf::StatisticsTemplate statistics) { | |
89 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | sz_size = statistics.RegisterTemplated("sz_size", "Total size"); |
90 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_getsize = statistics.RegisterTemplated("n_getsize", |
91 | "Number of GetSize calls"); | ||
92 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_getrefcount = statistics.RegisterTemplated("n_getrefcount", |
93 | "Number of GetRefcount calls"); | ||
94 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_incref = statistics.RegisterTemplated("n_incref", |
95 | "Number of IncRef calls"); | ||
96 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_unref = statistics.RegisterTemplated("n_unref", |
97 | "Number of Unref calls"); | ||
98 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_read = statistics.RegisterTemplated("n_read", "Number of Read calls"); |
99 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_commit = statistics.RegisterTemplated("n_commit", |
100 | "Number of Commit calls"); | ||
101 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_delete = statistics.RegisterTemplated("n_delete", |
102 | "Number of Delete calls"); | ||
103 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | n_shrinkto = statistics.RegisterTemplated("n_shrinkto", |
104 | "Number of ShrinkTo calls"); | ||
105 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | sz_read = statistics.RegisterTemplated("sz_read", "Bytes read"); |
106 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | sz_committed = statistics.RegisterTemplated("sz_committed", |
107 | "Bytes committed"); | ||
108 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | sz_deleted = statistics.RegisterTemplated("sz_deleted", "Bytes deleted"); |
109 |
3/6✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 63 times.
✗ Branch 10 not taken.
|
63 | sz_shrunk = statistics.RegisterTemplated("sz_shrunk", "Bytes shrunk"); |
110 | 63 | } | |
111 | }; | ||
112 | |||
113 | MemoryKvStore( | ||
114 | unsigned int cache_entries, | ||
115 | MemoryAllocator alloc, | ||
116 | unsigned alloc_size, | ||
117 | perf::StatisticsTemplate statistics); | ||
118 | |||
119 | ~MemoryKvStore(); | ||
120 | |||
121 | /** | ||
122 | * Check for the existence of an entry | ||
123 | * @param id The hash key | ||
124 | * @returns True iff the entry exists | ||
125 | */ | ||
126 | bool Contains(const shash::Any &id); | ||
127 | |||
128 | /** | ||
129 | * Get the size in bytes of the entry at id | ||
130 | * @param id The hash key | ||
131 | * @returns The entry's size | ||
132 | * @retval -ENOENT The entry is absent | ||
133 | */ | ||
134 | int64_t GetSize(const shash::Any &id); | ||
135 | |||
136 | /** | ||
137 | * Get the number of references to the entry at id | ||
138 | * @param id The hash key | ||
139 | * @returns A reference count | ||
140 | * @retval -ENOENT The entry is absent | ||
141 | */ | ||
142 | int64_t GetRefcount(const shash::Any &id); | ||
143 | |||
144 | /** | ||
145 | * Increase the reference count on the entry at id | ||
146 | * @param id The hash key | ||
147 | * @returns True if the entry exists and was updated | ||
148 | */ | ||
149 | bool IncRef(const shash::Any &id); | ||
150 | |||
151 | /** | ||
152 | * Decrease the reference count on the entry at id. If the refcount is zero, no effect | ||
153 | * @param id The hash key | ||
154 | * @returns True if the entry exists and was updated | ||
155 | */ | ||
156 | bool Unref(const shash::Any &id); | ||
157 | |||
158 | /** | ||
159 | * Copy a portion of the entry at id to the given address. See pread(2) | ||
160 | * @param id The hash key | ||
161 | * @param buf The address at which to write the data | ||
162 | * @param size The number of bytes to copy | ||
163 | * @param offset The offset within the entry to start the copy | ||
164 | * @returns The number of bytes copied | ||
165 | * @retval -ENOENT The entry is absent | ||
166 | */ | ||
167 | int64_t Read( | ||
168 | const shash::Any &id, | ||
169 | void *buf, | ||
170 | size_t size, | ||
171 | size_t offset); | ||
172 | |||
173 | /** | ||
174 | * Insert a new memory buffer. The KvStore copies the referred memory, so | ||
175 | * callers may free() their buffers after Commit returns | ||
176 | * @param buf The memory buffer to insert | ||
177 | * @returns -ENFILE if too many file handles are in use | ||
178 | * @returns -EIO if memory allocation fails | ||
179 | */ | ||
180 | int Commit(const MemoryBuffer &buf); | ||
181 | |||
182 | /** | ||
183 | * Delete an entry, free()ing its memory. Note that the entry not have any references | ||
184 | * @param id The hash key | ||
185 | * @returns True iff the entry was successfully deleted | ||
186 | */ | ||
187 | bool Delete(const shash::Any &id); | ||
188 | |||
189 | /** | ||
190 | * Delete the oldest entries until the KvStore uses less than the given size. | ||
191 | * Entries with nonzero refcount will not be deleted. | ||
192 | * @param size The maximum size to make the KvStore | ||
193 | * @returns True iff the shrink succeeds | ||
194 | */ | ||
195 | bool ShrinkTo(size_t size); | ||
196 | |||
197 | /** | ||
198 | * Get the total space used for data | ||
199 | */ | ||
200 | 177 | size_t GetUsed() { return used_bytes_; } | |
201 | |||
202 | private: | ||
203 | // Compact memory once utilization falls below the threshold | ||
204 | static const double kCompactThreshold; // = 0.8 | ||
205 | |||
206 | bool DoDelete(const shash::Any &id); | ||
207 | int DoMalloc(MemoryBuffer *buf); | ||
208 | void DoFree(MemoryBuffer *buf); | ||
209 | int DoCommit(const MemoryBuffer &buf); | ||
210 | void OnBlockMove(const MallocHeap::BlockPtr &ptr); | ||
211 | bool CompactMemory(); | ||
212 | |||
213 | MemoryAllocator allocator_; | ||
214 | size_t used_bytes_; | ||
215 | unsigned int entry_count_; | ||
216 | unsigned int max_entries_; | ||
217 | lru::LruCache<shash::Any, MemoryBuffer> entries_; | ||
218 | MallocHeap *heap_; | ||
219 | pthread_rwlock_t rwlock_; | ||
220 | Counters counters_; | ||
221 | }; | ||
222 | |||
223 | #endif // CVMFS_KVSTORE_H_ | ||
224 |