GCC Code Coverage Report


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