CernVM-FS  2.13.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cvmfs_cache_ram.cc
Go to the documentation of this file.
1 
7 #define __STDC_FORMAT_MACROS
8 
9 #include <alloca.h>
10 #include <fcntl.h>
11 #include <inttypes.h>
12 #include <signal.h>
13 #include <stdint.h>
14 #include <sys/types.h>
15 #include <sys/wait.h>
16 #include <unistd.h>
17 
18 #include <algorithm>
19 #include <cassert>
20 #include <cstdio>
21 #include <cstdlib>
22 #include <cstring>
23 #include <string>
24 #include <vector>
25 
27 #include "lru.h"
28 #include "malloc_heap.h"
29 #include "smallhash.h"
30 #include "util/concurrency.h"
31 #include "util/logging.h"
32 #include "util/murmur.hxx"
33 #include "util/platform.h"
34 #include "util/smalloc.h"
35 #include "util/string.h"
36 
37 using namespace std; // NOLINT
38 
43 struct ObjectHeader {
45  txn_id = uint64_t(-1);
46  size_data = 0;
47  size_desc = 0;
48  refcnt = 0;
50  memset(&id, 0, sizeof(id));
51  }
52 
53  char *GetDescription() {
54  if (size_desc == 0)
55  return NULL;
56  return reinterpret_cast<char *>(this) + sizeof(ObjectHeader);
57  }
58 
59  void SetDescription(char *description) {
60  if (description == NULL)
61  return;
62  memcpy(reinterpret_cast<char *>(this) + sizeof(ObjectHeader), description,
63  strlen(description) + 1);
64  }
65 
66  unsigned char *GetData() {
67  return reinterpret_cast<unsigned char *>(this) + sizeof(ObjectHeader)
68  + size_desc;
69  }
70 
76  uint64_t txn_id;
80  uint32_t size_data;
84  uint32_t size_desc;
89  union {
90  int32_t refcnt;
92  };
94  struct cvmcache_hash id;
95 };
96 
97 
102 struct Listing {
103  Listing() : pos(0) { }
104  uint64_t pos;
105  vector<struct cvmcache_object_info> elems;
106 };
107 
108 
112 struct ComparableHash {
113  ComparableHash() { memset(&hash, 0, sizeof(hash)); }
114  explicit ComparableHash(const struct cvmcache_hash &h) : hash(h) { }
115  bool operator==(const ComparableHash &other) const {
116  return cvmcache_hash_cmp(const_cast<cvmcache_hash *>(&(this->hash)),
117  const_cast<cvmcache_hash *>(&(other.hash)))
118  == 0;
119  }
120  bool operator!=(const ComparableHash &other) const {
121  return cvmcache_hash_cmp(const_cast<cvmcache_hash *>(&(this->hash)),
122  const_cast<cvmcache_hash *>(&(other.hash)))
123  != 0;
124  }
125  bool operator<(const ComparableHash &other) const {
126  return cvmcache_hash_cmp(const_cast<cvmcache_hash *>(&(this->hash)),
127  const_cast<cvmcache_hash *>(&(other.hash)))
128  < 0;
129  }
130  bool operator>(const ComparableHash &other) const {
131  return cvmcache_hash_cmp(const_cast<cvmcache_hash *>(&(this->hash)),
132  const_cast<cvmcache_hash *>(&(other.hash)))
133  > 0;
134  }
135 
136  struct cvmcache_hash hash;
137 };
138 
139 
140 namespace {
141 
142 static inline uint32_t hasher_uint64(const uint64_t &key) {
143  return MurmurHash2(&key, sizeof(key), 0x07387a4f);
144 }
145 
146 static inline uint32_t hasher_any(const ComparableHash &key) {
147  return (uint32_t) * (reinterpret_cast<const uint32_t *>(&key.hash));
148 }
149 
150 } // anonymous namespace
151 
152 
157 
158 
162 class PluginRamCache : public Callbackable<MallocHeap::BlockPtr> {
163  public:
164  static PluginRamCache *Create(const string &mem_size_str) {
165  assert(instance_ == NULL);
166 
167  uint64_t mem_size_bytes;
168  if (HasSuffix(mem_size_str, "%", false)) {
169  mem_size_bytes = platform_memsize() * String2Uint64(mem_size_str) / 100;
170  } else {
171  mem_size_bytes = String2Uint64(mem_size_str) * 1024 * 1024;
172  }
173  instance_ = new PluginRamCache(mem_size_bytes);
174  return instance_;
175  }
176 
178  assert(instance_ != NULL);
179  return instance_;
180  }
181 
183  delete storage_;
184  delete objects_all_;
185  delete objects_volatile_;
186  instance_ = NULL;
187  }
188 
189  void DropBreadcrumbs() { breadcrumbs_.clear(); }
190 
191  static int ram_chrefcnt(struct cvmcache_hash *id, int32_t change_by) {
192  ComparableHash h(*id);
193  ObjectHeader *object;
194  if (!Me()->objects_all_->Lookup(h, &object))
196 
197  if (object->type == CVMCACHE_OBJECT_VOLATILE)
198  Me()->objects_volatile_->Update(h);
199 
200  if (change_by == 0)
201  return CVMCACHE_STATUS_OK;
202  if ((object->refcnt + change_by) < 0)
204 
205  if (object->refcnt == 0) {
206  Me()->cache_info_.pinned_bytes += Me()->storage_->GetSize(object);
207  Me()->CheckHighPinWatermark();
208  }
209  object->refcnt += change_by;
210  if (object->refcnt == 0) {
211  Me()->cache_info_.pinned_bytes -= Me()->storage_->GetSize(object);
212  Me()->in_danger_zone_ = Me()->IsInDangerZone();
213  }
214  return CVMCACHE_STATUS_OK;
215  }
216 
217 
218  static int ram_obj_info(struct cvmcache_hash *id,
219  struct cvmcache_object_info *info) {
220  ComparableHash h(*id);
221  ObjectHeader *object;
222  if (!Me()->objects_all_->Lookup(h, &object, false))
224 
225  info->size = object->size_data;
226  info->type = object->type;
227  info->pinned = object->refcnt > 0;
228  info->description = (object->GetDescription() == NULL)
229  ? NULL
230  : strdup(object->GetDescription());
231  return CVMCACHE_STATUS_OK;
232  }
233 
234 
235  static int ram_pread(struct cvmcache_hash *id,
236  uint64_t offset,
237  uint32_t *size,
238  unsigned char *buffer) {
239  ComparableHash h(*id);
240  ObjectHeader *object;
241  bool retval = Me()->objects_all_->Lookup(h, &object, false);
242  assert(retval);
243  if (offset > object->size_data)
245  unsigned nbytes = std::min(
246  *size, static_cast<uint32_t>(object->size_data - offset));
247  memcpy(buffer, object->GetData() + offset, nbytes);
248  *size = nbytes;
249  return CVMCACHE_STATUS_OK;
250  }
251 
252 
253  static int ram_start_txn(struct cvmcache_hash *id,
254  uint64_t txn_id,
255  struct cvmcache_object_info *info) {
256  ObjectHeader object_header;
257  object_header.txn_id = txn_id;
258  if (info->size != CVMCACHE_SIZE_UNKNOWN)
259  object_header.size_data = info->size;
260  else
261  object_header.size_data = 4096;
262  if (info->description != NULL)
263  object_header.size_desc = strlen(info->description) + 1;
264  object_header.refcnt = 1;
265  object_header.type = info->type;
266  object_header.id = *id;
267 
268  uint32_t total_size = sizeof(object_header) + object_header.size_desc
269  + object_header.size_data;
270  Me()->TryFreeSpace(total_size);
271  ObjectHeader *allocd_object = reinterpret_cast<ObjectHeader *>(
272  Me()->storage_->Allocate(total_size, &object_header,
273  sizeof(object_header)));
274  if (allocd_object == NULL)
276 
277  allocd_object->SetDescription(info->description);
278  Me()->transactions_.Insert(txn_id, allocd_object);
279  return CVMCACHE_STATUS_OK;
280  }
281 
282 
283  static int ram_write_txn(uint64_t txn_id,
284  unsigned char *buffer,
285  uint32_t size) {
286  ObjectHeader *txn_object;
287  int retval = Me()->transactions_.Lookup(txn_id, &txn_object);
288  assert(retval);
289  assert(size > 0);
290 
291  if (txn_object->neg_nbytes_written > 0)
292  txn_object->neg_nbytes_written = 0;
293  if ((size - txn_object->neg_nbytes_written) > txn_object->size_data) {
294  uint32_t current_size = Me()->storage_->GetSize(txn_object);
295  uint32_t header_size = current_size - txn_object->size_data;
296  uint32_t new_size = std::max(
297  header_size + size - txn_object->neg_nbytes_written,
298  uint32_t(current_size * kObjectExpandFactor));
299  bool did_compact = Me()->TryFreeSpace(new_size);
300  if (did_compact) {
301  retval = Me()->transactions_.Lookup(txn_id, &txn_object);
302  assert(retval);
303  }
304  txn_object = reinterpret_cast<ObjectHeader *>(
305  Me()->storage_->Expand(txn_object, new_size));
306  if (txn_object == NULL)
308  txn_object->size_data = new_size - header_size;
309  Me()->transactions_.Insert(txn_id, txn_object);
310  }
311 
312  memcpy(txn_object->GetData() - txn_object->neg_nbytes_written, buffer,
313  size);
314  txn_object->neg_nbytes_written -= size;
315  return CVMCACHE_STATUS_OK;
316  }
317 
318 
319  static int ram_commit_txn(uint64_t txn_id) {
320  Me()->TryFreeSpace(0);
321  if (Me()->objects_all_->IsFull())
323 
324  ObjectHeader *txn_object;
325  int retval = Me()->transactions_.Lookup(txn_id, &txn_object);
326  assert(retval);
327 
328  Me()->transactions_.Erase(txn_id);
329  ComparableHash h(txn_object->id);
330  ObjectHeader *existing_object;
331  if (Me()->objects_all_->Lookup(h, &existing_object)) {
332  // Concurrent addition of same objects, drop the one at hand and
333  // increase ref count of existing copy
334  Me()->storage_->MarkFree(txn_object);
335  if (existing_object->refcnt == 0)
336  Me()->cache_info_.pinned_bytes += Me()->storage_->GetSize(
337  existing_object);
338  existing_object->refcnt++;
339  } else {
340  txn_object->txn_id = uint64_t(-1);
341  if (txn_object->neg_nbytes_written > 0)
342  txn_object->neg_nbytes_written = 0;
343  txn_object->size_data = -(txn_object->neg_nbytes_written);
344  txn_object->refcnt = 1;
345  Me()->cache_info_.used_bytes += Me()->storage_->GetSize(txn_object);
346  Me()->cache_info_.pinned_bytes += Me()->storage_->GetSize(txn_object);
347  Me()->objects_all_->Insert(h, txn_object);
348  if (txn_object->type == CVMCACHE_OBJECT_VOLATILE) {
349  assert(!Me()->objects_volatile_->IsFull());
350  Me()->objects_volatile_->Insert(h, txn_object);
351  }
352  }
353  Me()->CheckHighPinWatermark();
354  return CVMCACHE_STATUS_OK;
355  }
356 
357 
358  static int ram_abort_txn(uint64_t txn_id) {
359  ObjectHeader *txn_object = NULL;
360  int retval = Me()->transactions_.Lookup(txn_id, &txn_object);
361  assert(retval);
362  Me()->transactions_.Erase(txn_id);
363  Me()->storage_->MarkFree(txn_object);
364  return CVMCACHE_STATUS_OK;
365  }
366 
367 
368  static int ram_info(struct cvmcache_info *info) {
369  *info = Me()->cache_info_;
370  return CVMCACHE_STATUS_OK;
371  }
372 
373 
374  static int ram_shrink(uint64_t shrink_to, uint64_t *used) {
375  *used = Me()->cache_info_.used_bytes;
376  if (*used <= shrink_to)
377  return CVMCACHE_STATUS_OK;
378 
379  Me()->DoShrink(shrink_to);
380  *used = Me()->cache_info_.used_bytes;
381  return (*used <= shrink_to) ? CVMCACHE_STATUS_OK : CVMCACHE_STATUS_PARTIAL;
382  }
383 
384 
385  static int ram_listing_begin(uint64_t lst_id,
386  enum cvmcache_object_type type) {
387  Listing *lst = new Listing();
388  Me()->objects_all_->FilterBegin();
389  while (Me()->objects_all_->FilterNext()) {
390  ComparableHash h;
391  ObjectHeader *object;
392  Me()->objects_all_->FilterGet(&h, &object);
393  if (object->type != type)
394  continue;
395 
396  struct cvmcache_object_info item;
397  item.id = object->id;
398  item.size = object->size_data;
399  item.type = type;
400  item.pinned = object->refcnt != 0;
401  item.description = (object->size_desc > 0)
402  ? strdup(object->GetDescription())
403  : NULL;
404  lst->elems.push_back(item);
405  }
406  Me()->objects_all_->FilterEnd();
407 
408  Me()->listings_.Insert(lst_id, lst);
409  return CVMCACHE_STATUS_OK;
410  }
411 
412 
413  static int ram_listing_next(int64_t listing_id,
414  struct cvmcache_object_info *item) {
415  Listing *lst;
416  bool retval = Me()->listings_.Lookup(listing_id, &lst);
417  assert(retval);
418  if (lst->pos >= lst->elems.size())
420  *item = lst->elems[lst->pos];
421  lst->pos++;
422  return CVMCACHE_STATUS_OK;
423  }
424 
425 
426  static int ram_listing_end(int64_t listing_id) {
427  Listing *lst;
428  bool retval = Me()->listings_.Lookup(listing_id, &lst);
429  assert(retval);
430 
431  // Don't free description strings, done by the library
432  delete lst;
433  Me()->listings_.Erase(listing_id);
434  return CVMCACHE_STATUS_OK;
435  }
436 
437 
438  static int ram_breadcrumb_store(const char *fqrn,
439  const cvmcache_breadcrumb *breadcrumb) {
440  Me()->breadcrumbs_[fqrn] = *breadcrumb;
441  return CVMCACHE_STATUS_OK;
442  }
443 
444 
445  static int ram_breadcrumb_load(const char *fqrn,
446  cvmcache_breadcrumb *breadcrumb) {
447  map<std::string, cvmcache_breadcrumb>::const_iterator
448  itr = Me()->breadcrumbs_.find(fqrn);
449  if (itr == Me()->breadcrumbs_.end())
451  *breadcrumb = itr->second;
452  return CVMCACHE_STATUS_OK;
453  }
454 
455  private:
456  static const uint64_t kMinSize; // 100 * 1024 * 1024;
457  static const double kShrinkFactor; // = 0.75;
458  static const double kObjectExpandFactor; // = 1.5;
459  static const double kSlotFraction; // = 0.04;
460  static const double kDangerZoneThreshold; // = 0.7
461 
463  static PluginRamCache *Me() { return instance_; }
464  explicit PluginRamCache(uint64_t mem_size) {
465  in_danger_zone_ = false;
466 
467  uint64_t heap_size = RoundUp8(
468  std::max(kMinSize, uint64_t(mem_size * (1.0 - kSlotFraction))));
469  memset(&cache_info_, 0, sizeof(cache_info_));
470  cache_info_.size_bytes = heap_size;
471  storage_ = new MallocHeap(
472  heap_size, this->MakeCallback(&PluginRamCache::OnBlockMove, this));
473 
474  struct cvmcache_hash hash_empty;
475  memset(&hash_empty, 0, sizeof(hash_empty));
476 
477  transactions_.Init(64, uint64_t(-1), hasher_uint64);
478  listings_.Init(8, uint64_t(-1), hasher_uint64);
479 
480  double slot_size = lru::LruCache<ComparableHash,
481  ObjectHeader *>::GetEntrySize();
482  uint64_t num_slots = uint64_t((heap_size * kSlotFraction)
483  / (2.0 * slot_size));
484  const unsigned mask_64 = ~((1 << 6) - 1);
485 
487  "Allocating %" PRIu64 "MB of memory for up to %" PRIu64 " objects",
488  heap_size / (1024 * 1024), num_slots & mask_64);
489 
490  // Number of cache entries must be a multiple of 64
492  num_slots & mask_64,
493  ComparableHash(hash_empty),
494  hasher_any,
495  perf::StatisticsTemplate("objects_all", &statistics_));
496  objects_volatile_ = new lru::LruCache<ComparableHash, ObjectHeader *>(
497  num_slots & mask_64,
498  ComparableHash(hash_empty),
499  hasher_any,
500  perf::StatisticsTemplate("objects_volatile", &statistics_));
501  }
502 
507  bool TryFreeSpace(uint64_t bytes_required) {
508  if (!objects_all_->IsFull() && storage_->HasSpaceFor(bytes_required))
509  return false;
510 
511  // Free space occupied due to piecewise catalog storage
512  if (!objects_all_->IsFull()) {
513  LogCvmfs(kLogCache, kLogDebug, "compacting ram cache");
514  storage_->Compact();
515  if (storage_->HasSpaceFor(bytes_required))
516  return true;
517  }
518 
519  uint64_t shrink_to = std::min(
520  storage_->capacity() - (bytes_required + 8),
521  uint64_t(storage_->capacity() * kShrinkFactor));
522  DoShrink(shrink_to);
523  return true;
524  }
525 
527  assert(ptr.pointer);
528  ObjectHeader *object = reinterpret_cast<ObjectHeader *>(ptr.pointer);
529  ComparableHash h(object->id);
530  if (object->txn_id == uint64_t(-1)) {
531  bool retval = objects_all_->UpdateValue(h, object);
532  assert(retval);
533  if (object->type == CVMCACHE_OBJECT_VOLATILE) {
534  retval = objects_volatile_->UpdateValue(h, object);
535  assert(retval);
536  }
537  } else {
538  uint64_t old_size = transactions_.size();
539  transactions_.Insert(object->txn_id, object);
540  assert(old_size == transactions_.size());
541  }
542  }
543 
544 
545  void DoShrink(uint64_t shrink_to) {
546  ComparableHash h;
547  ObjectHeader *object;
548 
550  "clean up cache until at most %lu KB is used", shrink_to / 1024);
551 
552  objects_volatile_->FilterBegin();
553  while (objects_volatile_->FilterNext()) {
554  objects_volatile_->FilterGet(&h, &object);
555  if (object->refcnt != 0)
556  continue;
557  cache_info_.used_bytes -= storage_->GetSize(object);
558  storage_->MarkFree(object);
559  objects_volatile_->FilterDelete();
560  objects_all_->Forget(h);
561  if (storage_->compacted_bytes() <= shrink_to)
562  break;
563  }
564  objects_volatile_->FilterEnd();
565 
566  objects_all_->FilterBegin();
567  while ((storage_->compacted_bytes() > shrink_to)
568  && objects_all_->FilterNext()) {
569  objects_all_->FilterGet(&h, &object);
570  if (object->refcnt != 0)
571  continue;
573  cache_info_.used_bytes -= storage_->GetSize(object);
574  storage_->MarkFree(object);
575  objects_all_->FilterDelete();
576  }
577  objects_all_->FilterEnd();
578 
579  storage_->Compact();
580  cache_info_.no_shrink++;
581  }
582 
584  if (!Me()->in_danger_zone_ && Me()->IsInDangerZone()) {
586  "high watermark of pinned files");
587  Me()->in_danger_zone_ = true;
589  }
590  }
591 
592  bool IsInDangerZone() {
593  return (static_cast<double>(cache_info_.pinned_bytes)
594  / static_cast<double>(cache_info_.size_bytes))
595  > kDangerZoneThreshold;
596  }
597 
598 
599  struct cvmcache_info cache_info_;
605  map<std::string, cvmcache_breadcrumb> breadcrumbs_;
608 }; // class PluginRamCache
609 
611 const uint64_t PluginRamCache::kMinSize = 100 * 1024 * 1024;
612 const double PluginRamCache::kShrinkFactor = 0.75;
613 const double PluginRamCache::kObjectExpandFactor = 1.5;
614 const double PluginRamCache::kSlotFraction = 0.04;
615 const double PluginRamCache::kDangerZoneThreshold = 0.7;
616 
617 
618 static void Usage(const char *progname) {
619  LogCvmfs(kLogCache, kLogStdout, "%s <config file>", progname);
620 }
621 
622 
627 void DropBreadcrumbs(int sig, siginfo_t *siginfo, void *context) {
628  LogCvmfs(kLogCache, kLogSyslog | kLogDebug, "dropping breadcrumbs");
630 }
631 
632 
633 int main(int argc, char **argv) {
634  if (argc < 2) {
635  Usage(argv[0]);
636  return 1;
637  }
638 
639  SetLogDebugFile("/dev/null");
640 
642 
644  if (cvmcache_options_parse(options, argv[1]) != 0) {
645  LogCvmfs(kLogCache, kLogStderr, "cannot parse options file %s", argv[1]);
646  return 1;
647  }
648  char *debug_log = cvmcache_options_get(options,
649  "CVMFS_CACHE_PLUGIN_DEBUGLOG");
650  if (debug_log != NULL) {
651  SetLogDebugFile(debug_log);
652  cvmcache_options_free(debug_log);
653  }
654  char *locator = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_LOCATOR");
655  if (locator == NULL) {
656  LogCvmfs(kLogCache, kLogStderr, "CVMFS_CACHE_PLUGIN_LOCATOR missing");
657  cvmcache_options_fini(options);
658  return 1;
659  }
660  char *mem_size = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_SIZE");
661  if (mem_size == NULL) {
662  LogCvmfs(kLogCache, kLogStderr, "CVMFS_CACHE_PLUGIN_SIZE missing");
663  cvmcache_options_fini(options);
664  return 1;
665  }
666  char *test_mode = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_TEST");
667 
668  if (!test_mode)
670 
671  PluginRamCache *plugin = PluginRamCache::Create(mem_size);
672  struct sigaction sa;
673  memset(&sa, 0, sizeof(sa));
674  sa.sa_sigaction = DropBreadcrumbs;
675  sa.sa_flags = SA_SIGINFO;
676  sigfillset(&sa.sa_mask);
677  int retval = sigaction(SIGUSR2, &sa, NULL);
678  assert(retval == 0);
679 
680  struct cvmcache_callbacks callbacks;
681  memset(&callbacks, 0, sizeof(callbacks));
682  callbacks.cvmcache_chrefcnt = plugin->ram_chrefcnt;
683  callbacks.cvmcache_obj_info = plugin->ram_obj_info;
684  callbacks.cvmcache_pread = plugin->ram_pread;
685  callbacks.cvmcache_start_txn = plugin->ram_start_txn;
686  callbacks.cvmcache_write_txn = plugin->ram_write_txn;
687  callbacks.cvmcache_commit_txn = plugin->ram_commit_txn;
688  callbacks.cvmcache_abort_txn = plugin->ram_abort_txn;
689  callbacks.cvmcache_info = plugin->ram_info;
690  callbacks.cvmcache_shrink = plugin->ram_shrink;
691  callbacks.cvmcache_listing_begin = plugin->ram_listing_begin;
692  callbacks.cvmcache_listing_next = plugin->ram_listing_next;
693  callbacks.cvmcache_listing_end = plugin->ram_listing_end;
695  callbacks.cvmcache_breadcrumb_load = plugin->ram_breadcrumb_load;
696  callbacks.capabilities = CVMCACHE_CAP_ALL_V2;
697 
698  ctx = cvmcache_init(&callbacks);
699  retval = cvmcache_listen(ctx, locator);
700  if (!retval) {
701  LogCvmfs(kLogCache, kLogStderr, "failed to listen on %s", locator);
702  return 1;
703  }
704 
705  if (test_mode) {
706  // Daemonize, print out PID
707  pid_t pid;
708  int statloc;
709  if ((pid = fork()) == 0) {
710  if ((pid = fork()) == 0) {
711  int null_read = open("/dev/null", O_RDONLY);
712  int null_write = open("/dev/null", O_WRONLY);
713  assert((null_read >= 0) && (null_write >= 0));
714  int retval = dup2(null_read, 0);
715  assert(retval == 0);
716  retval = dup2(null_write, 1);
717  assert(retval == 1);
718  retval = dup2(null_write, 2);
719  assert(retval == 2);
720  close(null_read);
721  close(null_write);
722  } else {
723  assert(pid > 0);
724  printf("%d\n", pid);
725  fflush(stdout);
726  fsync(1);
727  _exit(0);
728  }
729  } else {
730  assert(pid > 0);
731  waitpid(pid, &statloc, 0);
732  _exit(0);
733  }
734  }
735 
737  "Listening for cvmfs clients on %s\n"
738  "NOTE: this process needs to run as user cvmfs\n",
739  locator);
740 
742  if (test_mode)
743  while (true)
744  sleep(1);
745  if (!cvmcache_is_supervised()) {
746  LogCvmfs(kLogCache, kLogStdout, "Press <Ctrl+D> to quit");
748  "Press <R Enter> to ask clients to release nested catalogs");
749  while (true) {
750  char buf;
751  retval = read(fileno(stdin), &buf, 1);
752  if (retval != 1)
753  break;
754  if (buf == 'R') {
756  " ... asking clients to release nested catalogs");
758  }
759  }
761  } else {
763  "CernVM-FS RAM cache plugin started in supervised mode");
764  }
765 
767  LogCvmfs(kLogCache, kLogDebug | kLogStdout, " ... good bye");
768  cvmcache_options_free(mem_size);
769  cvmcache_options_free(locator);
770  cvmcache_options_fini(options);
773  return 0;
774 }
static int ram_commit_txn(uint64_t txn_id)
static int ram_pread(struct cvmcache_hash *id, uint64_t offset, uint32_t *size, unsigned char *buffer)
int(* cvmcache_chrefcnt)(struct cvmcache_hash *id, int32_t change_by)
static int ram_listing_next(int64_t listing_id, struct cvmcache_object_info *item)
static int ram_write_txn(uint64_t txn_id, unsigned char *buffer, uint32_t size)
struct cvmcache_context * ctx
unsigned char * GetData()
struct cvmcache_hash hash
cvmcache_object_type
static int ram_chrefcnt(struct cvmcache_hash *id, int32_t change_by)
int(* cvmcache_info)(struct cvmcache_info *info)
SmallHashDynamic< uint64_t, ObjectHeader * > transactions_
static void Usage(const char *progname)
void cvmcache_terminate(struct cvmcache_context *ctx)
perf::Statistics statistics_
int cvmcache_listen(struct cvmcache_context *ctx, char *locator)
struct cvmcache_hash id
int(* cvmcache_listing_next)(int64_t lst_id, struct cvmcache_object_info *item)
void cvmcache_cleanup_global()
uint32_t size_data
MallocHeap * storage_
static const double kObjectExpandFactor
static int ram_listing_begin(uint64_t lst_id, enum cvmcache_object_type type)
void cvmcache_terminate_watchdog()
perf::Statistics * statistics_
Definition: repository.h:138
static PluginRamCache * Create(const string &mem_size_str)
assert((mem||(size==0))&&"Out Of Memory")
void OnBlockMove(const MallocHeap::BlockPtr &ptr)
bool operator!=(const ComparableHash &other) const
int cvmcache_is_supervised()
static uint32_t hasher_any(const ComparableHash &key)
int(* cvmcache_pread)(struct cvmcache_hash *id, uint64_t offset, uint32_t *size, unsigned char *buffer)
static PluginRamCache * GetInstance()
int(* cvmcache_breadcrumb_load)(const char *fqrn, cvmcache_breadcrumb *breadcrumb)
#define SetLogDebugFile(filename)
static int ram_info(struct cvmcache_info *info)
void cvmcache_wait_for(struct cvmcache_context *ctx)
SmallHashDynamic< uint64_t, Listing * > listings_
void CheckHighPinWatermark()
int main()
Definition: helper_allow.cc:16
int32_t neg_nbytes_written
uint64_t platform_memsize()
static int ram_abort_txn(uint64_t txn_id)
void cvmcache_ask_detach(struct cvmcache_context *ctx)
vector< struct cvmcache_object_info > elems
struct cvmcache_hash id
int(* cvmcache_write_txn)(uint64_t txn_id, unsigned char *buffer, uint32_t size)
uint64_t pos
bool operator==(const ComparableHash &other) const
bool HasSuffix(const std::string &str, const std::string &suffix, const bool ignore_case)
Definition: string.cc:296
PluginRamCache(uint64_t mem_size)
static int ram_start_txn(struct cvmcache_hash *id, uint64_t txn_id, struct cvmcache_object_info *info)
int cvmcache_hash_cmp(struct cvmcache_hash *a, struct cvmcache_hash *b)
static const double kShrinkFactor
lru::LruCache< ComparableHash, ObjectHeader * > * objects_all_
void cvmcache_options_free(char *value)
static uint64_t RoundUp8(const uint64_t size)
Definition: smalloc.h:37
void cvmcache_spawn_watchdog(const char *crash_dump_file)
static const double kDangerZoneThreshold
void cvmcache_options_fini(cvmcache_option_map *opts)
enum cvmcache_object_type type
void DoShrink(uint64_t shrink_to)
uint32_t size_desc
static const double kSlotFraction
static PluginRamCache * Me()
struct cvmcache_context * cvmcache_init(struct cvmcache_callbacks *callbacks)
static int ram_listing_end(int64_t listing_id)
static uint32_t hasher_uint64(const uint64_t &key)
lru::LruCache< ComparableHash, ObjectHeader * > * objects_volatile_
bool TryFreeSpace(uint64_t bytes_required)
void cvmcache_init_global()
vector< Object > * elems
char * GetDescription()
static const uint64_t kMinSize
static int ram_shrink(uint64_t shrink_to, uint64_t *used)
cvmcache_object_type type
int cvmcache_options_parse(cvmcache_option_map *opts, const char *path)
void DropBreadcrumbs(int sig, siginfo_t *siginfo, void *context)
int(* cvmcache_shrink)(uint64_t shrink_to, uint64_t *used)
#define CVMCACHE_SIZE_UNKNOWN
static int ram_breadcrumb_store(const char *fqrn, const cvmcache_breadcrumb *breadcrumb)
uint64_t String2Uint64(const string &value)
Definition: string.cc:240
int(* cvmcache_listing_begin)(uint64_t lst_id, enum cvmcache_object_type type)
bool operator>(const ComparableHash &other) const
void cvmcache_process_requests(struct cvmcache_context *ctx, unsigned nworkers)
int(* cvmcache_breadcrumb_store)(const char *fqrn, const cvmcache_breadcrumb *breadcrumb)
map< std::string, cvmcache_breadcrumb > breadcrumbs_
char * cvmcache_options_get(cvmcache_option_map *opts, const char *key)
int(* cvmcache_commit_txn)(uint64_t txn_id)
int(* cvmcache_start_txn)(struct cvmcache_hash *id, uint64_t txn_id, struct cvmcache_object_info *info)
int(* cvmcache_listing_end)(int64_t lst_id)
int(* cvmcache_abort_txn)(uint64_t txn_id)
ComparableHash(const struct cvmcache_hash &h)
void SetDescription(char *description)
static int ram_obj_info(struct cvmcache_hash *id, struct cvmcache_object_info *info)
static PluginRamCache * instance_
int(* cvmcache_obj_info)(struct cvmcache_hash *id, struct cvmcache_object_info *info)
static void size_t size
Definition: smalloc.h:54
uint32_t MurmurHash2(const void *key, int len, uint32_t seed)
Definition: murmur.hxx:23
cvmcache_option_map * cvmcache_options_init()
static int ram_breadcrumb_load(const char *fqrn, cvmcache_breadcrumb *breadcrumb)
bool operator<(const ComparableHash &other) const
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545