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  const 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  const 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  const ComparableHash h(*id);
240  ObjectHeader *object;
241  const bool retval = Me()->objects_all_->Lookup(h, &object, false);
242  assert(retval);
243  if (offset > object->size_data)
245  const unsigned nbytes =
246  std::min(*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  const uint32_t total_size = sizeof(object_header) +
269  object_header.size_desc +
270  object_header.size_data;
271  Me()->TryFreeSpace(total_size);
272  ObjectHeader *allocd_object = reinterpret_cast<ObjectHeader *>(
273  Me()->storage_->Allocate(total_size, &object_header,
274  sizeof(object_header)));
275  if (allocd_object == NULL)
277 
278  allocd_object->SetDescription(info->description);
279  Me()->transactions_.Insert(txn_id, allocd_object);
280  return CVMCACHE_STATUS_OK;
281  }
282 
283 
284  static int ram_write_txn(uint64_t txn_id,
285  unsigned char *buffer,
286  uint32_t size) {
287  ObjectHeader *txn_object;
288  int retval = Me()->transactions_.Lookup(txn_id, &txn_object);
289  assert(retval);
290  assert(size > 0);
291 
292  if (txn_object->neg_nbytes_written > 0)
293  txn_object->neg_nbytes_written = 0;
294  if ((size - txn_object->neg_nbytes_written) > txn_object->size_data) {
295  const uint32_t current_size = Me()->storage_->GetSize(txn_object);
296  const uint32_t header_size = current_size - txn_object->size_data;
297  const uint32_t new_size =
298  std::max(header_size + size - txn_object->neg_nbytes_written,
299  uint32_t(current_size * kObjectExpandFactor));
300  const bool did_compact = Me()->TryFreeSpace(new_size);
301  if (did_compact) {
302  retval = Me()->transactions_.Lookup(txn_id, &txn_object);
303  assert(retval);
304  }
305  txn_object = reinterpret_cast<ObjectHeader *>(
306  Me()->storage_->Expand(txn_object, new_size));
307  if (txn_object == NULL)
309  txn_object->size_data = new_size - header_size;
310  Me()->transactions_.Insert(txn_id, txn_object);
311  }
312 
313  memcpy(txn_object->GetData() - txn_object->neg_nbytes_written, buffer,
314  size);
315  txn_object->neg_nbytes_written -= size;
316  return CVMCACHE_STATUS_OK;
317  }
318 
319 
320  static int ram_commit_txn(uint64_t txn_id) {
321  Me()->TryFreeSpace(0);
322  if (Me()->objects_all_->IsFull())
324 
325  ObjectHeader *txn_object;
326  const int retval = Me()->transactions_.Lookup(txn_id, &txn_object);
327  assert(retval);
328 
329  Me()->transactions_.Erase(txn_id);
330  const ComparableHash h(txn_object->id);
331  ObjectHeader *existing_object;
332  if (Me()->objects_all_->Lookup(h, &existing_object)) {
333  // Concurrent addition of same objects, drop the one at hand and
334  // increase ref count of existing copy
335  Me()->storage_->MarkFree(txn_object);
336  if (existing_object->refcnt == 0)
337  Me()->cache_info_.pinned_bytes += Me()->storage_->GetSize(
338  existing_object);
339  existing_object->refcnt++;
340  } else {
341  txn_object->txn_id = uint64_t(-1);
342  if (txn_object->neg_nbytes_written > 0)
343  txn_object->neg_nbytes_written = 0;
344  txn_object->size_data = -(txn_object->neg_nbytes_written);
345  txn_object->refcnt = 1;
346  Me()->cache_info_.used_bytes += Me()->storage_->GetSize(txn_object);
347  Me()->cache_info_.pinned_bytes += Me()->storage_->GetSize(txn_object);
348  Me()->objects_all_->Insert(h, txn_object);
349  if (txn_object->type == CVMCACHE_OBJECT_VOLATILE) {
350  assert(!Me()->objects_volatile_->IsFull());
351  Me()->objects_volatile_->Insert(h, txn_object);
352  }
353  }
354  Me()->CheckHighPinWatermark();
355  return CVMCACHE_STATUS_OK;
356  }
357 
358 
359  static int ram_abort_txn(uint64_t txn_id) {
360  ObjectHeader *txn_object = NULL;
361  const int retval = Me()->transactions_.Lookup(txn_id, &txn_object);
362  assert(retval);
363  Me()->transactions_.Erase(txn_id);
364  Me()->storage_->MarkFree(txn_object);
365  return CVMCACHE_STATUS_OK;
366  }
367 
368 
369  static int ram_info(struct cvmcache_info *info) {
370  *info = Me()->cache_info_;
371  return CVMCACHE_STATUS_OK;
372  }
373 
374 
375  static int ram_shrink(uint64_t shrink_to, uint64_t *used) {
376  *used = Me()->cache_info_.used_bytes;
377  if (*used <= shrink_to)
378  return CVMCACHE_STATUS_OK;
379 
380  Me()->DoShrink(shrink_to);
381  *used = Me()->cache_info_.used_bytes;
382  return (*used <= shrink_to) ? CVMCACHE_STATUS_OK : CVMCACHE_STATUS_PARTIAL;
383  }
384 
385 
386  static int ram_listing_begin(uint64_t lst_id,
387  enum cvmcache_object_type type) {
388  Listing *lst = new Listing();
389  Me()->objects_all_->FilterBegin();
390  while (Me()->objects_all_->FilterNext()) {
391  ComparableHash h;
392  ObjectHeader *object;
393  Me()->objects_all_->FilterGet(&h, &object);
394  if (object->type != type)
395  continue;
396 
397  struct cvmcache_object_info item;
398  item.id = object->id;
399  item.size = object->size_data;
400  item.type = type;
401  item.pinned = object->refcnt != 0;
402  item.description = (object->size_desc > 0)
403  ? strdup(object->GetDescription())
404  : NULL;
405  lst->elems.push_back(item);
406  }
407  Me()->objects_all_->FilterEnd();
408 
409  Me()->listings_.Insert(lst_id, lst);
410  return CVMCACHE_STATUS_OK;
411  }
412 
413 
414  static int ram_listing_next(int64_t listing_id,
415  struct cvmcache_object_info *item) {
416  Listing *lst;
417  const bool retval = Me()->listings_.Lookup(listing_id, &lst);
418  assert(retval);
419  if (lst->pos >= lst->elems.size())
421  *item = lst->elems[lst->pos];
422  lst->pos++;
423  return CVMCACHE_STATUS_OK;
424  }
425 
426 
427  static int ram_listing_end(int64_t listing_id) {
428  Listing *lst;
429  const bool retval = Me()->listings_.Lookup(listing_id, &lst);
430  assert(retval);
431 
432  // Don't free description strings, done by the library
433  delete lst;
434  Me()->listings_.Erase(listing_id);
435  return CVMCACHE_STATUS_OK;
436  }
437 
438 
439  static int ram_breadcrumb_store(const char *fqrn,
440  const cvmcache_breadcrumb *breadcrumb) {
441  Me()->breadcrumbs_[fqrn] = *breadcrumb;
442  return CVMCACHE_STATUS_OK;
443  }
444 
445 
446  static int ram_breadcrumb_load(const char *fqrn,
447  cvmcache_breadcrumb *breadcrumb) {
448  const map<std::string, cvmcache_breadcrumb>::const_iterator itr =
449  Me()->breadcrumbs_.find(fqrn);
450  if (itr == Me()->breadcrumbs_.end())
452  *breadcrumb = itr->second;
453  return CVMCACHE_STATUS_OK;
454  }
455 
456  private:
457  static const uint64_t kMinSize; // 100 * 1024 * 1024;
458  static const double kShrinkFactor; // = 0.75;
459  static const double kObjectExpandFactor; // = 1.5;
460  static const double kSlotFraction; // = 0.04;
461  static const double kDangerZoneThreshold; // = 0.7
462 
464  static PluginRamCache *Me() { return instance_; }
465  explicit PluginRamCache(uint64_t mem_size) {
466  in_danger_zone_ = false;
467 
468  const uint64_t heap_size = RoundUp8(
469  std::max(kMinSize, uint64_t(mem_size * (1.0 - kSlotFraction))));
470  memset(&cache_info_, 0, sizeof(cache_info_));
471  cache_info_.size_bytes = heap_size;
472  storage_ = new MallocHeap(
473  heap_size, this->MakeCallback(&PluginRamCache::OnBlockMove, this));
474 
475  struct cvmcache_hash hash_empty;
476  memset(&hash_empty, 0, sizeof(hash_empty));
477 
478  transactions_.Init(64, uint64_t(-1), hasher_uint64);
479  listings_.Init(8, uint64_t(-1), hasher_uint64);
480 
481  const double slot_size =
483  const uint64_t num_slots =
484  uint64_t((heap_size * kSlotFraction) / (2.0 * slot_size));
485  const unsigned mask_64 = ~((1 << 6) - 1);
486 
488  "Allocating %" PRIu64 "MB of memory for up to %" PRIu64 " objects",
489  heap_size / (1024 * 1024), num_slots & mask_64);
490 
491  // Number of cache entries must be a multiple of 64
493  num_slots & mask_64,
494  ComparableHash(hash_empty),
495  hasher_any,
496  perf::StatisticsTemplate("objects_all", &statistics_));
497  objects_volatile_ = new lru::LruCache<ComparableHash, ObjectHeader *>(
498  num_slots & mask_64,
499  ComparableHash(hash_empty),
500  hasher_any,
501  perf::StatisticsTemplate("objects_volatile", &statistics_));
502  }
503 
508  bool TryFreeSpace(uint64_t bytes_required) {
509  if (!objects_all_->IsFull() && storage_->HasSpaceFor(bytes_required))
510  return false;
511 
512  // Free space occupied due to piecewise catalog storage
513  if (!objects_all_->IsFull()) {
514  LogCvmfs(kLogCache, kLogDebug, "compacting ram cache");
515  storage_->Compact();
516  if (storage_->HasSpaceFor(bytes_required))
517  return true;
518  }
519 
520  const uint64_t shrink_to =
521  std::min(storage_->capacity() - (bytes_required + 8),
522  uint64_t(storage_->capacity() * kShrinkFactor));
523  DoShrink(shrink_to);
524  return true;
525  }
526 
528  assert(ptr.pointer);
529  ObjectHeader *object = reinterpret_cast<ObjectHeader *>(ptr.pointer);
530  const ComparableHash h(object->id);
531  if (object->txn_id == uint64_t(-1)) {
532  bool retval = objects_all_->UpdateValue(h, object);
533  assert(retval);
534  if (object->type == CVMCACHE_OBJECT_VOLATILE) {
535  retval = objects_volatile_->UpdateValue(h, object);
536  assert(retval);
537  }
538  } else {
539  const uint64_t old_size = transactions_.size();
540  transactions_.Insert(object->txn_id, object);
541  assert(old_size == transactions_.size());
542  }
543  }
544 
545 
546  void DoShrink(uint64_t shrink_to) {
547  ComparableHash h;
548  ObjectHeader *object;
549 
551  "clean up cache until at most %lu KB is used", shrink_to / 1024);
552 
553  objects_volatile_->FilterBegin();
554  while (objects_volatile_->FilterNext()) {
555  objects_volatile_->FilterGet(&h, &object);
556  if (object->refcnt != 0)
557  continue;
558  cache_info_.used_bytes -= storage_->GetSize(object);
559  storage_->MarkFree(object);
560  objects_volatile_->FilterDelete();
561  objects_all_->Forget(h);
562  if (storage_->compacted_bytes() <= shrink_to)
563  break;
564  }
565  objects_volatile_->FilterEnd();
566 
567  objects_all_->FilterBegin();
568  while ((storage_->compacted_bytes() > shrink_to)
569  && objects_all_->FilterNext()) {
570  objects_all_->FilterGet(&h, &object);
571  if (object->refcnt != 0)
572  continue;
574  cache_info_.used_bytes -= storage_->GetSize(object);
575  storage_->MarkFree(object);
576  objects_all_->FilterDelete();
577  }
578  objects_all_->FilterEnd();
579 
580  storage_->Compact();
581  cache_info_.no_shrink++;
582  }
583 
585  if (!Me()->in_danger_zone_ && Me()->IsInDangerZone()) {
587  "high watermark of pinned files");
588  Me()->in_danger_zone_ = true;
590  }
591  }
592 
593  bool IsInDangerZone() {
594  return (static_cast<double>(cache_info_.pinned_bytes)
595  / static_cast<double>(cache_info_.size_bytes))
596  > kDangerZoneThreshold;
597  }
598 
599 
600  struct cvmcache_info cache_info_;
606  map<std::string, cvmcache_breadcrumb> breadcrumbs_;
609 }; // class PluginRamCache
610 
612 const uint64_t PluginRamCache::kMinSize = 100 * 1024 * 1024;
613 const double PluginRamCache::kShrinkFactor = 0.75;
614 const double PluginRamCache::kObjectExpandFactor = 1.5;
615 const double PluginRamCache::kSlotFraction = 0.04;
616 const double PluginRamCache::kDangerZoneThreshold = 0.7;
617 
618 
619 static void Usage(const char *progname) {
620  LogCvmfs(kLogCache, kLogStdout, "%s <config file>", progname);
621 }
622 
623 
628 void DropBreadcrumbs(int sig, siginfo_t *siginfo, void *context) {
629  LogCvmfs(kLogCache, kLogSyslog | kLogDebug, "dropping breadcrumbs");
631 }
632 
633 
634 int main(int argc, char **argv) {
635  if (argc < 2) {
636  Usage(argv[0]);
637  return 1;
638  }
639 
640  SetLogDebugFile("/dev/null");
641 
643 
645  if (cvmcache_options_parse(options, argv[1]) != 0) {
646  LogCvmfs(kLogCache, kLogStderr, "cannot parse options file %s", argv[1]);
647  return 1;
648  }
649  char *debug_log = cvmcache_options_get(options,
650  "CVMFS_CACHE_PLUGIN_DEBUGLOG");
651  if (debug_log != NULL) {
652  SetLogDebugFile(debug_log);
653  cvmcache_options_free(debug_log);
654  }
655  char *locator = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_LOCATOR");
656  if (locator == NULL) {
657  LogCvmfs(kLogCache, kLogStderr, "CVMFS_CACHE_PLUGIN_LOCATOR missing");
658  cvmcache_options_fini(options);
659  return 1;
660  }
661  char *mem_size = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_SIZE");
662  if (mem_size == NULL) {
663  LogCvmfs(kLogCache, kLogStderr, "CVMFS_CACHE_PLUGIN_SIZE missing");
664  cvmcache_options_fini(options);
665  return 1;
666  }
667  char *test_mode = cvmcache_options_get(options, "CVMFS_CACHE_PLUGIN_TEST");
668 
669  if (!test_mode)
671 
672  PluginRamCache *plugin = PluginRamCache::Create(mem_size);
673  struct sigaction sa;
674  memset(&sa, 0, sizeof(sa));
675  sa.sa_sigaction = DropBreadcrumbs;
676  sa.sa_flags = SA_SIGINFO;
677  sigfillset(&sa.sa_mask);
678  int retval = sigaction(SIGUSR2, &sa, NULL);
679  assert(retval == 0);
680 
681  struct cvmcache_callbacks callbacks;
682  memset(&callbacks, 0, sizeof(callbacks));
683  callbacks.cvmcache_chrefcnt = plugin->ram_chrefcnt;
684  callbacks.cvmcache_obj_info = plugin->ram_obj_info;
685  callbacks.cvmcache_pread = plugin->ram_pread;
686  callbacks.cvmcache_start_txn = plugin->ram_start_txn;
687  callbacks.cvmcache_write_txn = plugin->ram_write_txn;
688  callbacks.cvmcache_commit_txn = plugin->ram_commit_txn;
689  callbacks.cvmcache_abort_txn = plugin->ram_abort_txn;
690  callbacks.cvmcache_info = plugin->ram_info;
691  callbacks.cvmcache_shrink = plugin->ram_shrink;
692  callbacks.cvmcache_listing_begin = plugin->ram_listing_begin;
693  callbacks.cvmcache_listing_next = plugin->ram_listing_next;
694  callbacks.cvmcache_listing_end = plugin->ram_listing_end;
696  callbacks.cvmcache_breadcrumb_load = plugin->ram_breadcrumb_load;
697  callbacks.capabilities = CVMCACHE_CAP_ALL_V2;
698 
699  ctx = cvmcache_init(&callbacks);
700  retval = cvmcache_listen(ctx, locator);
701  if (!retval) {
702  LogCvmfs(kLogCache, kLogStderr, "failed to listen on %s", locator);
703  return 1;
704  }
705 
706  if (test_mode) {
707  // Daemonize, print out PID
708  pid_t pid;
709  int statloc;
710  if ((pid = fork()) == 0) {
711  if ((pid = fork()) == 0) {
712  const int null_read = open("/dev/null", O_RDONLY);
713  const int null_write = open("/dev/null", O_WRONLY);
714  assert((null_read >= 0) && (null_write >= 0));
715  int retval = dup2(null_read, 0);
716  assert(retval == 0);
717  retval = dup2(null_write, 1);
718  assert(retval == 1);
719  retval = dup2(null_write, 2);
720  assert(retval == 2);
721  close(null_read);
722  close(null_write);
723  } else {
724  assert(pid > 0);
725  printf("%d\n", pid);
726  fflush(stdout);
727  fsync(1);
728  _exit(0);
729  }
730  } else {
731  assert(pid > 0);
732  waitpid(pid, &statloc, 0);
733  _exit(0);
734  }
735  }
736 
738  "Listening for cvmfs clients on %s\n"
739  "NOTE: this process needs to run as user cvmfs\n",
740  locator);
741 
743  if (test_mode)
744  while (true)
745  sleep(1);
746  if (!cvmcache_is_supervised()) {
747  LogCvmfs(kLogCache, kLogStdout, "Press <Ctrl+D> to quit");
749  "Press <R Enter> to ask clients to release nested catalogs");
750  while (true) {
751  char buf;
752  retval = read(fileno(stdin), &buf, 1);
753  if (retval != 1)
754  break;
755  if (buf == 'R') {
757  " ... asking clients to release nested catalogs");
759  }
760  }
762  } else {
764  "CernVM-FS RAM cache plugin started in supervised mode");
765  }
766 
768  LogCvmfs(kLogCache, kLogDebug | kLogStdout, " ... good bye");
769  cvmcache_options_free(mem_size);
770  cvmcache_options_free(locator);
771  cvmcache_options_fini(options);
774  return 0;
775 }
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 double GetEntrySize()
Definition: lru.h:541
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