Directory: | cvmfs/ |
---|---|
File: | cvmfs/cache.h |
Date: | 2025-03-09 02:34:28 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 31 | 40 | 77.5% |
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 | 4843 | Label() : flags(0) | |
97 | 4843 | , size(kSizeUnknown) | |
98 | 4843 | , zip_algorithm(zlib::kZlibDefault) | |
99 | 4843 | , range_offset(-1) | |
100 | 4843 | {} | |
101 | |||
102 | 259 | bool IsCatalog() const { return flags & kLabelCatalog; } | |
103 | 134 | bool IsPinned() const { return flags & kLabelPinned; } | |
104 | 48 | bool IsExternal() const { return flags & kLabelExternal; } | |
105 | 2 | bool IsCertificate() const { return flags & kLabelCertificate; } | |
106 | |||
107 | /** | ||
108 | * The description for the quota manager | ||
109 | */ | ||
110 | 3175 | std::string GetDescription() const { | |
111 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 3129 times.
|
3175 | if (flags & kLabelCatalog) |
112 | 46 | return "file catalog at " + path; | |
113 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3120 times.
|
3129 | if (flags & kLabelCertificate) |
114 | 9 | return "certificate for " + path; | |
115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3120 times.
|
3120 | if (flags & kLabelMetainfo) |
116 | ✗ | return "metainfo for " + path; | |
117 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3119 times.
|
3120 | if (flags & kLabelHistory) |
118 | 1 | return "tag database for " + path; | |
119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3119 times.
|
3119 | if (flags & kLabelChunked) |
120 | ✗ | return "Part of " + path; | |
121 | 3119 | 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 | 494 | explicit LabeledObject(const shash::Any &id) : id(id), label() { } | |
141 | 2152 | LabeledObject(const shash::Any &id, const Label &l) | |
142 | 2152 | : id(id) | |
143 | 2152 | , label(l) { } | |
144 | |||
145 | shash::Any id; | ||
146 | Label label; | ||
147 | }; | ||
148 | |||
149 | virtual CacheManagerIds id() = 0; | ||
150 | /** | ||
151 | * Return a human readable description of the cache instance. Used in | ||
152 | * cvmfs_talk. | ||
153 | */ | ||
154 | virtual std::string Describe() = 0; | ||
155 | |||
156 | virtual bool AcquireQuotaManager(QuotaManager *quota_mgr) = 0; | ||
157 | |||
158 | virtual ~CacheManager(); | ||
159 | /** | ||
160 | * Opening an object might get it from a third-party source, e.g. when the | ||
161 | * tiered cache manager issues a copy-up operation. In this case it is | ||
162 | * beneficial to register the object with the accurate meta-data, in the same | ||
163 | * way it is done during transactions. | ||
164 | */ | ||
165 | virtual int Open(const LabeledObject &object) = 0; | ||
166 | virtual int64_t GetSize(int fd) = 0; | ||
167 | virtual int Close(int fd) = 0; | ||
168 | virtual int64_t Pread(int fd, void *buf, uint64_t size, uint64_t offset) = 0; | ||
169 | virtual int Dup(int fd) = 0; | ||
170 | virtual int Readahead(int fd) = 0; | ||
171 | |||
172 | virtual uint32_t SizeOfTxn() = 0; | ||
173 | virtual int StartTxn(const shash::Any &id, uint64_t size, void *txn) = 0; | ||
174 | virtual void CtrlTxn(const Label &label, | ||
175 | const int flags, // reserved for future use | ||
176 | void *txn) = 0; | ||
177 | virtual int64_t Write(const void *buf, uint64_t sz, void *txn) = 0; | ||
178 | virtual int Reset(void *txn) = 0; | ||
179 | virtual int AbortTxn(void *txn) = 0; | ||
180 | virtual int OpenFromTxn(void *txn) = 0; | ||
181 | virtual int CommitTxn(void *txn) = 0; | ||
182 | |||
183 | virtual void Spawn() = 0; | ||
184 | |||
185 | int ChecksumFd(int fd, shash::Any *id); | ||
186 | int OpenPinned(const LabeledObject &object); | ||
187 | bool Open2Mem(const LabeledObject &object, | ||
188 | unsigned char **buffer, uint64_t *size); | ||
189 | bool CommitFromMem(const LabeledObject &object, | ||
190 | const unsigned char *buffer, | ||
191 | const uint64_t size); | ||
192 | |||
193 | 44 | QuotaManager *quota_mgr() { return quota_mgr_; } | |
194 | |||
195 | // Rescue the open file table during reload of the fuse module. For the | ||
196 | // POSIX cache, nothing needs to be done because the table is keep in the | ||
197 | // kernel for the process. Other cache managers need to do it manually. | ||
198 | void *SaveState(const int fd_progress); | ||
199 | /** | ||
200 | * When RestoreState is called, the cache has already exactly one file | ||
201 | * descriptor open: the root file catalog. This file descriptor might be | ||
202 | * remapped to another number. A return value of -1 means no action needs | ||
203 | * to take place. A smaller value indicates an error. | ||
204 | */ | ||
205 | int RestoreState(const int fd_progress, void *state); | ||
206 | void FreeState(const int fd_progress, void *state); | ||
207 | ✗ | CacheManagerIds PeekState(void *state) { | |
208 | ✗ | return static_cast<State *>(state)->manager_type; | |
209 | } | ||
210 | |||
211 | /** | ||
212 | * While not strictly necessary, cache managers often have a directory | ||
213 | * associated with them. This directory is currently used to find the | ||
214 | * cached manifest copy, the cvmfschecksum.$reponame file. This is important | ||
215 | * to make pre-loaded alien caches work, even in a tiered setup. | ||
216 | */ | ||
217 | 11 | virtual manifest::Breadcrumb LoadBreadcrumb(const std::string & /*fqrn*/) { | |
218 | 11 | return manifest::Breadcrumb(); | |
219 | } | ||
220 | ✗ | virtual bool StoreBreadcrumb(const manifest::Manifest &/*manifest*/) { | |
221 | ✗ | return false; | |
222 | } | ||
223 | |||
224 | protected: | ||
225 | CacheManager(); | ||
226 | |||
227 | // Unless overwritten, Saving/Restoring states will crash the Fuse module | ||
228 | ✗ | virtual void *DoSaveState() { return NULL; } | |
229 | ✗ | virtual int DoRestoreState(void *data) { return false; } | |
230 | ✗ | virtual bool DoFreeState(void *data) { return false; } | |
231 | |||
232 | /** | ||
233 | * Never NULL but defaults to NoopQuotaManager. | ||
234 | */ | ||
235 | QuotaManager *quota_mgr_; | ||
236 | |||
237 | private: | ||
238 | static const unsigned kStateVersion = 0; | ||
239 | |||
240 | /** | ||
241 | * Wraps around the concrete cache manager's state block in memory. The | ||
242 | * state pointer is used in DoSaveState, DoRestoreState, DoFreeState. | ||
243 | */ | ||
244 | struct State : SingleCopy { | ||
245 | 4 | State() | |
246 | 8 | : version(kStateVersion) | |
247 | 4 | , manager_type(kUnknownCacheManager) | |
248 | 4 | , concrete_state(NULL) | |
249 | 4 | { } | |
250 | |||
251 | unsigned version; | ||
252 | CacheManagerIds manager_type; | ||
253 | void *concrete_state; | ||
254 | }; | ||
255 | }; // class CacheManager | ||
256 | |||
257 | #endif // CVMFS_CACHE_H_ | ||
258 |