GCC Code Coverage Report


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