GCC Code Coverage Report


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