CernVM-FS  2.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
glue_buffer.h
Go to the documentation of this file.
1 
11 #include <gtest/gtest_prod.h>
12 #include <pthread.h>
13 #include <sched.h>
14 #include <stdint.h>
15 
16 #include <cassert>
17 #include <cstring>
18 #include <map>
19 #include <string>
20 #include <vector>
21 
22 #include "bigqueue.h"
23 #include "bigvector.h"
24 #include "crypto/hash.h"
25 #include "shortstring.h"
26 #include "smallhash.h"
27 #include "util/atomic.h"
28 #include "util/mutex.h"
29 #include "util/platform.h"
30 #include "util/posix.h"
31 #include "util/smalloc.h"
32 #include "util/string.h"
33 
34 #ifndef CVMFS_GLUE_BUFFER_H_
35 #define CVMFS_GLUE_BUFFER_H_
36 
37 namespace glue {
38 
47 class InodeEx {
48  private:
49  // Extracts the file type bits from the POSIX mode field and shifts them to
50  // the right so that they align with EFileType constants.
51  static inline uint64_t ShiftMode(unsigned mode) { return (mode >> 12) & 017; }
52 
53  public:
54  enum EFileType {
56  kRegular = 010,
57  kSymlink = 012,
58  kDirectory = 004,
59  kFifo = 001,
60  kSocket = 014,
61  kCharDev = 002,
62  kBulkDev = 006,
63  };
64 
65  InodeEx() : inode_ex_(0) { }
66  InodeEx(uint64_t inode, EFileType type)
67  : inode_ex_(inode | (static_cast<uint64_t>(type) << 60))
68  { }
69  InodeEx(uint64_t inode, unsigned mode)
70  : inode_ex_(inode | (ShiftMode(mode) << 60))
71  { }
72 
73  inline uint64_t GetInode() const { return inode_ex_ & ~(uint64_t(15) << 60); }
74  inline EFileType GetFileType() const {
75  return static_cast<EFileType>(inode_ex_ >> 60);
76  }
77 
78  inline bool operator==(const InodeEx &other) const {
79  return GetInode() == other.GetInode();
80  }
81  inline bool operator!=(const InodeEx &other) const {
82  return GetInode() != other.GetInode();
83  }
84 
85  inline bool IsCompatibleFileType(unsigned mode) const {
86  return (static_cast<uint64_t>(GetFileType()) == ShiftMode(mode)) ||
88  }
89 
90  private:
91  uint64_t inode_ex_;
92 };
93 
94 static inline uint32_t hasher_md5(const shash::Md5 &key) {
95  // Don't start with the first bytes, because == is using them as well
96  return (uint32_t) *(reinterpret_cast<const uint32_t *>(key.digest) + 1);
97 }
98 
99 static inline uint32_t hasher_inode(const uint64_t &inode) {
100  return MurmurHash2(&inode, sizeof(inode), 0x07387a4f);
101 }
102 
103 static inline uint32_t hasher_inode_ex(const InodeEx &inode_ex) {
104  return hasher_inode(inode_ex.GetInode());
105 }
106 
107 
108 //------------------------------------------------------------------------------
109 
110 
114 class StringRef {
115  public:
117  length_ = NULL;
118  }
119 
120  uint16_t length() const { return *length_; }
121  uint16_t size() const { return sizeof(uint16_t) + *length_; }
122  static uint16_t size(const uint16_t length) {
123  return sizeof(uint16_t) + length;
124  }
125  char *data() const { return reinterpret_cast<char *>(length_ + 1); }
126  static StringRef Place(const uint16_t length, const char *str,
127  void *addr)
128  {
129  StringRef result;
130  result.length_ = reinterpret_cast<uint16_t *>(addr);
131  *result.length_ = length;
132  if (length > 0)
133  memcpy(result.length_ + 1, str, length);
134  return result;
135  }
136  private:
137  uint16_t *length_;
138 };
139 
140 
141 //------------------------------------------------------------------------------
142 
143 
149 class StringHeap : public SingleCopy {
150  public:
152  Init(128*1024); // 128kB (should be >= 64kB+2B which is largest string)
153  }
154 
155  explicit StringHeap(const uint64_t minimum_size) {
156  Init(minimum_size);
157  }
158 
159  void Init(const uint64_t minimum_size) {
160  size_ = 0;
161  used_ = 0;
162 
163  // Initial bin: 128kB or smallest power of 2 >= minimum size
164  uint64_t pow2_size = 128 * 1024;
165  while (pow2_size < minimum_size)
166  pow2_size *= 2;
167  AddBin(pow2_size);
168  }
169 
171  for (unsigned i = 0; i < bins_.size(); ++i) {
172  smunmap(bins_.At(i));
173  }
174  }
175 
176  StringRef AddString(const uint16_t length, const char *str) {
177  const uint16_t str_size = StringRef::size(length);
178  const uint64_t remaining_bin_size = bin_size_ - bin_used_;
179  // May require opening of new bin
180  if (remaining_bin_size < str_size) {
181  size_ += remaining_bin_size;
182  AddBin(2*bin_size_);
183  }
184  StringRef result =
185  StringRef::Place(length, str,
186  static_cast<char *>(bins_.At(bins_.size()-1))+bin_used_);
187  size_ += str_size;
188  used_ += str_size;
189  bin_used_ += str_size;
190  return result;
191  }
192 
193  void RemoveString(const StringRef str_ref) {
194  used_ -= str_ref.size();
195  }
196 
197  double GetUsage() const {
198  if (size_ == 0) return 1.0;
199  return static_cast<double>(used_) / static_cast<double>(size_);
200  }
201 
202  uint64_t used() const { return used_; }
203 
204  // mmap'd bytes, used for testing
205  uint64_t GetSizeAlloc() const {
206  uint64_t s = bin_size_;
207  uint64_t result = 0;
208  for (unsigned i = 0; i < bins_.size(); ++i) {
209  result += s;
210  s /= 2;
211  }
212  return result;
213  }
214 
215  private:
216  void AddBin(const uint64_t size) {
217  void *bin = smmap(size);
218  bins_.PushBack(bin);
219  bin_size_ = size;
220  bin_used_ = 0;
221  }
222 
223  uint64_t size_;
224  uint64_t used_;
225  uint64_t bin_size_;
226  uint64_t bin_used_;
228 };
229 
230 
231 //------------------------------------------------------------------------------
232 
233 
234 class PathStore {
235  public:
239  struct Cursor {
240  Cursor() : idx(0) { }
241  uint32_t idx;
242  };
243 
244 
246  map_.Init(16, shash::Md5(shash::AsciiPtr("!")), hasher_md5);
247  string_heap_ = new StringHeap();
248  }
249 
251  delete string_heap_;
252  }
253 
254  explicit PathStore(const PathStore &other);
255  PathStore &operator= (const PathStore &other);
256 
257  void Insert(const shash::Md5 &md5path, const PathString &path) {
258  PathInfo info;
259  bool found = map_.Lookup(md5path, &info);
260  if (found) {
261  info.refcnt++;
262  map_.Insert(md5path, info);
263  return;
264  }
265 
266  PathInfo new_entry;
267  if (path.IsEmpty()) {
268  new_entry.name = string_heap_->AddString(0, "");
269  map_.Insert(md5path, new_entry);
270  return;
271  }
272 
273  PathString parent_path = GetParentPath(path);
274  new_entry.parent = shash::Md5(parent_path.GetChars(),
275  parent_path.GetLength());
276  Insert(new_entry.parent, parent_path);
277 
278  const uint16_t name_length = path.GetLength() - parent_path.GetLength() - 1;
279  const char *name_str = path.GetChars() + parent_path.GetLength() + 1;
280  new_entry.name = string_heap_->AddString(name_length, name_str);
281  map_.Insert(md5path, new_entry);
282  }
283 
284  bool Lookup(const shash::Md5 &md5path, PathString *path) {
285  PathInfo info;
286  bool retval = map_.Lookup(md5path, &info);
287  if (!retval)
288  return false;
289 
290  if (info.parent.IsNull())
291  return true;
292 
293  retval = Lookup(info.parent, path);
294  assert(retval);
295  path->Append("/", 1);
296  path->Append(info.name.data(), info.name.length());
297  return true;
298  }
299 
300  void Erase(const shash::Md5 &md5path) {
301  PathInfo info;
302  bool found = map_.Lookup(md5path, &info);
303  if (!found)
304  return;
305 
306  info.refcnt--;
307  if (info.refcnt == 0) {
308  map_.Erase(md5path);
310  if (string_heap_->GetUsage() < 0.75) {
311  StringHeap *new_string_heap = new StringHeap(string_heap_->used());
312  shash::Md5 empty_path = map_.empty_key();
313  for (unsigned i = 0; i < map_.capacity(); ++i) {
314  if (map_.keys()[i] != empty_path) {
315  (map_.values() + i)->name =
316  new_string_heap->AddString(map_.values()[i].name.length(),
317  map_.values()[i].name.data());
318  }
319  }
320  delete string_heap_;
321  string_heap_ = new_string_heap;
322  }
323  Erase(info.parent);
324  } else {
325  map_.Insert(md5path, info);
326  }
327  }
328 
329  void Clear() {
330  map_.Clear();
331  delete string_heap_;
332  string_heap_ = new StringHeap();
333  }
334 
336  return Cursor();
337  }
338 
339  bool Next(Cursor *cursor, shash::Md5 *parent, StringRef *name) {
340  shash::Md5 empty_key = map_.empty_key();
341  while (cursor->idx < map_.capacity()) {
342  if (map_.keys()[cursor->idx] == empty_key) {
343  cursor->idx++;
344  continue;
345  }
346  *parent = map_.values()[cursor->idx].parent;
347  *name = map_.values()[cursor->idx].name;
348  cursor->idx++;
349  return true;
350  }
351  return false;
352  }
353 
354  private:
355  struct PathInfo {
357  refcnt = 1;
358  }
360  uint32_t refcnt;
362  };
363 
364  void CopyFrom(const PathStore &other);
365 
368 };
369 
370 
371 //------------------------------------------------------------------------------
372 
373 
381 class StatStore {
382  public:
383  int32_t Add(const struct stat &info) {
384  // We don't support more that 2B open files
385  assert(store_.size() < (1LU << 31));
386  int32_t index = static_cast<int>(store_.size());
387  store_.PushBack(info);
388  return index;
389  }
390 
391  // Note that that if the last element is removed, no swap has taken place
392  uint64_t Erase(int32_t index) {
393  struct stat info_back = store_.At(store_.size() - 1);
394  store_.Replace(index, info_back);
395  store_.SetSize(store_.size() - 1);
397  return info_back.st_ino;
398  }
399 
400  struct stat Get(int32_t index) const { return store_.At(index); }
401 
402  private:
404 };
405 
406 
407 //------------------------------------------------------------------------------
408 
409 
410 class PathMap {
411  public:
414  }
415 
416  bool LookupPath(const shash::Md5 &md5path, PathString *path) {
417  bool found = path_store_.Lookup(md5path, path);
418  return found;
419  }
420 
421  uint64_t LookupInodeByPath(const PathString &path) {
422  uint64_t inode;
423  bool found = map_.Lookup(shash::Md5(path.GetChars(), path.GetLength()),
424  &inode);
425  if (found) return inode;
426  return 0;
427  }
428 
429  uint64_t LookupInodeByMd5Path(const shash::Md5 &md5path) {
430  uint64_t inode;
431  bool found = map_.Lookup(md5path, &inode);
432  if (found) return inode;
433  return 0;
434  }
435 
436  shash::Md5 Insert(const PathString &path, const uint64_t inode) {
437  shash::Md5 md5path(path.GetChars(), path.GetLength());
438  if (!map_.Contains(md5path)) {
439  path_store_.Insert(md5path, path);
440  map_.Insert(md5path, inode);
441  }
442  return md5path;
443  }
444 
445  void Erase(const shash::Md5 &md5path) {
446  bool found = map_.Contains(md5path);
447  if (found) {
448  path_store_.Erase(md5path);
449  map_.Erase(md5path);
450  }
451  }
452 
453  void Replace(const shash::Md5 &md5path, uint64_t new_inode) {
454  map_.Insert(md5path, new_inode);
455  }
456 
457  void Clear() {
458  map_.Clear();
459  path_store_.Clear();
460  }
461 
462  // For enumerating
464 
465  private:
468 };
469 
470 
471 //------------------------------------------------------------------------------
472 
473 
478 class InodeExMap {
479  public:
481  map_.Init(16, InodeEx(), hasher_inode_ex);
482  }
483 
484  bool LookupMd5Path(InodeEx *inode_ex, shash::Md5 *md5path) {
485  bool found = map_.LookupEx(inode_ex, md5path);
486  return found;
487  }
488 
489  void Insert(const InodeEx inode_ex, const shash::Md5 &md5path) {
490  map_.Insert(inode_ex, md5path);
491  }
492 
493  void Erase(const uint64_t inode) {
494  map_.Erase(InodeEx(inode, InodeEx::kUnknownType));
495  }
496 
497  void Clear() { map_.Clear(); }
498 
499  private:
501 };
502 
503 
504 //------------------------------------------------------------------------------
505 
506 
508  public:
512  struct Cursor {
513  Cursor() : idx(0) { }
514  uint32_t idx;
515  };
516 
518  map_.Init(16, 0, hasher_inode);
519  }
520 
521  bool Get(const uint64_t inode, const uint32_t by) {
522  uint32_t refcounter = 0;
523  const bool found = map_.Lookup(inode, &refcounter);
524  const bool new_inode = !found;
525  refcounter += by; // This is 0 if the inode is not found
526  map_.Insert(inode, refcounter);
527  return new_inode;
528  }
529 
530  bool Put(const uint64_t inode, const uint32_t by) {
531  uint32_t refcounter;
532  bool found = map_.Lookup(inode, &refcounter);
533  if (!found) {
534  // May happen if a retired inode is cleared, i.e. if a file with
535  // outdated content is closed
536  return false;
537  }
538 
539  assert(refcounter >= by);
540  if (refcounter == by) {
541  map_.Erase(inode);
542  return true;
543  }
544  refcounter -= by;
545  map_.Insert(inode, refcounter);
546  return false;
547  }
548 
549  void Replace(const uint64_t old_inode, const uint64_t new_inode) {
550  map_.Erase(old_inode);
551  map_.Insert(new_inode, 0);
552  }
553 
554  void Clear() {
555  map_.Clear();
556  }
557 
559  return Cursor();
560  }
561 
562  bool Next(Cursor *cursor, uint64_t *inode) {
563  uint64_t empty_key = map_.empty_key();
564  while (cursor->idx < map_.capacity()) {
565  if (map_.keys()[cursor->idx] == empty_key) {
566  cursor->idx++;
567  continue;
568  }
569  *inode = map_.keys()[cursor->idx];
570  cursor->idx++;
571  return true;
572  }
573  return false;
574  }
575 
576  private:
578 };
579 
580 
581 //------------------------------------------------------------------------------
582 
583 
588  public:
592  struct Cursor {
593  explicit Cursor(
594  const PathStore::Cursor &p,
595  const InodeReferences::Cursor &i)
596  : csr_paths(p)
597  , csr_inos(i)
598  { }
601  };
602 
609  class VfsPutRaii {
610  public:
611  explicit VfsPutRaii(InodeTracker *t) : tracker_(t) {
612  tracker_->Lock();
613  }
615 
616  bool VfsPut(const uint64_t inode, const uint32_t by) {
617  bool removed = tracker_->inode_references_.Put(inode, by);
618  if (removed) {
619  // TODO(jblomer): pop operation (Lookup+Erase)
620  shash::Md5 md5path;
621  InodeEx inode_ex(inode, InodeEx::kUnknownType);
622  bool found = tracker_->inode_ex_map_.LookupMd5Path(&inode_ex, &md5path);
623  assert(found);
624  tracker_->inode_ex_map_.Erase(inode);
625  tracker_->path_map_.Erase(md5path);
626  atomic_inc64(&tracker_->statistics_.num_removes);
627  }
628  atomic_xadd64(&tracker_->statistics_.num_references, -int32_t(by));
629  return removed;
630  }
631 
632  private:
634  };
635 
636  // Cannot be moved to the statistics manager because it has to survive
637  // reloads. Added manually in the fuse module initialization and in talk.cc.
638  struct Statistics {
640  atomic_init64(&num_inserts);
641  atomic_init64(&num_removes);
642  atomic_init64(&num_references);
643  atomic_init64(&num_hits_inode);
644  atomic_init64(&num_hits_path);
645  atomic_init64(&num_misses_path);
646  }
647  std::string Print() {
648  return
649  "inserts: " + StringifyInt(atomic_read64(&num_inserts)) +
650  " removes: " + StringifyInt(atomic_read64(&num_removes)) +
651  " references: " + StringifyInt(atomic_read64(&num_references)) +
652  " hits(inode): " + StringifyInt(atomic_read64(&num_hits_inode)) +
653  " hits(path): " + StringifyInt(atomic_read64(&num_hits_path)) +
654  " misses(path): " + StringifyInt(atomic_read64(&num_misses_path));
655  }
662  };
664 
665  InodeTracker();
666  explicit InodeTracker(const InodeTracker &other);
667  InodeTracker &operator= (const InodeTracker &other);
668  ~InodeTracker();
669 
670  void VfsGetBy(const InodeEx inode_ex, const uint32_t by,
671  const PathString &path)
672  {
673  uint64_t inode = inode_ex.GetInode();
674  Lock();
675  bool is_new_inode = inode_references_.Get(inode, by);
676  shash::Md5 md5path = path_map_.Insert(path, inode);
677  inode_ex_map_.Insert(inode_ex, md5path);
678  Unlock();
679 
680  atomic_xadd64(&statistics_.num_references, by);
681  if (is_new_inode) atomic_inc64(&statistics_.num_inserts);
682  }
683 
684  void VfsGet(const InodeEx inode_ex, const PathString &path) {
685  VfsGetBy(inode_ex, 1, path);
686  }
687 
688  VfsPutRaii GetVfsPutRaii() { return VfsPutRaii(this); }
689 
690  bool FindPath(InodeEx *inode_ex, PathString *path) {
691  Lock();
692  shash::Md5 md5path;
693  bool found = inode_ex_map_.LookupMd5Path(inode_ex, &md5path);
694  if (found) {
695  found = path_map_.LookupPath(md5path, path);
696  assert(found);
697  }
698  Unlock();
699 
700  if (found) {
701  atomic_inc64(&statistics_.num_hits_path);
702  } else {
703  atomic_inc64(&statistics_.num_misses_path);
704  }
705  return found;
706  }
707 
708  uint64_t FindInode(const PathString &path) {
709  Lock();
710  uint64_t inode = path_map_.LookupInodeByPath(path);
711  Unlock();
712  atomic_inc64(&statistics_.num_hits_inode);
713  return inode;
714  }
715 
716  bool FindDentry(uint64_t ino, uint64_t *parent_ino, NameString *name) {
717  PathString path;
718  InodeEx inodex(ino, InodeEx::kUnknownType);
719  shash::Md5 md5path;
720 
721  Lock();
722  bool found = inode_ex_map_.LookupMd5Path(&inodex, &md5path);
723  if (found) {
724  found = path_map_.LookupPath(md5path, &path);
725  assert(found);
726  *name = GetFileName(path);
727  path = GetParentPath(path);
728  *parent_ino = path_map_.LookupInodeByPath(path);
729  }
730  Unlock();
731  return found;
732  }
733 
738  bool ReplaceInode(uint64_t old_inode, const InodeEx &new_inode) {
739  shash::Md5 md5path;
740  InodeEx old_inode_ex(old_inode, InodeEx::kUnknownType);
741  Lock();
742  bool found = inode_ex_map_.LookupMd5Path(&old_inode_ex, &md5path);
743  if (found) {
744  inode_references_.Replace(old_inode, new_inode.GetInode());
745  path_map_.Replace(md5path, new_inode.GetInode());
746  inode_ex_map_.Erase(old_inode);
747  inode_ex_map_.Insert(new_inode, md5path);
748  }
749  Unlock();
750  return found;
751  }
752 
754  Lock();
757  }
758 
759  bool NextEntry(Cursor *cursor, uint64_t *inode_parent, NameString *name) {
760  shash::Md5 parent_md5;
761  StringRef name_ref;
762  bool result = path_map_.path_store()->Next(
763  &(cursor->csr_paths), &parent_md5, &name_ref);
764  if (!result)
765  return false;
766  if (parent_md5.IsNull())
767  *inode_parent = 0;
768  else
769  *inode_parent = path_map_.LookupInodeByMd5Path(parent_md5);
770  name->Assign(name_ref.data(), name_ref.length());
771  return true;
772  }
773 
774  bool NextInode(Cursor *cursor, uint64_t *inode) {
775  return inode_references_.Next(&(cursor->csr_inos), inode);
776  }
777 
778  void EndEnumerate(Cursor *cursor) {
779  Unlock();
780  }
781 
782  private:
783  static const unsigned kVersion = 4;
784 
785  void InitLock();
786  void CopyFrom(const InodeTracker &other);
787  inline void Lock() const {
788  int retval = pthread_mutex_lock(lock_);
789  assert(retval == 0);
790  }
791  inline void Unlock() const {
792  int retval = pthread_mutex_unlock(lock_);
793  assert(retval == 0);
794  }
795 
796  unsigned version_;
797  pthread_mutex_t *lock_;
802 }; // class InodeTracker
803 
804 
810  FRIEND_TEST(T_GlueBuffer, DentryTracker);
811 
812  private:
813  struct Entry {
814  Entry() : expiry(0), inode_parent(0) {}
815  Entry(uint64_t e, uint64_t p, const char *n)
816  : expiry(e)
817  , inode_parent(p)
818  , name(n, strlen(n))
819  {}
820  uint64_t expiry;
821  uint64_t inode_parent;
823  };
824 
825  public:
826  struct Cursor {
827  explicit Cursor(Entry *h) : head(h), pos(0) {}
829  size_t pos;
830  };
831 
832  // Cannot be moved to the statistics manager because it has to survive
833  // reloads. Added manually in the fuse module initialization and in talk.cc.
834  struct Statistics {
836  int64_t num_insert;
837  int64_t num_remove;
838  int64_t num_prune;
839  };
841 
842  static void *MainCleaner(void *data);
843 
844  DentryTracker();
845  DentryTracker(const DentryTracker &other);
846  DentryTracker &operator= (const DentryTracker &other);
847  ~DentryTracker();
848 
852  DentryTracker *Move();
853 
854  void Add(const uint64_t inode_parent, const char *name, uint64_t timeout_s) {
855  if (!is_active_) return;
856  if (timeout_s == 0) return;
857 
858  uint64_t now = platform_monotonic_time();
859  Lock();
860  entries_.PushBack(Entry(now + timeout_s, inode_parent, name));
862  DoPrune(now);
863  Unlock();
864  }
865 
866  void Prune();
871  void Disable() { is_active_ = false; }
872  bool is_active() const { return is_active_; }
873 
874  void SpawnCleaner(unsigned interval_s);
875 
876  Cursor BeginEnumerate();
877  bool NextEntry(Cursor *cursor, uint64_t *inode_parent, NameString *name);
878  void EndEnumerate(Cursor *cursor);
879 
880  private:
881  static const unsigned kVersion = 0;
882 
883  void CopyFrom(const DentryTracker &other);
884 
885  void InitLock();
886  inline void Lock() const {
887  int retval = pthread_mutex_lock(lock_);
888  assert(retval == 0);
889  }
890  inline void Unlock() const {
891  int retval = pthread_mutex_unlock(lock_);
892  assert(retval == 0);
893  }
894 
895  void DoPrune(uint64_t now) {
896  Entry *entry;
897  while (entries_.Peek(&entry)) {
898  if (entry->expiry >= now)
899  break;
900  entries_.PopFront();
902  }
904  }
905 
906  pthread_mutex_t *lock_;
907  unsigned version_;
911 
914  pthread_t thread_cleaner_;
915 }; // class DentryTracker
916 
922  private:
923  struct Entry {
924  Entry() : nopen(0), idx_stat(-1) {}
925  Entry(int32_t n, int32_t i, const shash::Any &h)
926  : nopen(n), idx_stat(i), hash(h) {}
932  int32_t nopen;
936  int32_t idx_stat;
942  };
943 
944  public:
950  static const unsigned int kBitDirectIo = 62;
951 
955  struct OpenDirectives {
968  bool direct_io;
969 
970  // Defaults to the old (pre v2.10) behavior: always flush the cache, never
971  // use direct I/O.
972  OpenDirectives() : keep_cache(false), direct_io(false) {}
973 
974  OpenDirectives(bool k, bool d) : keep_cache(k), direct_io(d) {}
975  };
976 
983  class EvictRaii {
984  public:
985  explicit EvictRaii(PageCacheTracker *t);
986  ~EvictRaii();
987  void Evict(uint64_t inode);
988 
989  private:
991  };
992 
993  // Cannot be moved to the statistics manager because it has to survive
994  // reloads. Added manually in the fuse module initialization and in talk.cc.
995  struct Statistics {
997  : n_insert(0)
998  , n_remove(0)
999  , n_open_direct(0)
1000  , n_open_flush(0)
1001  , n_open_cached(0)
1002  {}
1003  uint64_t n_insert;
1004  uint64_t n_remove;
1005  uint64_t n_open_direct;
1006  uint64_t n_open_flush;
1007  uint64_t n_open_cached;
1008  };
1010 
1011  PageCacheTracker();
1012  explicit PageCacheTracker(const PageCacheTracker &other);
1015 
1016  OpenDirectives Open(uint64_t inode, const shash::Any &hash,
1017  const struct stat &info);
1022  OpenDirectives OpenDirect();
1023  void Close(uint64_t inode);
1024 
1025  bool GetInfoIfOpen(uint64_t inode, shash::Any *hash, struct stat *info)
1026  {
1027  MutexLockGuard guard(lock_);
1028  Entry entry;
1029  bool retval = map_.Lookup(inode, &entry);
1030  if (retval && (entry.nopen != 0)) {
1031  assert(entry.idx_stat >= 0);
1032  *hash = entry.hash;
1033  if (info != NULL)
1034  *info = stat_store_.Get(entry.idx_stat);
1035  return true;
1036  }
1037  return false;
1038  }
1039 
1040  EvictRaii GetEvictRaii() { return EvictRaii(this); }
1041 
1042  // Used in RestoreState to prevent using the page cache tracker from a
1043  // previous version after hotpatch
1044  void Disable() { is_active_ = false; }
1045 
1046  private:
1047  static const unsigned kVersion = 0;
1048 
1049  void InitLock();
1050  void CopyFrom(const PageCacheTracker &other);
1051 
1052  pthread_mutex_t *lock_;
1053  unsigned version_;
1063 };
1064 
1065 
1066 } // namespace glue
1067 
1068 #endif // CVMFS_GLUE_BUFFER_H_
bool GetInfoIfOpen(uint64_t inode, shash::Any *hash, struct stat *info)
Definition: glue_buffer.h:1025
BigVector< void * > bins_
Definition: glue_buffer.h:227
VfsPutRaii GetVfsPutRaii()
Definition: glue_buffer.h:688
uint64_t inode_parent
Definition: glue_buffer.h:821
InodeReferences inode_references_
Definition: glue_buffer.h:800
bool IsNull() const
Definition: hash.h:383
InodeReferences::Cursor csr_inos
Definition: glue_buffer.h:600
void Lock() const
Definition: glue_buffer.h:787
void Unlock() const
Definition: glue_buffer.h:791
int64_t atomic_int64
Definition: atomic.h:18
static uint32_t hasher_md5(const shash::Md5 &key)
Definition: glue_buffer.h:94
Cursor(const PathStore::Cursor &p, const InodeReferences::Cursor &i)
Definition: glue_buffer.h:593
Item At(const size_t index) const
Definition: bigvector.h:50
bool ReplaceInode(uint64_t old_inode, const InodeEx &new_inode)
Definition: glue_buffer.h:738
struct stat Get(int32_t index) const
Definition: glue_buffer.h:400
FRIEND_TEST(T_GlueBuffer, DentryTracker)
Statistics GetStatistics()
Definition: glue_buffer.h:663
NameString GetFileName(const PathString &path)
Definition: shortstring.cc:29
pthread_mutex_t * lock_
Definition: glue_buffer.h:1052
void DoPrune(uint64_t now)
Definition: glue_buffer.h:895
NameString name
Definition: glue_buffer.h:822
PageCacheTracker & operator=(const PageCacheTracker &other)
Definition: glue_buffer.cc:287
uint64_t GetInode() const
Definition: glue_buffer.h:73
Definition: glue_buffer.h:923
InodeEx(uint64_t inode, unsigned mode)
Definition: glue_buffer.h:69
Definition: glue_buffer.h:813
void Assign(const char *chars, const unsigned length)
Definition: shortstring.h:61
Cursor BeginEnumerate()
Definition: glue_buffer.h:753
double GetUsage() const
Definition: glue_buffer.h:197
PathStore::Cursor csr_paths
Definition: glue_buffer.h:599
void CopyFrom(const DentryTracker &other)
Definition: glue_buffer.cc:150
bool FindDentry(uint64_t ino, uint64_t *parent_ino, NameString *name)
Definition: glue_buffer.h:716
PathStore path_store_
Definition: glue_buffer.h:467
bool Put(const uint64_t inode, const uint32_t by)
Definition: glue_buffer.h:530
static uint16_t size(const uint16_t length)
Definition: glue_buffer.h:122
pthread_t thread_cleaner_
Definition: glue_buffer.h:914
void Unlock() const
Definition: glue_buffer.h:890
void Insert(const InodeEx inode_ex, const shash::Md5 &md5path)
Definition: glue_buffer.h:489
assert((mem||(size==0))&&"Out Of Memory")
bool LookupMd5Path(InodeEx *inode_ex, shash::Md5 *md5path)
Definition: glue_buffer.h:484
SmallHashDynamic< uint64_t, uint32_t > map_
Definition: glue_buffer.h:577
BigVector< struct stat > store_
Definition: glue_buffer.h:403
bool NextEntry(Cursor *cursor, uint64_t *inode_parent, NameString *name)
Definition: glue_buffer.cc:246
StringHeap * string_heap_
Definition: glue_buffer.h:367
void EndEnumerate(Cursor *cursor)
Definition: glue_buffer.h:778
bool VfsPut(const uint64_t inode, const uint32_t by)
Definition: glue_buffer.h:616
uint64_t bin_used_
Definition: glue_buffer.h:226
char * data() const
Definition: glue_buffer.h:125
uint64_t LookupInodeByMd5Path(const shash::Md5 &md5path)
Definition: glue_buffer.h:429
unsigned char digest[digest_size_]
Definition: hash.h:124
PathStore * path_store()
Definition: glue_buffer.h:463
void Lock() const
Definition: glue_buffer.h:886
uint16_t * length_
Definition: glue_buffer.h:137
uint64_t LookupInodeByPath(const PathString &path)
Definition: glue_buffer.h:421
bool operator==(const InodeEx &other) const
Definition: glue_buffer.h:78
int32_t nopen
Definition: glue_buffer.h:932
static uint32_t hasher_inode_ex(const InodeEx &inode_ex)
Definition: glue_buffer.h:103
void Insert(const shash::Md5 &md5path, const PathString &path)
Definition: glue_buffer.h:257
uint64_t inode_ex_
Definition: glue_buffer.h:91
shash::Md5 Insert(const PathString &path, const uint64_t inode)
Definition: glue_buffer.h:436
static uint32_t hasher_inode(const uint64_t &inode)
Definition: glue_buffer.h:99
bool Next(Cursor *cursor, shash::Md5 *parent, StringRef *name)
Definition: glue_buffer.h:339
uint64_t GetSizeAlloc() const
Definition: glue_buffer.h:205
void EndEnumerate(Cursor *cursor)
Definition: glue_buffer.cc:261
bool is_active() const
Definition: glue_buffer.h:872
SmallHashDynamic< InodeEx, shash::Md5 > map_
Definition: glue_buffer.h:500
uint16_t size() const
Definition: glue_buffer.h:121
void CopyFrom(const InodeTracker &other)
Definition: glue_buffer.cc:73
uint64_t FindInode(const PathString &path)
Definition: glue_buffer.h:708
InodeTracker & operator=(const InodeTracker &other)
Definition: glue_buffer.cc:95
uint32_t capacity() const
Definition: smallhash.h:301
Statistics GetStatistics()
Definition: glue_buffer.h:1009
uint64_t bin_size_
Definition: glue_buffer.h:225
Statistics GetStatistics()
Definition: glue_buffer.h:840
void Add(const uint64_t inode_parent, const char *name, uint64_t timeout_s)
Definition: glue_buffer.h:854
void Replace(const uint64_t old_inode, const uint64_t new_inode)
Definition: glue_buffer.h:549
bool NextEntry(Cursor *cursor, uint64_t *inode_parent, NameString *name)
Definition: glue_buffer.h:759
void SetSize(const size_t new_size)
Definition: bigvector.h:116
StringHeap(const uint64_t minimum_size)
Definition: glue_buffer.h:155
InodeEx(uint64_t inode, EFileType type)
Definition: glue_buffer.h:66
Statistics statistics_
Definition: glue_buffer.h:801
bool NextInode(Cursor *cursor, uint64_t *inode)
Definition: glue_buffer.h:774
static StringRef Place(const uint16_t length, const char *str, void *addr)
Definition: glue_buffer.h:126
void SpawnCleaner(unsigned interval_s)
Definition: glue_buffer.cc:170
uint16_t length() const
Definition: glue_buffer.h:120
int32_t idx_stat
Definition: glue_buffer.h:936
bool Lookup(const shash::Md5 &md5path, PathString *path)
Definition: glue_buffer.h:284
void Insert(const Key &key, const Value &value)
Definition: smallhash.h:109
int32_t Add(const struct stat &info)
Definition: glue_buffer.h:383
Key * keys() const
Definition: smallhash.h:154
void ShrinkIfOversized()
Definition: bigvector.h:99
DentryTracker * Move()
Definition: glue_buffer.cc:160
Entry(uint64_t e, uint64_t p, const char *n)
Definition: glue_buffer.h:815
bool Next(Cursor *cursor, uint64_t *inode)
Definition: glue_buffer.h:562
static const unsigned kVersion
Definition: glue_buffer.h:1047
void Append(const char *chars, const unsigned length)
Definition: shortstring.h:80
string StringifyInt(const int64_t value)
Definition: string.cc:78
void VfsGetBy(const InodeEx inode_ex, const uint32_t by, const PathString &path)
Definition: glue_buffer.h:670
pthread_mutex_t * lock_
Definition: glue_buffer.h:797
void Erase(const uint64_t inode)
Definition: glue_buffer.h:493
uint64_t platform_monotonic_time()
Entry(int32_t n, int32_t i, const shash::Any &h)
Definition: glue_buffer.h:925
static const unsigned kVersion
Definition: glue_buffer.h:783
InodeExMap inode_ex_map_
Definition: glue_buffer.h:799
SmallHashDynamic< shash::Md5, PathInfo > map_
Definition: glue_buffer.h:366
uint64_t used() const
Definition: glue_buffer.h:202
EFileType GetFileType() const
Definition: glue_buffer.h:74
SmallHashDynamic< shash::Md5, uint64_t > map_
Definition: glue_buffer.h:466
Entry()
Definition: glue_buffer.h:814
bool Contains(const Key &key) const
Definition: smallhash.h:102
PathStore & operator=(const PathStore &other)
Definition: glue_buffer.cc:32
OpenDirectives Open(uint64_t inode, const shash::Any &hash, const struct stat &info)
Definition: glue_buffer.cc:317
void PushBack(const Item &item)
Definition: bigvector.h:60
bool IsEmpty() const
Definition: shortstring.h:137
void Clear()
Definition: smallhash.h:134
uint64_t expiry
Definition: glue_buffer.h:820
bool IsCompatibleFileType(unsigned mode) const
Definition: glue_buffer.h:85
void Close(uint64_t inode)
Definition: glue_buffer.cc:399
OpenDirectives OpenDirect()
Definition: glue_buffer.cc:388
EvictRaii(PageCacheTracker *t)
Definition: glue_buffer.cc:439
void RemoveString(const StringRef str_ref)
Definition: glue_buffer.h:193
Definition: mutex.h:42
Entry()
Definition: glue_buffer.h:924
void Replace(size_t index, const Item &item)
Definition: bigvector.h:67
void Erase(const shash::Md5 &md5path)
Definition: glue_buffer.h:445
PathString GetParentPath(const PathString &path)
Definition: shortstring.cc:15
void CopyFrom(const PathStore &other)
Definition: glue_buffer.cc:47
uint64_t Erase(int32_t index)
Definition: glue_buffer.h:392
EvictRaii GetEvictRaii()
Definition: glue_buffer.h:1040
bool Erase(const Key &key)
Definition: smallhash.h:115
static uint64_t ShiftMode(unsigned mode)
Definition: glue_buffer.h:51
bool LookupPath(const shash::Md5 &md5path, PathString *path)
Definition: glue_buffer.h:416
DentryTracker & operator=(const DentryTracker &other)
Definition: glue_buffer.cc:139
void CopyFrom(const PageCacheTracker &other)
Definition: glue_buffer.cc:297
void Erase(const shash::Md5 &md5path)
Definition: glue_buffer.h:300
BigQueue< Entry > entries_
Definition: glue_buffer.h:910
unsigned GetLength() const
Definition: shortstring.h:131
bool Lookup(const Key &key, Value *value) const
Definition: smallhash.h:73
static void * MainCleaner(void *data)
Definition: glue_buffer.cc:180
static const unsigned kVersion
Definition: glue_buffer.h:881
void Init(uint32_t expected_size, Key empty, uint32_t(*hasher)(const Key &key))
Definition: smallhash.h:60
void Replace(const shash::Md5 &md5path, uint64_t new_inode)
Definition: glue_buffer.h:453
static const unsigned int kBitDirectIo
Definition: glue_buffer.h:950
const char * GetChars() const
Definition: shortstring.h:123
void Init(const uint64_t minimum_size)
Definition: glue_buffer.h:159
void AddBin(const uint64_t size)
Definition: glue_buffer.h:216
bool Get(const uint64_t inode, const uint32_t by)
Definition: glue_buffer.h:521
StringRef AddString(const uint16_t length, const char *str)
Definition: glue_buffer.h:176
static void size_t size
Definition: smalloc.h:54
Key empty_key() const
Definition: smallhash.h:153
pthread_mutex_t * lock_
Definition: glue_buffer.h:906
SmallHashDynamic< uint64_t, Entry > map_
Definition: glue_buffer.h:1061
void VfsGet(const InodeEx inode_ex, const PathString &path)
Definition: glue_buffer.h:684
shash::Any hash
Definition: glue_buffer.h:941
bool FindPath(InodeEx *inode_ex, PathString *path)
Definition: glue_buffer.h:690
Cursor BeginEnumerate()
Definition: glue_buffer.h:335
uint32_t MurmurHash2(const void *key, int len, uint32_t seed)
Definition: murmur.hxx:23
bool operator!=(const InodeEx &other) const
Definition: glue_buffer.h:81
size_t size() const
Definition: bigvector.h:121
Statistics statistics_
Definition: glue_buffer.h:908