GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/cache_plugin/libcvmfs_cache.cc
Date: 2026-05-19 11:45:12
Exec Total Coverage
Lines: 0 195 0.0%
Branches: 0 152 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #define _FILE_OFFSET_BITS 64
6
7
8 #include "libcvmfs_cache.h"
9
10 #include <unistd.h>
11
12 #include <cassert>
13 #include <cstdlib>
14 #include <cstring>
15 #include <string>
16
17 #include "cache_plugin/channel.h"
18 #include "cache_transport.h"
19 #include "crypto/hash.h"
20 #include "manifest.h"
21 #include "monitor.h"
22 #include "util/pointer.h"
23
24 using namespace std; // NOLINT
25
26 namespace {
27
28 static shash::Any Chash2Cpphash(const struct cvmcache_hash *h) {
29 shash::Any hash;
30 memcpy(hash.digest, h->digest, sizeof(h->digest));
31 hash.algorithm = static_cast<shash::Algorithms>(h->algorithm);
32 return hash;
33 }
34
35 static struct cvmcache_hash Cpphash2Chash(const shash::Any &hash) {
36 struct cvmcache_hash h;
37 memcpy(h.digest, hash.digest, sizeof(h.digest));
38 h.algorithm = hash.algorithm;
39 return h;
40 }
41
42 static enum cvmcache_object_type ObjectType2CType(cvmfs::EnumObjectType type) {
43 switch (type) {
44 case cvmfs::OBJECT_REGULAR:
45 return CVMCACHE_OBJECT_REGULAR;
46 case cvmfs::OBJECT_CATALOG:
47 return CVMCACHE_OBJECT_CATALOG;
48 case cvmfs::OBJECT_VOLATILE:
49 return CVMCACHE_OBJECT_VOLATILE;
50 }
51 abort();
52 }
53
54 class ForwardCachePlugin : public CachePlugin {
55 public:
56 explicit ForwardCachePlugin(struct cvmcache_callbacks *callbacks)
57 : CachePlugin(callbacks->capabilities), callbacks_(*callbacks) {
58 assert(callbacks->cvmcache_chrefcnt != NULL);
59 assert(callbacks->cvmcache_obj_info != NULL);
60 assert(callbacks->cvmcache_pread != NULL);
61 if (callbacks->capabilities & CVMCACHE_CAP_WRITE) {
62 assert(callbacks->cvmcache_start_txn != NULL);
63 assert(callbacks->cvmcache_write_txn != NULL);
64 assert(callbacks->cvmcache_commit_txn != NULL);
65 assert(callbacks->cvmcache_abort_txn != NULL);
66 }
67 if (callbacks->capabilities & CVMCACHE_CAP_INFO)
68 assert(callbacks->cvmcache_info != NULL);
69 if (callbacks->capabilities & CVMCACHE_CAP_SHRINK_RATE)
70 assert(callbacks->capabilities & CVMCACHE_CAP_INFO);
71 if (callbacks->capabilities & CVMCACHE_CAP_SHRINK)
72 assert(callbacks->cvmcache_shrink != NULL);
73 if (callbacks->capabilities & CVMCACHE_CAP_LIST) {
74 assert(callbacks->cvmcache_listing_begin != NULL);
75 assert(callbacks->cvmcache_listing_next != NULL);
76 assert(callbacks->cvmcache_listing_end != NULL);
77 }
78 if (callbacks->capabilities & CVMCACHE_CAP_BREADCRUMB) {
79 assert(callbacks->cvmcache_breadcrumb_store != NULL);
80 assert(callbacks->cvmcache_breadcrumb_load != NULL);
81 }
82 }
83 virtual ~ForwardCachePlugin() { }
84
85 protected:
86 virtual cvmfs::EnumStatus ChangeRefcount(const shash::Any &id,
87 int32_t change_by) {
88 struct cvmcache_hash c_hash = Cpphash2Chash(id);
89 const int result = callbacks_.cvmcache_chrefcnt(&c_hash, change_by);
90 return static_cast<cvmfs::EnumStatus>(result);
91 }
92
93 virtual cvmfs::EnumStatus GetObjectInfo(const shash::Any &id,
94 ObjectInfo *info) {
95 struct cvmcache_hash c_hash = Cpphash2Chash(id);
96 cvmcache_object_info c_info;
97 memset(&c_info, 0, sizeof(c_info));
98 c_info.size = CachePlugin::kSizeUnknown;
99 const int result = callbacks_.cvmcache_obj_info(&c_hash, &c_info);
100 info->size = c_info.size;
101 info->object_type = static_cast<cvmfs::EnumObjectType>(c_info.type);
102 info->pinned = c_info.pinned;
103 if (c_info.description) {
104 info->description = string(c_info.description);
105 free(c_info.description);
106 }
107 return static_cast<cvmfs::EnumStatus>(result);
108 }
109
110 virtual cvmfs::EnumStatus Pread(const shash::Any &id,
111 uint64_t offset,
112 uint32_t *size,
113 unsigned char *buffer) {
114 struct cvmcache_hash c_hash = Cpphash2Chash(id);
115 const int result = callbacks_.cvmcache_pread(&c_hash, offset, size, buffer);
116 return static_cast<cvmfs::EnumStatus>(result);
117 }
118
119 virtual cvmfs::EnumStatus StartTxn(const shash::Any &id,
120 const uint64_t txn_id,
121 const ObjectInfo &info) {
122 if (!(callbacks_.capabilities & CVMCACHE_CAP_WRITE))
123 return cvmfs::STATUS_NOSUPPORT;
124
125 struct cvmcache_hash c_hash = Cpphash2Chash(id);
126 cvmcache_object_info c_info;
127 memset(&c_info, 0, sizeof(c_info));
128 c_info.size = info.size;
129 c_info.type = ObjectType2CType(info.object_type);
130 if (info.description.empty()) {
131 c_info.description = NULL;
132 } else {
133 c_info.description = strdup(info.description.c_str());
134 }
135 const int result = callbacks_.cvmcache_start_txn(&c_hash, txn_id, &c_info);
136 free(c_info.description);
137 return static_cast<cvmfs::EnumStatus>(result);
138 }
139
140 virtual cvmfs::EnumStatus WriteTxn(const uint64_t txn_id,
141 unsigned char *buffer,
142 uint32_t size) {
143 if (!(callbacks_.capabilities & CVMCACHE_CAP_WRITE))
144 return cvmfs::STATUS_NOSUPPORT;
145
146 const int result = callbacks_.cvmcache_write_txn(txn_id, buffer, size);
147 return static_cast<cvmfs::EnumStatus>(result);
148 }
149
150 virtual cvmfs::EnumStatus CommitTxn(const uint64_t txn_id) {
151 if (!(callbacks_.capabilities & CVMCACHE_CAP_WRITE))
152 return cvmfs::STATUS_NOSUPPORT;
153
154 const int result = callbacks_.cvmcache_commit_txn(txn_id);
155 return static_cast<cvmfs::EnumStatus>(result);
156 }
157
158 virtual cvmfs::EnumStatus AbortTxn(const uint64_t txn_id) {
159 if (!(callbacks_.capabilities & CVMCACHE_CAP_WRITE))
160 return cvmfs::STATUS_NOSUPPORT;
161
162 const int result = callbacks_.cvmcache_abort_txn(txn_id);
163 return static_cast<cvmfs::EnumStatus>(result);
164 }
165
166 virtual cvmfs::EnumStatus GetInfo(Info *info) {
167 if (!(callbacks_.capabilities & CVMCACHE_CAP_INFO))
168 return cvmfs::STATUS_NOSUPPORT;
169
170 cvmcache_info c_info;
171 c_info.size_bytes = info->size_bytes;
172 c_info.used_bytes = info->used_bytes;
173 c_info.pinned_bytes = info->pinned_bytes;
174 c_info.no_shrink = info->no_shrink;
175 const int result = callbacks_.cvmcache_info(&c_info);
176 if (result == CVMCACHE_STATUS_OK) {
177 info->size_bytes = c_info.size_bytes;
178 info->used_bytes = c_info.used_bytes;
179 info->pinned_bytes = c_info.pinned_bytes;
180 info->no_shrink = c_info.no_shrink;
181 }
182 return static_cast<cvmfs::EnumStatus>(result);
183 }
184
185 virtual cvmfs::EnumStatus Shrink(uint64_t shrink_to, uint64_t *used) {
186 if (!(callbacks_.capabilities & CVMCACHE_CAP_SHRINK))
187 return cvmfs::STATUS_NOSUPPORT;
188
189 const int result = callbacks_.cvmcache_shrink(shrink_to, used);
190 return static_cast<cvmfs::EnumStatus>(result);
191 }
192
193 virtual cvmfs::EnumStatus ListingBegin(uint64_t lst_id,
194 cvmfs::EnumObjectType type) {
195 if (!(callbacks_.capabilities & CVMCACHE_CAP_LIST))
196 return cvmfs::STATUS_NOSUPPORT;
197
198 const int result = callbacks_.cvmcache_listing_begin(
199 lst_id, ObjectType2CType(type));
200 return static_cast<cvmfs::EnumStatus>(result);
201 }
202
203 virtual cvmfs::EnumStatus ListingNext(int64_t lst_id, ObjectInfo *item) {
204 if (!(callbacks_.capabilities & CVMCACHE_CAP_LIST))
205 return cvmfs::STATUS_NOSUPPORT;
206
207 struct cvmcache_object_info c_item;
208 memset(&c_item, 0, sizeof(c_item));
209 const int result = callbacks_.cvmcache_listing_next(lst_id, &c_item);
210 if (result == CVMCACHE_STATUS_OK) {
211 item->id = Chash2Cpphash(&c_item.id);
212 item->size = c_item.size;
213 item->object_type = static_cast<cvmfs::EnumObjectType>(c_item.type);
214 item->pinned = c_item.pinned;
215 if (c_item.description) {
216 item->description = string(c_item.description);
217 free(c_item.description);
218 }
219 }
220 return static_cast<cvmfs::EnumStatus>(result);
221 }
222
223 virtual cvmfs::EnumStatus ListingEnd(int64_t lst_id) {
224 if (!(callbacks_.capabilities & CVMCACHE_CAP_LIST))
225 return cvmfs::STATUS_NOSUPPORT;
226
227 const int result = callbacks_.cvmcache_listing_end(lst_id);
228 return static_cast<cvmfs::EnumStatus>(result);
229 }
230
231 virtual cvmfs::EnumStatus LoadBreadcrumb(const std::string &fqrn,
232 manifest::Breadcrumb *breadcrumb) {
233 if (!(callbacks_.capabilities & CVMCACHE_CAP_BREADCRUMB))
234 return cvmfs::STATUS_NOSUPPORT;
235
236 cvmcache_breadcrumb c_breadcrumb;
237 const int result = callbacks_.cvmcache_breadcrumb_load(fqrn.c_str(),
238 &c_breadcrumb);
239 if (result == CVMCACHE_STATUS_OK) {
240 breadcrumb->catalog_hash = Chash2Cpphash(&c_breadcrumb.catalog_hash);
241 breadcrumb->timestamp = c_breadcrumb.timestamp;
242 breadcrumb->revision = c_breadcrumb.revision;
243 }
244 return static_cast<cvmfs::EnumStatus>(result);
245 }
246
247 virtual cvmfs::EnumStatus StoreBreadcrumb(
248 const std::string &fqrn, const manifest::Breadcrumb &breadcrumb) {
249 if (!(callbacks_.capabilities & CVMCACHE_CAP_BREADCRUMB))
250 return cvmfs::STATUS_NOSUPPORT;
251
252 cvmcache_breadcrumb c_breadcrumb;
253 c_breadcrumb.catalog_hash = Cpphash2Chash(breadcrumb.catalog_hash);
254 c_breadcrumb.timestamp = breadcrumb.timestamp;
255 c_breadcrumb.revision = breadcrumb.revision;
256 const int result = callbacks_.cvmcache_breadcrumb_store(fqrn.c_str(),
257 &c_breadcrumb);
258 return static_cast<cvmfs::EnumStatus>(result);
259 }
260
261 private:
262 struct cvmcache_callbacks callbacks_;
263 };
264
265 Watchdog *g_watchdog = NULL;
266
267 } // anonymous namespace
268
269
270 struct cvmcache_context {
271 explicit cvmcache_context(ForwardCachePlugin *p) : plugin(p) { }
272 UniquePtr<ForwardCachePlugin> plugin;
273 };
274
275
276 int cvmcache_hash_cmp(struct cvmcache_hash *a, struct cvmcache_hash *b) {
277 const shash::Any hash_a = Chash2Cpphash(a);
278 const shash::Any hash_b = Chash2Cpphash(b);
279 if (hash_a < hash_b)
280 return -1;
281 else if (hash_a == hash_b)
282 return 0;
283 else
284 return 1;
285 }
286
287 char *cvmcache_hash_print(const struct cvmcache_hash *h) {
288 const shash::Any hash = Chash2Cpphash(h);
289 return strdup(hash.ToString().c_str());
290 }
291
292
293 void cvmcache_init_global() { }
294
295
296 void cvmcache_cleanup_global() { }
297
298 int cvmcache_is_supervised() {
299 return getenv(CacheTransport::kEnvReadyNotifyFd) != NULL;
300 }
301
302 struct cvmcache_context *cvmcache_init(struct cvmcache_callbacks *callbacks) {
303 return new cvmcache_context(new ForwardCachePlugin(callbacks));
304 }
305
306 int cvmcache_listen(struct cvmcache_context *ctx, char *locator) {
307 return ctx->plugin->Listen(locator);
308 }
309
310 void cvmcache_process_requests(struct cvmcache_context *ctx,
311 unsigned nworkers) {
312 ctx->plugin->ProcessRequests(nworkers);
313 }
314
315 void cvmcache_ask_detach(struct cvmcache_context *ctx) {
316 ctx->plugin->AskToDetach();
317 }
318
319 void cvmcache_wait_for(struct cvmcache_context *ctx) {
320 ctx->plugin->WaitFor();
321 delete ctx;
322 }
323
324 void cvmcache_terminate(struct cvmcache_context *ctx) {
325 ctx->plugin->Terminate();
326 }
327
328 uint32_t cvmcache_max_object_size(struct cvmcache_context *ctx) {
329 return ctx->plugin->max_object_size();
330 }
331
332 void cvmcache_get_session(cvmcache_session *session) {
333 assert(session != NULL);
334 SessionCtx *session_ctx = SessionCtx::GetInstance();
335 assert(session_ctx);
336 session_ctx->Get(
337 &(session->id), &(session->repository_name), &(session->client_instance));
338 }
339
340 void cvmcache_spawn_watchdog(const char *crash_dump_file) {
341 if (g_watchdog != NULL)
342 return;
343 g_watchdog = Watchdog::Create(NULL, false /* needs_read_environ */);
344 assert(g_watchdog != NULL);
345 g_watchdog->Spawn((crash_dump_file != NULL) ? string(crash_dump_file) : "");
346 }
347
348 void cvmcache_terminate_watchdog() {
349 delete g_watchdog;
350 g_watchdog = NULL;
351 }
352