GCC Code Coverage Report


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