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