CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
catalog_mgr_impl.h
Go to the documentation of this file.
1 
5 #ifndef CVMFS_CATALOG_MGR_IMPL_H_
6 #define CVMFS_CATALOG_MGR_IMPL_H_
7 
8 #ifndef __STDC_FORMAT_MACROS
9 #define __STDC_FORMAT_MACROS
10 #endif
11 
12 #include "cvmfs_config.h"
13 
14 #include <cassert>
15 #include <string>
16 #include <vector>
17 
18 #include "shortstring.h"
19 #include "statistics.h"
20 #include "util/logging.h"
21 #include "xattr.h"
22 
23 using namespace std; // NOLINT
24 
25 namespace catalog {
26 
27 template <class CatalogT>
29  perf::Statistics *statistics) :
30  statistics_(statistics) {
33  revision_cache_ = 0;
34  timestamp_cache_ = 0;
36  volatile_flag_ = false;
37  has_authz_cache_ = false;
38  inode_annotation_ = NULL;
39  incarnation_ = 0;
40  rwlock_ =
41  reinterpret_cast<pthread_rwlock_t *>(smalloc(sizeof(pthread_rwlock_t)));
42  int retval = pthread_rwlock_init(rwlock_, NULL);
43  assert(retval == 0);
44  retval = pthread_key_create(&pkey_sqlitemem_, NULL);
45  assert(retval == 0);
46 }
47 
48 template <class CatalogT>
50  DetachAll();
51  pthread_key_delete(pkey_sqlitemem_);
52  pthread_rwlock_destroy(rwlock_);
53  free(rwlock_);
54 }
55 
56 template <class CatalogT>
58  InodeAnnotation *new_annotation)
59 {
60  assert(catalogs_.empty() || (new_annotation == inode_annotation_));
61  inode_annotation_ = new_annotation;
62 }
63 
64 template <class CatalogT>
66  const OwnerMap &gid_map)
67 {
68  uid_map_ = uid_map;
69  gid_map_ = gid_map;
70 }
71 
72 template <class CatalogT>
74  catalog_watermark_ = limit;
75 }
76 
77 template <class CatalogT>
79  if (inode_watermark_status_ > 0)
80  return;
81 
82  uint64_t highest_inode = inode_gauge_;
83  if (inode_annotation_)
84  highest_inode += inode_annotation_->GetGeneration();
85  uint64_t uint32_border = 1;
86  uint32_border = uint32_border << 32;
87  if (highest_inode >= uint32_border) {
88  LogCvmfs(kLogCatalog, kLogDebug | kLogSyslogWarn, "inodes exceed 32bit");
89  inode_watermark_status_++;
90  }
91 }
92 
93 
98 template <class CatalogT>
100  LogCvmfs(kLogCatalog, kLogDebug, "Initialize catalog");
101  WriteLock();
102  bool attached = MountCatalog(PathString("", 0), shash::Any(), NULL);
103  Unlock();
104 
105  if (!attached) {
106  LogCvmfs(kLogCatalog, kLogDebug, "failed to initialize root catalog");
107  }
108 
109  return attached;
110 }
111 
112 
118 template <class CatalogT>
121  "dryrun remounting repositories");
122  CatalogContext ctlg_context;
123  return GetNewRootCatalogContext(&ctlg_context);
124 }
125 
126 template <class CatalogT>
128  LogCvmfs(kLogCatalog, kLogDebug, "remounting repositories");
129  CatalogContext ctlg_context;
130 
131  if (GetNewRootCatalogContext(&ctlg_context) != kLoadNew
132  && GetNewRootCatalogContext(&ctlg_context) != kLoadUp2Date) {
133  LogCvmfs(kLogCatalog, kLogDebug, "remounting repositories: "
134  "Did not find any valid root catalog to mount");
135  return kLoadFail;
136  }
137 
138  WriteLock();
139 
140  const LoadReturn load_error = LoadCatalogByHash(&ctlg_context);
141 
142  if (load_error == kLoadNew) {
143  inode_t old_inode_gauge = inode_gauge_;
144  DetachAll();
146 
147  CatalogT *new_root = CreateCatalog(ctlg_context.mountpoint(),
148  ctlg_context.hash(), NULL);
149  assert(new_root);
150  bool retval = AttachCatalog(ctlg_context.sqlite_path(), new_root);
151  assert(retval);
152 
153  if (inode_annotation_) {
154  inode_annotation_->IncGeneration(old_inode_gauge);
155  }
156  }
157  CheckInodeWatermark();
158  Unlock();
159 
160  return load_error;
161 }
162 
166 template <class CatalogT>
168  const shash::Any &root_hash)
169 {
170  assert(!root_hash.IsNull());
172  "switching to root hash %s", root_hash.ToString().c_str());
173 
174  WriteLock();
175 
176  CatalogContext ctlg_context(root_hash, PathString("", 0),
178  // we do not need to set revision as LoadCatalogByHash
179  // needs only mountpoint, hash
180 
181  const LoadReturn load_error = LoadCatalogByHash(&ctlg_context);
182 
183  if (load_error == kLoadNew) {
184  inode_t old_inode_gauge = inode_gauge_;
185  DetachAll();
187 
188  CatalogT *new_root =
189  CreateCatalog(PathString("", 0), ctlg_context.hash(), NULL);
190  assert(new_root);
191  bool retval = AttachCatalog(ctlg_context.sqlite_path(), new_root);
192  assert(retval);
193 
194  if (inode_annotation_) {
195  inode_annotation_->IncGeneration(old_inode_gauge);
196  }
197  }
198  CheckInodeWatermark();
199  Unlock();
200 
201  return load_error;
202 }
203 
204 
208 template <class CatalogT>
210  WriteLock();
211  if (catalogs_.empty()) {
212  Unlock();
213  return;
214  }
215 
216  typename CatalogList::const_iterator i;
217  typename CatalogList::const_iterator iend;
218  CatalogList catalogs_to_detach = GetRootCatalog()->GetChildren();
219  for (i = catalogs_to_detach.begin(), iend = catalogs_to_detach.end();
220  i != iend; ++i)
221  {
222  DetachSubtree(*i);
223  }
224 
225  Unlock();
226 }
227 
228 
232 template <class CatalogT>
234  const PathString &mountpoint)
235 {
236  assert(!mountpoint.IsEmpty());
237  CatalogT *catalog = FindCatalog(mountpoint);
238  assert(catalog != NULL);
239  if (catalog->mountpoint() == mountpoint) {
240  catalog = catalog->parent();
241  assert(catalog != NULL);
242  }
243  shash::Any result;
244  uint64_t size;
245  catalog->FindNested(mountpoint, &result, &size);
246  return result;
247 }
248 
249 
259 template <class CatalogT>
261  const LookupOptions options,
262  DirectoryEntry *dirent)
263 {
264  // initialize as non-negative
265  assert(dirent);
266  *dirent = DirectoryEntry();
267 
268  // create a dummy negative directory entry
269  const DirectoryEntry dirent_negative =
271 
272  EnforceSqliteMemLimit();
273  ReadLock();
274 
275  CatalogT *best_fit = FindCatalog(path);
276  assert(best_fit != NULL);
277 
278  perf::Inc(statistics_.n_lookup_path);
279  LogCvmfs(kLogCatalog, kLogDebug, "looking up '%s' in catalog: '%s'",
280  path.c_str(), best_fit->mountpoint().c_str());
281  bool found = best_fit->LookupPath(path, dirent);
282 
283  // Possibly in a nested catalog
284  if (!found && MountSubtree(path, best_fit, false /* is_listable */, NULL)) {
285  LogCvmfs(kLogCatalog, kLogDebug, "looking up '%s' in a nested catalog",
286  path.c_str());
287  StageNestedCatalogAndUnlock(path, best_fit, false /* is_listable */);
288  WriteLock();
289  // Check again to avoid race
290  best_fit = FindCatalog(path);
291  assert(best_fit != NULL);
292  perf::Inc(statistics_.n_lookup_path);
293  found = best_fit->LookupPath(path, dirent);
294 
295  if (!found) {
297  "entry not found, we may have to load nested catalogs");
298 
299  CatalogT *nested_catalog;
300  found =
301  MountSubtree(path, best_fit, false /* is_listable */, &nested_catalog);
302 
303  if (!found) {
305  "failed to load nested catalog for '%s'", path.c_str());
306  goto lookup_path_notfound;
307  }
308 
309  if (nested_catalog != best_fit) {
310  perf::Inc(statistics_.n_lookup_path);
311  found = nested_catalog->LookupPath(path, dirent);
312  if (!found) {
314  "nested catalogs loaded but entry '%s' was still not found",
315  path.c_str());
316  if (dirent != NULL) *dirent = dirent_negative;
317  goto lookup_path_notfound;
318  } else {
319  best_fit = nested_catalog;
320  }
321  } else {
322  LogCvmfs(kLogCatalog, kLogDebug, "no nested catalog fits");
323  if (dirent != NULL) *dirent = dirent_negative;
324  goto lookup_path_notfound;
325  }
326  }
327  assert(found);
328  }
329  // Not in a nested catalog (because no nested cataog fits), ENOENT
330  if (!found) {
331  LogCvmfs(kLogCatalog, kLogDebug, "ENOENT: '%s'", path.c_str());
332  if (dirent != NULL) *dirent = dirent_negative;
333  goto lookup_path_notfound;
334  }
335 
336  LogCvmfs(kLogCatalog, kLogDebug, "found entry '%s' in catalog '%s'",
337  path.c_str(), best_fit->mountpoint().c_str());
338 
339  if ((options & kLookupRawSymlink) == kLookupRawSymlink) {
340  LinkString raw_symlink;
341  bool retval = best_fit->LookupRawSymlink(path, &raw_symlink);
342  assert(retval); // Must be true, we have just found the entry
343  dirent->set_symlink(raw_symlink);
344  }
345 
346  Unlock();
347  return true;
348 
349  lookup_path_notfound:
350  Unlock();
351  // Includes both: ENOENT and not found due to I/O error
352  perf::Inc(statistics_.n_lookup_path_negative);
353  return false;
354 }
355 
356 
369 template <class CatalogT>
371  const PathString &path,
372  PathString *mountpoint,
373  shash::Any *hash,
374  uint64_t *size
375 ) {
376  EnforceSqliteMemLimit();
377  bool result = false;
378  ReadLock();
379 
380  // Look past current path to mount up to intended location
381  PathString catalog_path(path);
382  catalog_path.Append("/.cvmfscatalog", 14);
383 
384  // Find catalog, possibly load nested
385  CatalogT *best_fit = FindCatalog(catalog_path);
386  CatalogT *catalog = best_fit;
387  if (MountSubtree(catalog_path, best_fit, false /* is_listable */, NULL)) {
388  StageNestedCatalogAndUnlock(path, best_fit, false);
389  WriteLock();
390  // Check again to avoid race
391  best_fit = FindCatalog(catalog_path);
392  result =
393  MountSubtree(catalog_path, best_fit, false /* is_listable */, &catalog);
394  // Result is false if an available catalog failed to load (error happened)
395  if (!result) {
396  Unlock();
397  return false;
398  }
399  }
400 
401  // If the found catalog is the Root there is no parent to lookup
402  if (catalog->HasParent()) {
403  result = catalog->parent()->FindNested(catalog->root_prefix(), hash, size);
404  }
405 
406  // Mountpoint now points to the found catalog
407  mountpoint->Assign(catalog->root_prefix());
408 
409  // If the result is false, it means that no nested catalog was found for
410  // this path. As the root catalog does not have a Nested Catalog of
411  // itself, we manually set the values and leave the size as 0.
412  // TODO(nhazekam) Allow for Root Catalog to be returned
413  if (!result) {
414  *hash = GetRootCatalog()->hash();
415  *size = 0;
416  result = true;
417  }
418 
419  Unlock();
420  return result;
421 }
422 
423 
433 template <class CatalogT>
435  const PathString &path,
436  std::vector<PathString> *result_list
437 ) {
438  EnforceSqliteMemLimit();
439  bool result;
440  ReadLock();
441 
442  // Look past current path to mount up to intended location
443  PathString test(path);
444  test.Append("/.cvmfscatalog", 14);
445 
446  // Find catalog, possibly load nested
447  CatalogT *best_fit = FindCatalog(test);
448  CatalogT *catalog = best_fit;
449  // True if there is an available nested catalog
450  if (MountSubtree(test, best_fit, false /* is_listable */, NULL)) {
451  StageNestedCatalogAndUnlock(path, best_fit, false);
452  WriteLock();
453  // Check again to avoid race
454  best_fit = FindCatalog(test);
455  result = MountSubtree(test, best_fit, false /* is_listable */, &catalog);
456  // result is false if an available catalog failed to load
457  if (!result) {
458  Unlock();
459  return false;
460  }
461  }
462 
463  // Build listing
464  CatalogT *cur_parent = catalog->parent();
465  if (cur_parent) {
466  // Walk up parent tree to find base
467  std::vector<catalog::Catalog*> parents;
468  while (cur_parent->HasParent()) {
469  parents.push_back(cur_parent);
470  cur_parent = cur_parent->parent();
471  }
472  parents.push_back(cur_parent);
473  while (!parents.empty()) {
474  // Add to list in order starting at root
475  result_list->push_back(parents.back()->root_prefix());
476  parents.pop_back();
477  }
478  }
479  // Add the current catalog
480  result_list->push_back(catalog->root_prefix());
481 
482  Catalog::NestedCatalogList children = catalog->ListOwnNestedCatalogs();
483 
484  // Add all children nested catalogs
485  for (unsigned i = 0; i < children.size(); i++) {
486  result_list->push_back(children.at(i).mountpoint);
487  }
488 
489  Unlock();
490  return true;
491 }
492 
493 
494 template <class CatalogT>
496  const PathString &path,
497  XattrList *xattrs)
498 {
499  EnforceSqliteMemLimit();
500  bool result;
501  ReadLock();
502 
503  // Find catalog, possibly load nested
504  CatalogT *best_fit = FindCatalog(path);
505  CatalogT *catalog = best_fit;
506  if (MountSubtree(path, best_fit, false /* is_listable */, NULL)) {
507  StageNestedCatalogAndUnlock(path, best_fit, false);
508  WriteLock();
509  // Check again to avoid race
510  best_fit = FindCatalog(path);
511  result = MountSubtree(path, best_fit, false /* is_listable */, &catalog);
512  if (!result) {
513  Unlock();
514  return false;
515  }
516  }
517 
518  perf::Inc(statistics_.n_lookup_xattrs);
519  result = catalog->LookupXattrsPath(path, xattrs);
520 
521  Unlock();
522  return result;
523 }
524 
525 
532 template <class CatalogT>
534  DirectoryEntryList *listing,
535  const bool expand_symlink)
536 {
537  EnforceSqliteMemLimit();
538  bool result;
539  ReadLock();
540 
541  // Find catalog, possibly load nested
542  CatalogT *best_fit = FindCatalog(path);
543  CatalogT *catalog = best_fit;
544  if (MountSubtree(path, best_fit, true /* is_listable */, NULL)) {
545  StageNestedCatalogAndUnlock(path, best_fit, true /* is_listable */);
546  WriteLock();
547  // Check again to avoid race
548  best_fit = FindCatalog(path);
549  result = MountSubtree(path, best_fit, true /* is_listable */, &catalog);
550  if (!result) {
551  Unlock();
552  return false;
553  }
554  }
555 
556  perf::Inc(statistics_.n_listing);
557  result = catalog->ListingPath(path, listing, expand_symlink);
558 
559  Unlock();
560  return result;
561 }
562 
563 
570 template <class CatalogT>
572  StatEntryList *listing)
573 {
574  EnforceSqliteMemLimit();
575  bool result;
576  ReadLock();
577 
578  // Find catalog, possibly load nested
579  CatalogT *best_fit = FindCatalog(path);
580  CatalogT *catalog = best_fit;
581  if (MountSubtree(path, best_fit, true /* is_listable */, NULL)) {
582  StageNestedCatalogAndUnlock(path, best_fit, true /* is_listable */);
583  WriteLock();
584  // Check again to avoid race
585  best_fit = FindCatalog(path);
586  result = MountSubtree(path, best_fit, true /* is_listable */, &catalog);
587  if (!result) {
588  Unlock();
589  return false;
590  }
591  }
592 
593  perf::Inc(statistics_.n_listing);
594  result = catalog->ListingPathStat(path, listing);
595 
596  Unlock();
597  return result;
598 }
599 
600 
608 template <class CatalogT>
610  const PathString &path,
611  const shash::Algorithms interpret_hashes_as,
612  FileChunkList *chunks)
613 {
614  EnforceSqliteMemLimit();
615  bool result;
616  ReadLock();
617 
618  // Find catalog, possibly load nested
619  CatalogT *best_fit = FindCatalog(path);
620  CatalogT *catalog = best_fit;
621  if (MountSubtree(path, best_fit, false /* is_listable */, NULL)) {
622  StageNestedCatalogAndUnlock(path, best_fit, false);
623  WriteLock();
624  // Check again to avoid race
625  best_fit = FindCatalog(path);
626  result = MountSubtree(path, best_fit, false /* is_listable */, &catalog);
627  if (!result) {
628  Unlock();
629  return false;
630  }
631  }
632 
633  result = catalog->ListPathChunks(path, interpret_hashes_as, chunks);
634 
635  Unlock();
636  return result;
637 }
638 
639 template <class CatalogT>
641  const PathString &path,
642  std::string *subcatalog_path,
643  shash::Any *hash
644  )
645 {
646  EnforceSqliteMemLimit();
647  bool result;
648  ReadLock();
649 
650  // Look past current path to mount up to intended location
651  PathString catalog_path(path);
652  catalog_path.Append("/.cvmfscatalog", 14);
653 
654  // Find catalog, possibly load nested
655  CatalogT *best_fit = FindCatalog(catalog_path);
656  CatalogT *catalog = best_fit;
657  if (MountSubtree(catalog_path, best_fit, false /* is_listable */, NULL)) {
658  StageNestedCatalogAndUnlock(path, best_fit, false /* is_listable */);
659  WriteLock();
660  // Check again to avoid race
661  best_fit = FindCatalog(catalog_path);
662  result =
663  MountSubtree(catalog_path, best_fit, false /* is_listable */, &catalog);
664  // Result is false if an available catalog failed to load (error happened)
665  if (!result) {
666  Unlock();
667  *subcatalog_path = "error: failed to load catalog!";
668  *hash = shash::Any();
669  return catalog::Counters();
670  }
671  }
672 
673  *hash = catalog->hash();
674  *subcatalog_path = catalog->mountpoint().ToString();
675  catalog::Counters counters = catalog->GetCounters();
676  Unlock();
677  return counters;
678 }
679 
680 
681 template <class CatalogT>
683  ReadLock();
684  const uint64_t revision = GetRevisionNoLock();
685  Unlock();
686 
687  return revision;
688 }
689 
695 template <class CatalogT>
697  return revision_cache_;
698 }
699 
700 template <class CatalogT>
702  ReadLock();
703  const uint64_t timestamp = GetTimestampNoLock();
704  Unlock();
705 
706  return timestamp;
707 }
708 
714 template <class CatalogT>
716  return timestamp_cache_;
717 }
718 
719 template <class CatalogT>
720 bool AbstractCatalogManager<CatalogT>::GetVOMSAuthz(std::string *authz) const {
721  ReadLock();
722  const bool has_authz = has_authz_cache_;
723  if (has_authz && authz)
724  *authz = authz_cache_;
725  Unlock();
726  return has_authz;
727 }
728 
729 
730 template <class CatalogT>
732  ReadLock();
733  const bool result = GetRootCatalog()->HasExplicitTTL();
734  Unlock();
735  return result;
736 }
737 
738 
739 template <class CatalogT>
741  ReadLock();
742  const uint64_t ttl = GetRootCatalog()->GetTTL();
743  Unlock();
744  return ttl;
745 }
746 
747 
748 template <class CatalogT>
750  ReadLock();
751  int result = catalogs_.size();
752  Unlock();
753  return result;
754 }
755 
756 
760 template <class CatalogT>
762  ReadLock();
763  string output = PrintHierarchyRecursively(GetRootCatalog(), 0);
764  Unlock();
765  return output;
766 }
767 
768 
772 template <class CatalogT>
774  InodeRange result;
775  result.offset = inode_gauge_;
776  result.size = size;
777 
778  inode_gauge_ += size;
779  LogCvmfs(kLogCatalog, kLogDebug, "allocating inodes from %lu to %lu.",
780  result.offset + 1, inode_gauge_);
781 
782  return result;
783 }
784 
785 
791 template <class CatalogT>
793  // TODO(jblomer) currently inodes are only released on remount
794 }
795 
796 
803 template <class CatalogT>
805  const PathString &path) const {
806  assert(catalogs_.size() > 0);
807 
808  // Start at the root catalog and successively go down the catalog tree
809  CatalogT *best_fit = GetRootCatalog();
810  CatalogT *next_fit = NULL;
811  while (best_fit->mountpoint() != path) {
812  next_fit = best_fit->FindSubtree(path);
813  if (next_fit == NULL)
814  break;
815  best_fit = next_fit;
816  }
817 
818  return best_fit;
819 }
820 
821 
828 template <class CatalogT>
830  CatalogT **attached_catalog) const
831 {
832  if (catalogs_.size() == 0)
833  return false;
834 
835  CatalogT *best_fit = FindCatalog(root_path);
836  if (best_fit->mountpoint() != root_path)
837  return false;
838 
839  if (attached_catalog != NULL) *attached_catalog = best_fit;
840  return true;
841 }
842 
843 
844 template <class CatalogT>
846  const PathString &path,
847  const CatalogT *parent,
848  bool is_listable)
849 {
850  assert(parent);
851  const unsigned path_len = path.GetLength();
852 
853  perf::Inc(statistics_.n_nested_listing);
854  typedef typename CatalogT::NestedCatalogList NestedCatalogList;
855  const NestedCatalogList& nested_catalogs = parent->ListNestedCatalogs();
856 
857  for (typename NestedCatalogList::const_iterator i = nested_catalogs.begin(),
858  iEnd = nested_catalogs.end(); i != iEnd; ++i)
859  {
860  if (!path.StartsWith(i->mountpoint))
861  continue;
862 
863  // in this case the path doesn't start with
864  // the mountpoint in a file path sense
865  // (e.g. path is /a/bc and mountpoint is /a/b), and will be ignored
866  const unsigned mountpoint_len = i->mountpoint.GetLength();
867  if (path_len > mountpoint_len && path.GetChars()[mountpoint_len] != '/')
868  continue;
869 
870  // Found a nested catalog transition point
871  if (!is_listable && (path_len == mountpoint_len))
872  break;
873 
874  Unlock();
875  LogCvmfs(kLogCatalog, kLogDebug, "staging nested catalog at %s (%s)",
876  i->mountpoint.c_str(), i->hash.ToString().c_str());
877  StageNestedCatalogByHash(i->hash, i->mountpoint);
878  return;
879  }
880  Unlock();
881 }
882 
892 template <class CatalogT>
894  const PathString &path,
895  const CatalogT *entry_point,
896  bool is_listable,
897  CatalogT **leaf_catalog)
898 {
899  bool result = true;
900  CatalogT *parent = (entry_point == NULL) ?
901  GetRootCatalog() : const_cast<CatalogT *>(entry_point);
902  assert(path.StartsWith(parent->mountpoint()));
903 
904  unsigned path_len = path.GetLength();
905 
906  // Try to find path as a super string of nested catalog mount points
907  perf::Inc(statistics_.n_nested_listing);
908  typedef typename CatalogT::NestedCatalogList NestedCatalogList;
909  const NestedCatalogList& nested_catalogs =
910  parent->ListNestedCatalogs();
911  for (typename NestedCatalogList::const_iterator i = nested_catalogs.begin(),
912  iEnd = nested_catalogs.end(); i != iEnd; ++i)
913  {
914  // Next nesting level
915  if (path.StartsWith(i->mountpoint)) {
916  // in this case the path doesn't start with
917  // the mountpoint in a file path sense
918  // (e.g. path is /a/bc and mountpoint is /a/b), and will be ignored
919  unsigned mountpoint_len = i->mountpoint.GetLength();
920  if (path_len > mountpoint_len && path.GetChars()[mountpoint_len] != '/')
921  continue;
922 
923  // Found a nested catalog transition point
924  if (!is_listable && (path_len == mountpoint_len))
925  break;
926 
927  if (leaf_catalog == NULL)
928  return true;
929  CatalogT *new_nested;
930  LogCvmfs(kLogCatalog, kLogDebug, "load nested catalog at %s",
931  i->mountpoint.c_str());
932  // prevent endless recursion with corrupted catalogs
933  // (due to reloading root)
934  if (i->hash.IsNull())
935  return false;
936  new_nested = MountCatalog(i->mountpoint, i->hash, parent);
937  if (!new_nested)
938  return false;
939 
940  result = MountSubtree(path, new_nested, is_listable, &parent);
941  break;
942  }
943  }
944 
945  if (leaf_catalog == NULL)
946  return false;
947  *leaf_catalog = parent;
948  return result;
949 }
950 
951 
956 template <class CatalogT>
958  const PathString &mountpoint,
959  const shash::Any &hash,
960  CatalogT *parent_catalog)
961 {
962  CatalogT *attached_catalog = NULL;
963  if (IsAttached(mountpoint, &attached_catalog)) {
964  return attached_catalog;
965  }
966 
967  CatalogContext ctlg_context(hash, mountpoint, kCtlgLocationMounted);
968 
969  if (ctlg_context.IsRootCatalog() && hash.IsNull()) {
970  if (GetNewRootCatalogContext(&ctlg_context) == kLoadFail) {
972  "failed to retrieve valid root catalog '%s'",
973  mountpoint.c_str());
974  return NULL;
975  }
976  }
977 
978  const LoadReturn retval = LoadCatalogByHash(&ctlg_context);
979  if ((retval == kLoadFail) || (retval == kLoadNoSpace)) {
980  LogCvmfs(kLogCatalog, kLogDebug, "failed to load catalog '%s' (%d - %s)",
981  mountpoint.c_str(), retval, Code2Ascii(retval));
982  return NULL;
983  }
984 
985  attached_catalog = CreateCatalog(ctlg_context.mountpoint(),
986  ctlg_context.hash(),
987  parent_catalog);
988 
989  // Attach loaded catalog
990  if (!AttachCatalog(ctlg_context.sqlite_path(), attached_catalog)) {
991  LogCvmfs(kLogCatalog, kLogDebug, "failed to attach catalog '%s'",
992  mountpoint.c_str());
993  UnloadCatalog(attached_catalog);
994  return NULL;
995  }
996 
997  if ((catalog_watermark_ > 0) && (catalogs_.size() >= catalog_watermark_)) {
998  DetachSiblings(mountpoint);
999  }
1000 
1001  return attached_catalog;
1002 }
1003 
1004 
1009 template <class CatalogT>
1011  const PathString &mountpoint,
1012  const shash::Any &hash)
1013 {
1014  assert(!hash.IsNull());
1015  CatalogContext ctlg_context(hash, mountpoint, kCtlgNoLocationNeeded);
1016 
1017  const LoadReturn load_ret = LoadCatalogByHash(&ctlg_context);
1018 
1019  if (load_ret != kLoadNew) {
1020  return NULL;
1021  }
1022 
1023  CatalogT *catalog = CatalogT::AttachFreely(mountpoint.ToString(),
1024  ctlg_context.sqlite_path(),
1025  ctlg_context.hash());
1026  catalog->TakeDatabaseFileOwnership();
1027  return catalog;
1028 }
1029 
1030 
1037 template <class CatalogT>
1039  CatalogT *new_catalog)
1040 {
1041  LogCvmfs(kLogCatalog, kLogDebug, "attaching catalog file %s",
1042  db_path.c_str());
1043 
1044  // Initialize the new catalog
1045  if (!new_catalog->OpenDatabase(db_path)) {
1046  LogCvmfs(kLogCatalog, kLogDebug, "initialization of catalog %s failed",
1047  db_path.c_str());
1048  return false;
1049  }
1050 
1051  // Determine the inode offset of this catalog
1052  uint64_t inode_chunk_size = new_catalog->max_row_id();
1053  InodeRange range = AcquireInodes(inode_chunk_size);
1054  new_catalog->set_inode_range(range);
1055  new_catalog->SetInodeAnnotation(inode_annotation_);
1056  new_catalog->SetOwnerMaps(&uid_map_, &gid_map_);
1057 
1058  // Add catalog to the manager
1059  if (!new_catalog->IsInitialized()) {
1061  "catalog initialization failed (obscure data)");
1062  inode_gauge_ -= inode_chunk_size;
1063  return false;
1064  }
1065  CheckInodeWatermark();
1066 
1067  // The revision of the catalog tree is given by the root catalog revision
1068  if (catalogs_.empty()) {
1069  revision_cache_ = new_catalog->GetRevision();
1070  timestamp_cache_ = new_catalog->GetLastModified();
1071  statistics_.catalog_revision->Set(revision_cache_);
1072  has_authz_cache_ = new_catalog->GetVOMSAuthz(&authz_cache_);
1073  volatile_flag_ = new_catalog->volatile_flag();
1074  }
1075 
1076  catalogs_.push_back(new_catalog);
1077  ActivateCatalog(new_catalog);
1078  return true;
1079 }
1080 
1081 
1090 template <class CatalogT>
1092  if (catalog->HasParent())
1093  catalog->parent()->RemoveChild(catalog);
1094 
1095  ReleaseInodes(catalog->inode_range());
1096  UnloadCatalog(catalog);
1097 
1098  // Delete catalog from internal lists
1099  typename CatalogList::iterator i;
1100  typename CatalogList::const_iterator iend;
1101  for (i = catalogs_.begin(), iend = catalogs_.end(); i != iend; ++i) {
1102  if (*i == catalog) {
1103  catalogs_.erase(i);
1104  delete catalog;
1105  return;
1106  }
1107  }
1108 
1109  assert(false);
1110 }
1111 
1112 
1119 template <class CatalogT>
1121  // Detach all child catalogs recursively
1122  typename CatalogList::const_iterator i;
1123  typename CatalogList::const_iterator iend;
1124  CatalogList catalogs_to_detach = catalog->GetChildren();
1125  for (i = catalogs_to_detach.begin(), iend = catalogs_to_detach.end();
1126  i != iend; ++i)
1127  {
1128  DetachSubtree(*i);
1129  }
1130 
1131  DetachCatalog(catalog);
1132 }
1133 
1134 
1139 template <class CatalogT>
1141  const PathString &current_tree)
1142 {
1143  bool again;
1144  do {
1145  again = false;
1146  unsigned N = catalogs_.size();
1147  for (unsigned i = 0; i < N; ++i) {
1148  if (!HasPrefix(current_tree.ToString(),
1149  catalogs_[i]->mountpoint().ToString(),
1150  false /* ignore_case */))
1151  {
1152  DetachSubtree(catalogs_[i]);
1153  again = true;
1154  break;
1155  }
1156  }
1157  } while (again);
1158  perf::Inc(statistics_.n_detach_siblings);
1159 }
1160 
1161 
1165 template <class CatalogT>
1167  const CatalogT *catalog,
1168  const int level) const
1169 {
1170  string output;
1171 
1172  // Indent according to level
1173  for (int i = 0; i < level; ++i)
1174  output += " ";
1175 
1176  output += "-> " + string(catalog->mountpoint().GetChars(),
1177  catalog->mountpoint().GetLength())
1178  + "\n";
1179 
1180  CatalogList children = catalog->GetChildren();
1181  typename CatalogList::const_iterator i = children.begin();
1182  typename CatalogList::const_iterator iend = children.end();
1183  for (; i != iend; ++i) {
1184  output += PrintHierarchyRecursively(*i, level + 1);
1185  }
1186 
1187  return output;
1188 }
1189 
1190 
1191 template <class CatalogT>
1193  const CatalogT *catalog) const
1194 {
1195  string result = catalog->PrintMemStatistics() + "\n";
1196 
1197  CatalogList children = catalog->GetChildren();
1198  typename CatalogList::const_iterator i = children.begin();
1199  typename CatalogList::const_iterator iend = children.end();
1200  for (; i != iend; ++i) {
1201  result += PrintMemStatsRecursively(*i);
1202  }
1203  return result;
1204 }
1205 
1206 
1210 template <class CatalogT>
1212  string result;
1213  ReadLock();
1214  result = PrintMemStatsRecursively(GetRootCatalog());
1215  Unlock();
1216  return result;
1217 }
1218 
1219 
1220 template <class CatalogT>
1222  char *mem_enforced =
1223  static_cast<char *>(pthread_getspecific(pkey_sqlitemem_));
1224  if (mem_enforced == NULL) {
1225  sqlite3_soft_heap_limit(kSqliteMemPerThread);
1226  pthread_setspecific(pkey_sqlitemem_, this);
1227  }
1228 }
1229 
1230 } // namespace catalog
1231 
1232 
1233 
1234 
1235 #endif // CVMFS_CATALOG_MGR_IMPL_H_
shash::Any hash() const
Definition: catalog_mgr.h:125
void DetachSubtree(CatalogT *catalog)
bool GetVOMSAuthz(std::string *authz) const
catalog::Counters LookupCounters(const PathString &path, std::string *subcatalog_path, shash::Any *hash)
bool IsNull() const
Definition: hash.h:383
CatalogT * LoadFreeCatalog(const PathString &mountpoint, const shash::Any &hash)
void StageNestedCatalogAndUnlock(const PathString &path, const CatalogT *parent, bool is_listable)
bool MountSubtree(const PathString &path, const CatalogT *entry_point, bool can_listing, CatalogT **leaf_catalog)
void DetachSiblings(const PathString &current_tree)
InodeAnnotation * inode_annotation_
Definition: catalog_mgr.h:452
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:249
void Assign(const char *chars, const unsigned length)
Definition: shortstring.h:61
std::string PrintHierarchyRecursively(const CatalogT *catalog, const int level) const
unsigned LookupOptions
Definition: catalog_mgr.h:42
void set_symlink(const LinkString &symlink)
perf::Statistics * statistics_
Definition: repository.h:139
void DetachCatalog(CatalogT *catalog)
bool IsAttached(const PathString &root_path, CatalogT **attached_catalog) const
uint64_t inode_t
bool ListingStat(const PathString &path, StatEntryList *listing)
assert((mem||(size==0))&&"Out Of Memory")
bool LookupPath(const PathString &path, const LookupOptions options, DirectoryEntry *entry)
IntegerMap< uint64_t > OwnerMap
Definition: catalog.h:41
std::string sqlite_path() const
Definition: catalog_mgr.h:127
uint64_t size
Definition: catalog.h:51
Algorithms
Definition: hash.h:41
bool Listing(const PathString &path, DirectoryEntryList *listing, const bool expand_symlink)
std::vector< DirectoryEntry > DirectoryEntryList
bool AttachCatalog(const std::string &db_path, CatalogT *new_catalog)
LoadReturn ChangeRoot(const shash::Any &root_hash)
const unsigned kSqliteMemPerThread
Definition: catalog_mgr.h:34
shash::Any GetNestedCatalogHash(const PathString &mountpoint)
void Append(const char *chars, const unsigned length)
Definition: shortstring.h:80
void Inc(class Counter *counter)
Definition: statistics.h:50
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:267
std::vector< CatalogT * > CatalogList
Definition: catalog_mgr.h:237
const unsigned kLookupRawSymlink
Definition: catalog_mgr.h:44
bool ListCatalogSkein(const PathString &path, std::vector< PathString > *result_list)
InodeRange AcquireInodes(uint64_t size)
pthread_rwlock_t * rwlock_
Definition: catalog_mgr.h:453
std::string ToString() const
Definition: shortstring.h:141
std::vector< NestedCatalog > NestedCatalogList
Definition: catalog.h:208
bool IsEmpty() const
Definition: shortstring.h:137
bool ListFileChunks(const PathString &path, const shash::Algorithms interpret_hashes_as, FileChunkList *chunks)
ShortString< kDefaultMaxPath, 0 > PathString
Definition: shortstring.h:217
const char * Code2Ascii(const LoadReturn error)
Definition: catalog_mgr.h:164
bool LookupXattrs(const PathString &path, XattrList *xattrs)
PathString mountpoint() const
Definition: catalog_mgr.h:126
bool LookupNested(const PathString &path, PathString *mountpoint, shash::Any *hash, uint64_t *size)
CatalogT * MountCatalog(const PathString &mountpoint, const shash::Any &hash, CatalogT *parent_catalog)
bool StartsWith(const ShortString &other) const
Definition: shortstring.h:189
void SetCatalogWatermark(unsigned limit)
void SetOwnerMaps(const OwnerMap &uid_map, const OwnerMap &gid_map)
unsigned GetLength() const
Definition: shortstring.h:131
void ReleaseInodes(const InodeRange chunk)
CatalogT * FindCatalog(const PathString &path) const
uint64_t offset
Definition: catalog.h:50
const char * c_str() const
Definition: shortstring.h:145
const char * GetChars() const
Definition: shortstring.h:123
std::string PrintHierarchy() const
std::string PrintMemStatsRecursively(const CatalogT *catalog) const
std::string PrintAllMemStatistics() const
static void size_t size
Definition: smalloc.h:54
void SetInodeAnnotation(InodeAnnotation *new_annotation)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528