GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/cache.h
Date: 2026-07-05 02:36:18
Exec Total Coverage
Lines: 28 37 75.7%
Branches: 8 10 80.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_CACHE_H_
6 #define CVMFS_CACHE_H_
7
8 #include <stdint.h>
9
10 #include <string>
11
12 #include "compression/compression.h"
13 #include "crypto/hash.h"
14 #include "manifest.h"
15
16
17 class QuotaManager;
18
19 enum CacheManagerIds {
20 kUnknownCacheManager = 0,
21 kPosixCacheManager,
22 kRamCacheManager,
23 kTieredCacheManager,
24 kExternalCacheManager,
25 kStreamingCacheManager,
26 };
27
28 enum CacheModes {
29 kCacheReadWrite = 0,
30 kCacheReadOnly,
31 };
32
33
34 /**
35 * The Cache Manager provides (virtual) file descriptors to content-addressable
36 * objects in the cache. The implementation can use a POSIX file system or
37 * other means such as a key-value store. A file descriptor must remain
38 * readable until closed, no matter if it is removed from the backend storage
39 * or not (POSIX semantics).
40 *
41 * Writing into the cache is streamed and transactional: a file descriptor must
42 * be acquired from StartTxn and the object is only visible in the cache after
43 * CommitTxn. The state of the transaction is carried in an opque transaction
44 * object, which needs to be provided by the caller. The size of the object is
45 * returned by SizeOfTxn. This way, users of derived classes can take care of
46 * the storage allocation (e.g. on the stack), while the derived class
47 * determines the contents of the transaction object. For race-free read access
48 * to objects that are just being written to the cache, the OpenFromTxn routine
49 * is used just before the transaction is committed.
50 *
51 * Writing to the cache can be coupled to a quota manager. The quota manager
52 * maintains some extra information for data chunks: whether they are
53 * volatile, whether they are pinned, and a description (usually the path that
54 * corresponds to a data chunk). By default the NoopQuotaManager is used, which
55 * ignores all this extra information. The CtrlTxn() function is used to
56 * specify this extra information sometime between StartTxn() and CommitTxn().
57 *
58 * The integer return values can be negative and, in this case, represent a
59 * -errno failure code. Otherwise the return value 0 indicates a success, or
60 * >= 0 for a file descriptor.
61 */
62 class CacheManager : SingleCopy {
63 public:
64 /**
65 * Sizes of objects should be known for StartTxn(). For file catalogs we
66 * cannot ensure that, however, because the size field for nested catalogs
67 * was only recently added.
68 */
69 static const uint64_t kSizeUnknown;
70
71 /**
72 * Relevant for the quota management and for downloading (URL construction).
73 * Used in Label::flags.
74 */
75 static const int kLabelCatalog = 0x01;
76 static const int kLabelPinned = 0x02;
77 static const int kLabelVolatile = 0x04;
78 static const int kLabelExternal = 0x08;
79 static const int kLabelChunked = 0x10;
80 static const int kLabelCertificate = 0x20;
81 static const int kLabelMetainfo = 0x40;
82 static const int kLabelHistory = 0x80;
83
84 /**
85 * Meta-data of an object that the cache may or may not maintain/use.
86 * Good cache implementations should at least distinguish between volatile
87 * and regular objects. The data in the label are sufficient to download an
88 * object, if necessary.
89 */
90 struct Label {
91 21777 Label()
92 21777 : flags(0)
93 21777 , size(kSizeUnknown)
94 21777 , zip_algorithm(zlib::kZlibDefault)
95 21777 , range_offset(-1) { }
96
97 7847 bool IsCatalog() const { return flags & kLabelCatalog; }
98 4000 bool IsPinned() const { return flags & kLabelPinned; }
99 1495 bool IsExternal() const { return flags & kLabelExternal; }
100 4 bool IsCertificate() const { return flags & kLabelCertificate; }
101
102 bool operator==(const Label &other) const {
103 return flags == other.flags and size == other.size
104 and zip_algorithm == other.zip_algorithm
105 and range_offset == other.range_offset and path == other.path;
106 }
107 /**
108 * The description for the quota manager
109 */
110 30677 std::string GetDescription() const {
111
2/2
✓ Branch 0 taken 1368 times.
✓ Branch 1 taken 29309 times.
30677 if (flags & kLabelCatalog)
112 1368 return "file catalog at " + path;
113
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 29105 times.
29309 if (flags & kLabelCertificate)
114 204 return "certificate for " + path;
115
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29105 times.
29105 if (flags & kLabelMetainfo)
116 return "metainfo for " + path;
117
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 29071 times.
29105 if (flags & kLabelHistory)
118 34 return "tag database for " + path;
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29071 times.
29071 if (flags & kLabelChunked)
120 return "Part of " + path;
121 29071 return path;
122 }
123
124 int flags;
125 uint64_t size; ///< unzipped size, if known
126 zlib::Algorithms zip_algorithm;
127 off_t range_offset;
128 /**
129 * The logical path on the mountpoint connected to the object. For meta-
130 * data objects, e.g. certificate, catalog, it's the repository name (which
131 * does not start with a slash).
132 */
133 std::string path;
134 };
135
136 /**
137 * A content hash together with the meta-data from a (partial) label.
138 */
139 struct LabeledObject {
140 9691 explicit LabeledObject(const shash::Any &id) : id(id), label() { }
141 5866 LabeledObject(const shash::Any &id, const Label &l) : id(id), label(l) { }
142
143 bool operator==(const LabeledObject &other) const {
144 return id == other.id && label == other.label;
145 }
146
147 shash::Any id;
148 Label label;
149 };
150
151 virtual CacheManagerIds id() = 0;
152 /**
153 * Return a human readable description of the cache instance. Used in
154 * cvmfs_talk.
155 */
156 virtual std::string Describe() = 0;
157
158 virtual bool AcquireQuotaManager(QuotaManager *quota_mgr) = 0;
159
160 virtual ~CacheManager();
161 /**
162 * Opening an object might get it from a third-party source, e.g. when the
163 * tiered cache manager issues a copy-up operation. In this case it is
164 * beneficial to register the object with the accurate meta-data, in the same
165 * way it is done during transactions.
166 */
167 virtual int Open(const LabeledObject &object) = 0;
168 virtual int64_t GetSize(int fd) = 0;
169 virtual int Close(int fd) = 0;
170 virtual int64_t Pread(int fd, void *buf, uint64_t size, uint64_t offset) = 0;
171 virtual int Dup(int fd) = 0;
172 virtual int Readahead(int fd) = 0;
173
174 virtual uint32_t SizeOfTxn() = 0;
175 virtual int StartTxn(const shash::Any &id, uint64_t size, void *txn) = 0;
176 virtual void CtrlTxn(const Label &label,
177 const int flags, // reserved for future use
178 void *txn) = 0;
179 virtual int64_t Write(const void *buf, uint64_t sz, void *txn) = 0;
180 virtual int Reset(void *txn) = 0;
181 virtual int AbortTxn(void *txn) = 0;
182 virtual int OpenFromTxn(void *txn) = 0;
183 virtual int CommitTxn(void *txn) = 0;
184
185 virtual void Spawn() = 0;
186
187 int ChecksumFd(int fd, shash::Any *id);
188 int OpenPinned(const LabeledObject &object);
189 bool Open2Mem(const LabeledObject &object, unsigned char **buffer,
190 uint64_t *size);
191 bool CommitFromMem(const LabeledObject &object,
192 const unsigned char *buffer,
193 const uint64_t size);
194
195 1329 QuotaManager *quota_mgr() { return quota_mgr_; }
196
197 // Rescue the open file table during reload of the fuse module. For the
198 // POSIX cache, nothing needs to be done because the table is keep in the
199 // kernel for the process. Other cache managers need to do it manually.
200 void *SaveState(const int fd_progress);
201 /**
202 * When RestoreState is called, the cache has already exactly one file
203 * descriptor open: the root file catalog. This file descriptor might be
204 * remapped to another number. A return value of -1 means no action needs
205 * to take place. A smaller value indicates an error.
206 */
207 int RestoreState(const int fd_progress, void *state);
208 void FreeState(const int fd_progress, void *state);
209 CacheManagerIds PeekState(void *state) {
210 return static_cast<State *>(state)->manager_type;
211 }
212
213 /**
214 * While not strictly necessary, cache managers often have a directory
215 * associated with them. This directory is currently used to find the
216 * cached manifest copy, the cvmfschecksum.$reponame file. This is important
217 * to make pre-loaded alien caches work, even in a tiered setup.
218 */
219 470 virtual manifest::Breadcrumb LoadBreadcrumb(const std::string & /*fqrn*/) {
220 470 return manifest::Breadcrumb();
221 }
222 virtual bool StoreBreadcrumb(const manifest::Manifest & /*manifest*/) {
223 return false;
224 }
225
226 protected:
227 CacheManager();
228
229 // Unless overwritten, Saving/Restoring states will crash the Fuse module
230 virtual void *DoSaveState() { return NULL; }
231 virtual int DoRestoreState(void *data) { return false; }
232 virtual bool DoFreeState(void *data) { return false; }
233
234 /**
235 * Never NULL but defaults to NoopQuotaManager.
236 */
237 QuotaManager *quota_mgr_;
238
239 private:
240 static const unsigned kStateVersion = 0;
241
242 /**
243 * Wraps around the concrete cache manager's state block in memory. The
244 * state pointer is used in DoSaveState, DoRestoreState, DoFreeState.
245 */
246 struct State : SingleCopy {
247 126 State()
248 252 : version(kStateVersion)
249 126 , manager_type(kUnknownCacheManager)
250 126 , concrete_state(NULL) { }
251
252 unsigned version;
253 CacheManagerIds manager_type;
254 void *concrete_state;
255 };
256 }; // class CacheManager
257
258 #endif // CVMFS_CACHE_H_
259
260