CernVM-FS  2.9.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 "logging.h"
19 #include "shortstring.h"
20 #include "statistics.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;
35  volatile_flag_ = false;
36  has_authz_cache_ = false;
37  inode_annotation_ = NULL;
38  incarnation_ = 0;
39  rwlock_ =
40  reinterpret_cast<pthread_rwlock_t *>(smalloc(sizeof(pthread_rwlock_t)));
41  int retval = pthread_rwlock_init(rwlock_, NULL);
42  assert(retval == 0);
43  retval = pthread_key_create(&pkey_sqlitemem_, NULL);
44  assert(retval == 0);
45 }
46 
47 template <class CatalogT>
49  DetachAll();
50  pthread_key_delete(pkey_sqlitemem_);
51  pthread_rwlock_destroy(rwlock_);
52  free(rwlock_);
53 }
54 
55 template <class CatalogT>
57  InodeAnnotation *new_annotation)
58 {
59  assert(catalogs_.empty() || (new_annotation == inode_annotation_));
60  inode_annotation_ = new_annotation;
61 }
62 
63 template <class CatalogT>
65  const OwnerMap &gid_map)
66 {
67  uid_map_ = uid_map;
68  gid_map_ = gid_map;
69 }
70 
71 template <class CatalogT>
73  catalog_watermark_ = limit;
74 }
75 
76 template <class CatalogT>
78  if (inode_watermark_status_ > 0)
79  return;
80 
81  uint64_t highest_inode = inode_gauge_;
82  if (inode_annotation_)
83  highest_inode += inode_annotation_->GetGeneration();
84  uint64_t uint32_border = 1;
85  uint32_border = uint32_border << 32;
86  if (highest_inode >= uint32_border) {
87  LogCvmfs(kLogCatalog, kLogDebug | kLogSyslogWarn, "inodes exceed 32bit");
88  inode_watermark_status_++;
89  }
90 }
91 
92 
97 template <class CatalogT>
99  LogCvmfs(kLogCatalog, kLogDebug, "Initialize catalog");
100  WriteLock();
101  bool attached = MountCatalog(PathString("", 0), shash::Any(), NULL);
102  Unlock();
103 
104  if (!attached) {
105  LogCvmfs(kLogCatalog, kLogDebug, "failed to initialize root catalog");
106  }
107 
108  return attached;
109 }
110 
111 
117 template <class CatalogT>
120  "remounting repositories (dry run %d)", dry_run);
121  if (dry_run)
122  return LoadCatalog(PathString("", 0), shash::Any(), NULL, NULL);
123 
124  WriteLock();
125 
126  string catalog_path;
127  shash::Any catalog_hash;
128  const LoadError load_error = LoadCatalog(PathString("", 0),
129  shash::Any(),
130  &catalog_path,
131  &catalog_hash);
132  if (load_error == kLoadNew) {
133  inode_t old_inode_gauge = inode_gauge_;
134  DetachAll();
136 
137  CatalogT *new_root = CreateCatalog(PathString("", 0), catalog_hash, NULL);
138  assert(new_root);
139  bool retval = AttachCatalog(catalog_path, new_root);
140  assert(retval);
141 
142  if (inode_annotation_) {
143  inode_annotation_->IncGeneration(old_inode_gauge);
144  }
145  }
146  CheckInodeWatermark();
147  Unlock();
148 
149  return load_error;
150 }
151 
155 template <class CatalogT>
157  const shash::Any &root_hash)
158 {
160  "switching to root hash %s", root_hash.ToString().c_str());
161 
162  WriteLock();
163 
164  string catalog_path;
165  shash::Any catalog_hash;
166  const LoadError load_error = LoadCatalog(PathString("", 0),
167  root_hash,
168  &catalog_path,
169  &catalog_hash);
170  if (load_error == kLoadNew) {
171  inode_t old_inode_gauge = inode_gauge_;
172  DetachAll();
174 
175  CatalogT *new_root = CreateCatalog(PathString("", 0), catalog_hash, NULL);
176  assert(new_root);
177  bool retval = AttachCatalog(catalog_path, new_root);
178  assert(retval);
179 
180  if (inode_annotation_) {
181  inode_annotation_->IncGeneration(old_inode_gauge);
182  }
183  }
184  CheckInodeWatermark();
185  Unlock();
186 
187  return load_error;
188 }
189 
190 
194 template <class CatalogT>
196  WriteLock();
197  if (catalogs_.empty()) {
198  Unlock();
199  return;
200  }
201 
202  typename CatalogList::const_iterator i;
203  typename CatalogList::const_iterator iend;
204  CatalogList catalogs_to_detach = GetRootCatalog()->GetChildren();
205  for (i = catalogs_to_detach.begin(), iend = catalogs_to_detach.end();
206  i != iend; ++i)
207  {
208  DetachSubtree(*i);
209  }
210 
211  Unlock();
212 }
213 
214 
218 template <class CatalogT>
220  const PathString &mountpoint)
221 {
222  assert(!mountpoint.IsEmpty());
223  CatalogT *catalog = FindCatalog(mountpoint);
224  assert(catalog != NULL);
225  if (catalog->mountpoint() == mountpoint) {
226  catalog = catalog->parent();
227  assert(catalog != NULL);
228  }
229  shash::Any result;
230  uint64_t size;
231  catalog->FindNested(mountpoint, &result, &size);
232  return result;
233 }
234 
235 
245 template <class CatalogT>
247  const LookupOptions options,
248  DirectoryEntry *dirent)
249 {
250  // initialize as non-negative
251  assert(dirent);
252  *dirent = DirectoryEntry();
253 
254  // create a dummy negative directory entry
255  const DirectoryEntry dirent_negative =
257 
258  EnforceSqliteMemLimit();
259  ReadLock();
260 
261  CatalogT *best_fit = FindCatalog(path);
262  assert(best_fit != NULL);
263 
264  perf::Inc(statistics_.n_lookup_path);
265  LogCvmfs(kLogCatalog, kLogDebug, "looking up '%s' in catalog: '%s'",
266  path.c_str(), best_fit->mountpoint().c_str());
267  bool found = best_fit->LookupPath(path, dirent);
268 
269  // Possibly in a nested catalog
270  if (!found && MountSubtree(path, best_fit, false /* is_listable */, NULL)) {
271  LogCvmfs(kLogCatalog, kLogDebug, "looking up '%s' in a nested catalog",
272  path.c_str());
273  Unlock();
274  WriteLock();
275  // Check again to avoid race
276  best_fit = FindCatalog(path);
277  assert(best_fit != NULL);
278  perf::Inc(statistics_.n_lookup_path);
279  found = best_fit->LookupPath(path, dirent);
280 
281  if (!found) {
283  "entry not found, we may have to load nested catalogs");
284 
285  CatalogT *nested_catalog;
286  found =
287  MountSubtree(path, best_fit, false /* is_listable */, &nested_catalog);
288 
289  if (!found) {
291  "failed to load nested catalog for '%s'", path.c_str());
292  goto lookup_path_notfound;
293  }
294 
295  if (nested_catalog != best_fit) {
296  perf::Inc(statistics_.n_lookup_path);
297  found = nested_catalog->LookupPath(path, dirent);
298  if (!found) {
300  "nested catalogs loaded but entry '%s' was still not found",
301  path.c_str());
302  if (dirent != NULL) *dirent = dirent_negative;
303  goto lookup_path_notfound;
304  } else {
305  best_fit = nested_catalog;
306  }
307  } else {
308  LogCvmfs(kLogCatalog, kLogDebug, "no nested catalog fits");
309  if (dirent != NULL) *dirent = dirent_negative;
310  goto lookup_path_notfound;
311  }
312  }
313  assert(found);
314  }
315  // Not in a nested catalog (because no nested cataog fits), ENOENT
316  if (!found) {
317  LogCvmfs(kLogCatalog, kLogDebug, "ENOENT: '%s'", path.c_str());
318  if (dirent != NULL) *dirent = dirent_negative;
319  goto lookup_path_notfound;
320  }
321 
322  LogCvmfs(kLogCatalog, kLogDebug, "found entry '%s' in catalog '%s'",
323  path.c_str(), best_fit->mountpoint().c_str());
324 
325  if ((options & kLookupRawSymlink) == kLookupRawSymlink) {
326  LinkString raw_symlink;
327  bool retval = best_fit->LookupRawSymlink(path, &raw_symlink);
328  assert(retval); // Must be true, we have just found the entry
329  dirent->set_symlink(raw_symlink);
330  }
331 
332  Unlock();
333  return true;
334 
335  lookup_path_notfound:
336  Unlock();
337  // Includes both: ENOENT and not found due to I/O error
338  perf::Inc(statistics_.n_lookup_path_negative);
339  return false;
340 }
341 
342 
355 template <class CatalogT>
357  const PathString &path,
358  PathString *mountpoint,
359  shash::Any *hash,
360  uint64_t *size
361 ) {
362  EnforceSqliteMemLimit();
363  bool result = false;
364  ReadLock();
365 
366  // Look past current path to mount up to intended location
367  PathString catalog_path(path);
368  catalog_path.Append("/.cvmfscatalog", 14);
369 
370  // Find catalog, possibly load nested
371  CatalogT *best_fit = FindCatalog(catalog_path);
372  CatalogT *catalog = best_fit;
373  if (MountSubtree(catalog_path, best_fit, false /* is_listable */, NULL)) {
374  Unlock();
375  WriteLock();
376  // Check again to avoid race
377  best_fit = FindCatalog(catalog_path);
378  result =
379  MountSubtree(catalog_path, best_fit, false /* is_listable */, &catalog);
380  // Result is false if an available catalog failed to load (error happened)
381  if (!result) {
382  Unlock();
383  return false;
384  }
385  }
386 
387  // If the found catalog is the Root there is no parent to lookup
388  if (catalog->HasParent()) {
389  result = catalog->parent()->FindNested(catalog->root_prefix(), hash, size);
390  }
391 
392  // Mountpoint now points to the found catalog
393  mountpoint->Assign(catalog->root_prefix());
394 
395  // If the result is false, it means that no nested catalog was found for
396  // this path. As the root catalog does not have a Nested Catalog of
397  // itself, we manually set the values and leave the size as 0.
398  // TODO(nhazekam) Allow for Root Catalog to be returned
399  if (!result) {
400  *hash = GetRootCatalog()->hash();
401  *size = 0;
402  result = true;
403  }
404 
405  Unlock();
406  return result;
407 }
408 
409 
419 template <class CatalogT>
421  const PathString &path,
422  std::vector<PathString> *result_list
423 ) {
424  EnforceSqliteMemLimit();
425  bool result;
426  ReadLock();
427 
428  // Look past current path to mount up to intended location
429  PathString test(path);
430  test.Append("/.cvmfscatalog", 14);
431 
432  // Find catalog, possibly load nested
433  CatalogT *best_fit = FindCatalog(test);
434  CatalogT *catalog = best_fit;
435  // True if there is an available nested catalog
436  if (MountSubtree(test, best_fit, false /* is_listable */, NULL)) {
437  Unlock();
438  WriteLock();
439  // Check again to avoid race
440  best_fit = FindCatalog(test);
441  result = MountSubtree(test, best_fit, false /* is_listable */, &catalog);
442  // result is false if an available catalog failed to load
443  if (!result) {
444  Unlock();
445  return false;
446  }
447  }
448 
449  // Build listing
450  CatalogT *cur_parent = catalog->parent();
451  if (cur_parent) {
452  // Walk up parent tree to find base
453  std::vector<catalog::Catalog*> parents;
454  while (cur_parent->HasParent()) {
455  parents.push_back(cur_parent);
456  cur_parent = cur_parent->parent();
457  }
458  parents.push_back(cur_parent);
459  while (!parents.empty()) {
460  // Add to list in order starting at root
461  result_list->push_back(parents.back()->root_prefix());
462  parents.pop_back();
463  }
464  }
465  // Add the current catalog
466  result_list->push_back(catalog->root_prefix());
467 
468  Catalog::NestedCatalogList children = catalog->ListOwnNestedCatalogs();
469 
470  // Add all children nested catalogs
471  for (unsigned i = 0; i < children.size(); i++) {
472  result_list->push_back(children.at(i).mountpoint);
473  }
474 
475  Unlock();
476  return true;
477 }
478 
479 
480 template <class CatalogT>
482  const PathString &path,
483  XattrList *xattrs)
484 {
485  EnforceSqliteMemLimit();
486  bool result;
487  ReadLock();
488 
489  // Find catalog, possibly load nested
490  CatalogT *best_fit = FindCatalog(path);
491  CatalogT *catalog = best_fit;
492  if (MountSubtree(path, best_fit, false /* is_listable */, NULL)) {
493  Unlock();
494  WriteLock();
495  // Check again to avoid race
496  best_fit = FindCatalog(path);
497  result = MountSubtree(path, best_fit, false /* is_listable */, &catalog);
498  if (!result) {
499  Unlock();
500  return false;
501  }
502  }
503 
504  perf::Inc(statistics_.n_lookup_xattrs);
505  result = catalog->LookupXattrsPath(path, xattrs);
506 
507  Unlock();
508  return result;
509 }
510 
511 
518 template <class CatalogT>
520  DirectoryEntryList *listing,
521  const bool expand_symlink)
522 {
523  EnforceSqliteMemLimit();
524  bool result;
525  ReadLock();
526 
527  // Find catalog, possibly load nested
528  CatalogT *best_fit = FindCatalog(path);
529  CatalogT *catalog = best_fit;
530  if (MountSubtree(path, best_fit, true /* is_listable */, NULL)) {
531  Unlock();
532  WriteLock();
533  // Check again to avoid race
534  best_fit = FindCatalog(path);
535  result = MountSubtree(path, best_fit, true /* is_listable */, &catalog);
536  if (!result) {
537  Unlock();
538  return false;
539  }
540  }
541 
542  perf::Inc(statistics_.n_listing);
543  result = catalog->ListingPath(path, listing, expand_symlink);
544 
545  Unlock();
546  return result;
547 }
548 
549 
556 template <class CatalogT>
558  StatEntryList *listing)
559 {
560  EnforceSqliteMemLimit();
561  bool result;
562  ReadLock();
563 
564  // Find catalog, possibly load nested
565  CatalogT *best_fit = FindCatalog(path);
566  CatalogT *catalog = best_fit;
567  if (MountSubtree(path, best_fit, true /* is_listable */, NULL)) {
568  Unlock();
569  WriteLock();
570  // Check again to avoid race
571  best_fit = FindCatalog(path);
572  result = MountSubtree(path, best_fit, true /* is_listable */, &catalog);
573  if (!result) {
574  Unlock();
575  return false;
576  }
577  }
578 
579  perf::Inc(statistics_.n_listing);
580  result = catalog->ListingPathStat(path, listing);
581 
582  Unlock();
583  return result;
584 }
585 
586 
594 template <class CatalogT>
596  const PathString &path,
597  const shash::Algorithms interpret_hashes_as,
598  FileChunkList *chunks)
599 {
600  EnforceSqliteMemLimit();
601  bool result;
602  ReadLock();
603 
604  // Find catalog, possibly load nested
605  CatalogT *best_fit = FindCatalog(path);
606  CatalogT *catalog = best_fit;
607  if (MountSubtree(path, best_fit, false /* is_listable */, NULL)) {
608  Unlock();
609  WriteLock();
610  // Check again to avoid race
611  best_fit = FindCatalog(path);
612  result = MountSubtree(path, best_fit, false /* is_listable */, &catalog);
613  if (!result) {
614  Unlock();
615  return false;
616  }
617  }
618 
619  result = catalog->ListPathChunks(path, interpret_hashes_as, chunks);
620 
621  Unlock();
622  return result;
623 }
624 
625 template <class CatalogT>
627  const PathString &path,
628  std::string *subcatalog_path)
629 {
630  EnforceSqliteMemLimit();
631  bool result;
632  ReadLock();
633 
634  // Look past current path to mount up to intended location
635  PathString catalog_path(path);
636  catalog_path.Append("/.cvmfscatalog", 14);
637 
638  // Find catalog, possibly load nested
639  CatalogT *best_fit = FindCatalog(catalog_path);
640  CatalogT *catalog = best_fit;
641  if (MountSubtree(catalog_path, best_fit, false /* is_listable */, NULL)) {
642  Unlock();
643  WriteLock();
644  // Check again to avoid race
645  best_fit = FindCatalog(catalog_path);
646  result =
647  MountSubtree(catalog_path, best_fit, false /* is_listable */, &catalog);
648  // Result is false if an available catalog failed to load (error happened)
649  if (!result) {
650  Unlock();
651  *subcatalog_path = "error: failed to load catalog!";
652  return catalog::Counters();
653  }
654  }
655 
656  *subcatalog_path = catalog->mountpoint().ToString();
657  catalog::Counters counters = catalog->GetCounters();
658  Unlock();
659  return counters;
660 }
661 
662 
663 template <class CatalogT>
665  ReadLock();
666  const uint64_t revision = revision_cache_;
667  Unlock();
668  return revision;
669 }
670 
671 
672 template <class CatalogT>
673 bool AbstractCatalogManager<CatalogT>::GetVOMSAuthz(std::string *authz) const {
674  ReadLock();
675  const bool has_authz = has_authz_cache_;
676  if (has_authz && authz)
677  *authz = authz_cache_;
678  Unlock();
679  return has_authz;
680 }
681 
682 
683 template <class CatalogT>
685  ReadLock();
686  const bool result = GetRootCatalog()->HasExplicitTTL();
687  Unlock();
688  return result;
689 }
690 
691 
692 template <class CatalogT>
694  ReadLock();
695  const uint64_t ttl = GetRootCatalog()->GetTTL();
696  Unlock();
697  return ttl;
698 }
699 
700 
701 template <class CatalogT>
703  ReadLock();
704  int result = catalogs_.size();
705  Unlock();
706  return result;
707 }
708 
709 
713 template <class CatalogT>
715  ReadLock();
716  const string output = PrintHierarchyRecursively(GetRootCatalog(), 0);
717  Unlock();
718  return output;
719 }
720 
721 
725 template <class CatalogT>
727  InodeRange result;
728  result.offset = inode_gauge_;
729  result.size = size;
730 
731  inode_gauge_ += size;
732  LogCvmfs(kLogCatalog, kLogDebug, "allocating inodes from %d to %d.",
733  result.offset + 1, inode_gauge_);
734 
735  return result;
736 }
737 
738 
744 template <class CatalogT>
746  // TODO(jblomer) currently inodes are only released on remount
747 }
748 
749 
756 template <class CatalogT>
758  const PathString &path) const {
759  assert(catalogs_.size() > 0);
760 
761  // Start at the root catalog and successively go down the catalog tree
762  CatalogT *best_fit = GetRootCatalog();
763  CatalogT *next_fit = NULL;
764  while (best_fit->mountpoint() != path) {
765  next_fit = best_fit->FindSubtree(path);
766  if (next_fit == NULL)
767  break;
768  best_fit = next_fit;
769  }
770 
771  return best_fit;
772 }
773 
774 
781 template <class CatalogT>
783  CatalogT **attached_catalog) const
784 {
785  if (catalogs_.size() == 0)
786  return false;
787 
788  CatalogT *best_fit = FindCatalog(root_path);
789  if (best_fit->mountpoint() != root_path)
790  return false;
791 
792  if (attached_catalog != NULL) *attached_catalog = best_fit;
793  return true;
794 }
795 
796 
806 template <class CatalogT>
808  const PathString &path,
809  const CatalogT *entry_point,
810  bool is_listable,
811  CatalogT **leaf_catalog)
812 {
813  bool result = true;
814  CatalogT *parent = (entry_point == NULL) ?
815  GetRootCatalog() : const_cast<CatalogT *>(entry_point);
816  assert(path.StartsWith(parent->mountpoint()));
817 
818  // Try to find path as a super string of nested catalog mount points
819  PathString path_slash(path);
820  path_slash.Append("/", 1);
821  perf::Inc(statistics_.n_nested_listing);
822  typedef typename CatalogT::NestedCatalogList NestedCatalogList;
823  const NestedCatalogList& nested_catalogs =
824  parent->ListNestedCatalogs();
825  for (typename NestedCatalogList::const_iterator i = nested_catalogs.begin(),
826  iEnd = nested_catalogs.end(); i != iEnd; ++i)
827  {
828  // Next nesting level
829  PathString nested_path_slash(i->mountpoint);
830  nested_path_slash.Append("/", 1);
831  if (path_slash.StartsWith(nested_path_slash)) {
832  // Found a nested catalog transition point
833  if (!is_listable && (path_slash == nested_path_slash))
834  break;
835 
836  if (leaf_catalog == NULL)
837  return true;
838  CatalogT *new_nested;
839  LogCvmfs(kLogCatalog, kLogDebug, "load nested catalog at %s",
840  i->mountpoint.c_str());
841  // prevent endless recursion with corrupted catalogs
842  // (due to reloading root)
843  if (i->hash.IsNull())
844  return false;
845  new_nested = MountCatalog(i->mountpoint, i->hash, parent);
846  if (!new_nested)
847  return false;
848 
849  result = MountSubtree(path, new_nested, is_listable, &parent);
850  break;
851  }
852  }
853 
854  if (leaf_catalog == NULL)
855  return false;
856  *leaf_catalog = parent;
857  return result;
858 }
859 
860 
865 template <class CatalogT>
867  const PathString &mountpoint,
868  const shash::Any &hash,
869  CatalogT *parent_catalog)
870 {
871  CatalogT *attached_catalog = NULL;
872  if (IsAttached(mountpoint, &attached_catalog))
873  return attached_catalog;
874 
875  string catalog_path;
876  shash::Any catalog_hash;
877  const LoadError retval =
878  LoadCatalog(mountpoint, hash, &catalog_path, &catalog_hash);
879  if ((retval == kLoadFail) || (retval == kLoadNoSpace)) {
880  LogCvmfs(kLogCatalog, kLogDebug, "failed to load catalog '%s' (%d - %s)",
881  mountpoint.c_str(), retval, Code2Ascii(retval));
882  return NULL;
883  }
884 
885  attached_catalog = CreateCatalog(mountpoint, catalog_hash, parent_catalog);
886 
887  // Attach loaded catalog
888  if (!AttachCatalog(catalog_path, attached_catalog)) {
889  LogCvmfs(kLogCatalog, kLogDebug, "failed to attach catalog '%s'",
890  mountpoint.c_str());
891  UnloadCatalog(attached_catalog);
892  return NULL;
893  }
894 
895  if ((catalog_watermark_ > 0) && (catalogs_.size() >= catalog_watermark_)) {
896  DetachSiblings(mountpoint);
897  }
898 
899  return attached_catalog;
900 }
901 
902 
907 template <class CatalogT>
909  const PathString &mountpoint,
910  const shash::Any &hash)
911 {
912  string new_path;
913  shash::Any check_hash;
914  const LoadError load_error = LoadCatalog(mountpoint, hash, &new_path,
915  &check_hash);
916  if (load_error != kLoadNew)
917  return NULL;
918  assert(hash == check_hash);
919  CatalogT *catalog = CatalogT::AttachFreely(mountpoint.ToString(),
920  new_path, hash);
921  catalog->TakeDatabaseFileOwnership();
922  return catalog;
923 }
924 
925 
932 template <class CatalogT>
934  CatalogT *new_catalog)
935 {
936  LogCvmfs(kLogCatalog, kLogDebug, "attaching catalog file %s",
937  db_path.c_str());
938 
939  // Initialize the new catalog
940  if (!new_catalog->OpenDatabase(db_path)) {
941  LogCvmfs(kLogCatalog, kLogDebug, "initialization of catalog %s failed",
942  db_path.c_str());
943  return false;
944  }
945 
946  // Determine the inode offset of this catalog
947  uint64_t inode_chunk_size = new_catalog->max_row_id();
948  InodeRange range = AcquireInodes(inode_chunk_size);
949  new_catalog->set_inode_range(range);
950  new_catalog->SetInodeAnnotation(inode_annotation_);
951  new_catalog->SetOwnerMaps(&uid_map_, &gid_map_);
952 
953  // Add catalog to the manager
954  if (!new_catalog->IsInitialized()) {
956  "catalog initialization failed (obscure data)");
957  inode_gauge_ -= inode_chunk_size;
958  return false;
959  }
960  CheckInodeWatermark();
961 
962  // The revision of the catalog tree is given by the root catalog revision
963  if (catalogs_.empty()) {
964  revision_cache_ = new_catalog->GetRevision();
965  has_authz_cache_ = new_catalog->GetVOMSAuthz(&authz_cache_);
966  volatile_flag_ = new_catalog->volatile_flag();
967  }
968 
969  catalogs_.push_back(new_catalog);
970  ActivateCatalog(new_catalog);
971  return true;
972 }
973 
974 
983 template <class CatalogT>
985  if (catalog->HasParent())
986  catalog->parent()->RemoveChild(catalog);
987 
988  ReleaseInodes(catalog->inode_range());
989  UnloadCatalog(catalog);
990 
991  // Delete catalog from internal lists
992  typename CatalogList::iterator i;
993  typename CatalogList::const_iterator iend;
994  for (i = catalogs_.begin(), iend = catalogs_.end(); i != iend; ++i) {
995  if (*i == catalog) {
996  catalogs_.erase(i);
997  delete catalog;
998  return;
999  }
1000  }
1001 
1002  assert(false);
1003 }
1004 
1005 
1012 template <class CatalogT>
1014  // Detach all child catalogs recursively
1015  typename CatalogList::const_iterator i;
1016  typename CatalogList::const_iterator iend;
1017  CatalogList catalogs_to_detach = catalog->GetChildren();
1018  for (i = catalogs_to_detach.begin(), iend = catalogs_to_detach.end();
1019  i != iend; ++i)
1020  {
1021  DetachSubtree(*i);
1022  }
1023 
1024  DetachCatalog(catalog);
1025 }
1026 
1027 
1032 template <class CatalogT>
1034  const PathString &current_tree)
1035 {
1036  bool again;
1037  do {
1038  again = false;
1039  unsigned N = catalogs_.size();
1040  for (unsigned i = 0; i < N; ++i) {
1041  if (!HasPrefix(current_tree.ToString(),
1042  catalogs_[i]->mountpoint().ToString(),
1043  false /* ignore_case */))
1044  {
1045  DetachSubtree(catalogs_[i]);
1046  again = true;
1047  break;
1048  }
1049  }
1050  } while (again);
1051  perf::Inc(statistics_.n_detach_siblings);
1052 }
1053 
1054 
1058 template <class CatalogT>
1060  const CatalogT *catalog,
1061  const int level) const
1062 {
1063  string output;
1064 
1065  // Indent according to level
1066  for (int i = 0; i < level; ++i)
1067  output += " ";
1068 
1069  output += "-> " + string(catalog->mountpoint().GetChars(),
1070  catalog->mountpoint().GetLength())
1071  + "\n";
1072 
1073  CatalogList children = catalog->GetChildren();
1074  typename CatalogList::const_iterator i = children.begin();
1075  typename CatalogList::const_iterator iend = children.end();
1076  for (; i != iend; ++i) {
1077  output += PrintHierarchyRecursively(*i, level + 1);
1078  }
1079 
1080  return output;
1081 }
1082 
1083 
1084 template <class CatalogT>
1086  const CatalogT *catalog) const
1087 {
1088  string result = catalog->PrintMemStatistics() + "\n";
1089 
1090  CatalogList children = catalog->GetChildren();
1091  typename CatalogList::const_iterator i = children.begin();
1092  typename CatalogList::const_iterator iend = children.end();
1093  for (; i != iend; ++i) {
1094  result += PrintMemStatsRecursively(*i);
1095  }
1096  return result;
1097 }
1098 
1099 
1103 template <class CatalogT>
1105  string result;
1106  ReadLock();
1107  result = PrintMemStatsRecursively(GetRootCatalog());
1108  Unlock();
1109  return result;
1110 }
1111 
1112 
1113 template <class CatalogT>
1115  char *mem_enforced =
1116  static_cast<char *>(pthread_getspecific(pkey_sqlitemem_));
1117  if (mem_enforced == NULL) {
1118  sqlite3_soft_heap_limit(kSqliteMemPerThread);
1119  pthread_setspecific(pkey_sqlitemem_, reinterpret_cast<char *>(1));
1120  }
1121 }
1122 
1123 } // namespace catalog
1124 
1125 
1126 
1127 
1128 #endif // CVMFS_CATALOG_MGR_IMPL_H_
LoadError ChangeRoot(const shash::Any &root_hash)
void DetachSubtree(CatalogT *catalog)
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
bool GetVOMSAuthz(std::string *authz) const
const char * Code2Ascii(const LoadError error)
Definition: catalog_mgr.h:56
CatalogT * LoadFreeCatalog(const PathString &mountpoint, const shash::Any &hash)
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:301
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:245
void Assign(const char *chars, const unsigned length)
Definition: shortstring.h:53
std::string PrintHierarchyRecursively(const CatalogT *catalog, const int level) const
void set_symlink(const LinkString &symlink)
perf::Statistics * statistics_
Definition: repository.h:138
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
uint64_t size
Definition: catalog.h:51
LoadError Remount(const bool dry_run)
Algorithms
Definition: hash.h:39
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)
const unsigned kSqliteMemPerThread
Definition: catalog_mgr.h:32
shash::Any GetNestedCatalogHash(const PathString &mountpoint)
void Append(const char *chars, const unsigned length)
Definition: shortstring.h:70
void Inc(class Counter *counter)
Definition: statistics.h:50
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
Definition: string.cc:264
std::vector< CatalogT * > CatalogList
Definition: catalog_mgr.h:119
bool ListCatalogSkein(const PathString &path, std::vector< PathString > *result_list)
InodeRange AcquireInodes(uint64_t size)
pthread_rwlock_t * rwlock_
Definition: catalog_mgr.h:302
std::string ToString() const
Definition: shortstring.h:113
std::vector< NestedCatalog > NestedCatalogList
Definition: catalog.h:208
bool IsEmpty() const
Definition: shortstring.h:109
bool ListFileChunks(const PathString &path, const shash::Algorithms interpret_hashes_as, FileChunkList *chunks)
ShortString< kDefaultMaxPath, 0 > PathString
Definition: shortstring.h:189
catalog::Counters LookupCounters(const PathString &path, std::string *subcatalog_path)
bool LookupXattrs(const PathString &path, XattrList *xattrs)
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:161
void SetCatalogWatermark(unsigned limit)
void SetOwnerMaps(const OwnerMap &uid_map, const OwnerMap &gid_map)
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:117
std::string PrintHierarchy() const
std::string PrintMemStatsRecursively(const CatalogT *catalog) const
std::string PrintAllMemStatistics() const
static void size_t size
Definition: smalloc.h:47
void SetInodeAnnotation(InodeAnnotation *new_annotation)