CernVM-FS  2.11.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;
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  shash::Any *hash
630  )
631 {
632  EnforceSqliteMemLimit();
633  bool result;
634  ReadLock();
635 
636  // Look past current path to mount up to intended location
637  PathString catalog_path(path);
638  catalog_path.Append("/.cvmfscatalog", 14);
639 
640  // Find catalog, possibly load nested
641  CatalogT *best_fit = FindCatalog(catalog_path);
642  CatalogT *catalog = best_fit;
643  if (MountSubtree(catalog_path, best_fit, false /* is_listable */, NULL)) {
644  Unlock();
645  WriteLock();
646  // Check again to avoid race
647  best_fit = FindCatalog(catalog_path);
648  result =
649  MountSubtree(catalog_path, best_fit, false /* is_listable */, &catalog);
650  // Result is false if an available catalog failed to load (error happened)
651  if (!result) {
652  Unlock();
653  *subcatalog_path = "error: failed to load catalog!";
654  *hash = shash::Any();
655  return catalog::Counters();
656  }
657  }
658 
659  *hash = catalog->hash();
660  *subcatalog_path = catalog->mountpoint().ToString();
661  catalog::Counters counters = catalog->GetCounters();
662  Unlock();
663  return counters;
664 }
665 
666 
667 template <class CatalogT>
669  ReadLock();
670  const uint64_t revision = revision_cache_;
671  Unlock();
672  return revision;
673 }
674 
675 
676 template <class CatalogT>
677 bool AbstractCatalogManager<CatalogT>::GetVOMSAuthz(std::string *authz) const {
678  ReadLock();
679  const bool has_authz = has_authz_cache_;
680  if (has_authz && authz)
681  *authz = authz_cache_;
682  Unlock();
683  return has_authz;
684 }
685 
686 
687 template <class CatalogT>
689  ReadLock();
690  const bool result = GetRootCatalog()->HasExplicitTTL();
691  Unlock();
692  return result;
693 }
694 
695 
696 template <class CatalogT>
698  ReadLock();
699  const uint64_t ttl = GetRootCatalog()->GetTTL();
700  Unlock();
701  return ttl;
702 }
703 
704 
705 template <class CatalogT>
707  ReadLock();
708  int result = catalogs_.size();
709  Unlock();
710  return result;
711 }
712 
713 
717 template <class CatalogT>
719  ReadLock();
720  string output = PrintHierarchyRecursively(GetRootCatalog(), 0);
721  Unlock();
722  return output;
723 }
724 
725 
729 template <class CatalogT>
731  InodeRange result;
732  result.offset = inode_gauge_;
733  result.size = size;
734 
735  inode_gauge_ += size;
736  LogCvmfs(kLogCatalog, kLogDebug, "allocating inodes from %d to %d.",
737  result.offset + 1, inode_gauge_);
738 
739  return result;
740 }
741 
742 
748 template <class CatalogT>
750  // TODO(jblomer) currently inodes are only released on remount
751 }
752 
753 
760 template <class CatalogT>
762  const PathString &path) const {
763  assert(catalogs_.size() > 0);
764 
765  // Start at the root catalog and successively go down the catalog tree
766  CatalogT *best_fit = GetRootCatalog();
767  CatalogT *next_fit = NULL;
768  while (best_fit->mountpoint() != path) {
769  next_fit = best_fit->FindSubtree(path);
770  if (next_fit == NULL)
771  break;
772  best_fit = next_fit;
773  }
774 
775  return best_fit;
776 }
777 
778 
785 template <class CatalogT>
787  CatalogT **attached_catalog) const
788 {
789  if (catalogs_.size() == 0)
790  return false;
791 
792  CatalogT *best_fit = FindCatalog(root_path);
793  if (best_fit->mountpoint() != root_path)
794  return false;
795 
796  if (attached_catalog != NULL) *attached_catalog = best_fit;
797  return true;
798 }
799 
800 
810 template <class CatalogT>
812  const PathString &path,
813  const CatalogT *entry_point,
814  bool is_listable,
815  CatalogT **leaf_catalog)
816 {
817  bool result = true;
818  CatalogT *parent = (entry_point == NULL) ?
819  GetRootCatalog() : const_cast<CatalogT *>(entry_point);
820  assert(path.StartsWith(parent->mountpoint()));
821 
822  unsigned path_len = path.GetLength();
823 
824  // Try to find path as a super string of nested catalog mount points
825  perf::Inc(statistics_.n_nested_listing);
826  typedef typename CatalogT::NestedCatalogList NestedCatalogList;
827  const NestedCatalogList& nested_catalogs =
828  parent->ListNestedCatalogs();
829  for (typename NestedCatalogList::const_iterator i = nested_catalogs.begin(),
830  iEnd = nested_catalogs.end(); i != iEnd; ++i)
831  {
832  // Next nesting level
833  if (path.StartsWith(i->mountpoint)) {
834  // in this case the path doesn't start with
835  // the mountpoint in a file path sense
836  // (e.g. path is /a/bc and mountpoint is /a/b), and will be ignored
837  unsigned mountpoint_len = i->mountpoint.GetLength();
838  if (path_len > mountpoint_len && path.GetChars()[mountpoint_len] != '/')
839  continue;
840 
841  // Found a nested catalog transition point
842  if (!is_listable && (path_len == mountpoint_len))
843  break;
844 
845  if (leaf_catalog == NULL)
846  return true;
847  CatalogT *new_nested;
848  LogCvmfs(kLogCatalog, kLogDebug, "load nested catalog at %s",
849  i->mountpoint.c_str());
850  // prevent endless recursion with corrupted catalogs
851  // (due to reloading root)
852  if (i->hash.IsNull())
853  return false;
854  new_nested = MountCatalog(i->mountpoint, i->hash, parent);
855  if (!new_nested)
856  return false;
857 
858  result = MountSubtree(path, new_nested, is_listable, &parent);
859  break;
860  }
861  }
862 
863  if (leaf_catalog == NULL)
864  return false;
865  *leaf_catalog = parent;
866  return result;
867 }
868 
869 
874 template <class CatalogT>
876  const PathString &mountpoint,
877  const shash::Any &hash,
878  CatalogT *parent_catalog)
879 {
880  CatalogT *attached_catalog = NULL;
881  if (IsAttached(mountpoint, &attached_catalog))
882  return attached_catalog;
883 
884  string catalog_path;
885  shash::Any catalog_hash;
886  const LoadError retval =
887  LoadCatalog(mountpoint, hash, &catalog_path, &catalog_hash);
888  if ((retval == kLoadFail) || (retval == kLoadNoSpace)) {
889  LogCvmfs(kLogCatalog, kLogDebug, "failed to load catalog '%s' (%d - %s)",
890  mountpoint.c_str(), retval, Code2Ascii(retval));
891  return NULL;
892  }
893 
894  attached_catalog = CreateCatalog(mountpoint, catalog_hash, parent_catalog);
895 
896  // Attach loaded catalog
897  if (!AttachCatalog(catalog_path, attached_catalog)) {
898  LogCvmfs(kLogCatalog, kLogDebug, "failed to attach catalog '%s'",
899  mountpoint.c_str());
900  UnloadCatalog(attached_catalog);
901  return NULL;
902  }
903 
904  if ((catalog_watermark_ > 0) && (catalogs_.size() >= catalog_watermark_)) {
905  DetachSiblings(mountpoint);
906  }
907 
908  return attached_catalog;
909 }
910 
911 
916 template <class CatalogT>
918  const PathString &mountpoint,
919  const shash::Any &hash)
920 {
921  string new_path;
922  shash::Any check_hash;
923  const LoadError load_error = LoadCatalog(mountpoint, hash, &new_path,
924  &check_hash);
925  if (load_error != kLoadNew)
926  return NULL;
927  assert(hash == check_hash);
928  CatalogT *catalog = CatalogT::AttachFreely(mountpoint.ToString(),
929  new_path, hash);
930  catalog->TakeDatabaseFileOwnership();
931  return catalog;
932 }
933 
934 
941 template <class CatalogT>
943  CatalogT *new_catalog)
944 {
945  LogCvmfs(kLogCatalog, kLogDebug, "attaching catalog file %s",
946  db_path.c_str());
947 
948  // Initialize the new catalog
949  if (!new_catalog->OpenDatabase(db_path)) {
950  LogCvmfs(kLogCatalog, kLogDebug, "initialization of catalog %s failed",
951  db_path.c_str());
952  return false;
953  }
954 
955  // Determine the inode offset of this catalog
956  uint64_t inode_chunk_size = new_catalog->max_row_id();
957  InodeRange range = AcquireInodes(inode_chunk_size);
958  new_catalog->set_inode_range(range);
959  new_catalog->SetInodeAnnotation(inode_annotation_);
960  new_catalog->SetOwnerMaps(&uid_map_, &gid_map_);
961 
962  // Add catalog to the manager
963  if (!new_catalog->IsInitialized()) {
965  "catalog initialization failed (obscure data)");
966  inode_gauge_ -= inode_chunk_size;
967  return false;
968  }
969  CheckInodeWatermark();
970 
971  // The revision of the catalog tree is given by the root catalog revision
972  if (catalogs_.empty()) {
973  revision_cache_ = new_catalog->GetRevision();
974  has_authz_cache_ = new_catalog->GetVOMSAuthz(&authz_cache_);
975  volatile_flag_ = new_catalog->volatile_flag();
976  }
977 
978  catalogs_.push_back(new_catalog);
979  ActivateCatalog(new_catalog);
980  return true;
981 }
982 
983 
992 template <class CatalogT>
994  if (catalog->HasParent())
995  catalog->parent()->RemoveChild(catalog);
996 
997  ReleaseInodes(catalog->inode_range());
998  UnloadCatalog(catalog);
999 
1000  // Delete catalog from internal lists
1001  typename CatalogList::iterator i;
1002  typename CatalogList::const_iterator iend;
1003  for (i = catalogs_.begin(), iend = catalogs_.end(); i != iend; ++i) {
1004  if (*i == catalog) {
1005  catalogs_.erase(i);
1006  delete catalog;
1007  return;
1008  }
1009  }
1010 
1011  assert(false);
1012 }
1013 
1014 
1021 template <class CatalogT>
1023  // Detach all child catalogs recursively
1024  typename CatalogList::const_iterator i;
1025  typename CatalogList::const_iterator iend;
1026  CatalogList catalogs_to_detach = catalog->GetChildren();
1027  for (i = catalogs_to_detach.begin(), iend = catalogs_to_detach.end();
1028  i != iend; ++i)
1029  {
1030  DetachSubtree(*i);
1031  }
1032 
1033  DetachCatalog(catalog);
1034 }
1035 
1036 
1041 template <class CatalogT>
1043  const PathString &current_tree)
1044 {
1045  bool again;
1046  do {
1047  again = false;
1048  unsigned N = catalogs_.size();
1049  for (unsigned i = 0; i < N; ++i) {
1050  if (!HasPrefix(current_tree.ToString(),
1051  catalogs_[i]->mountpoint().ToString(),
1052  false /* ignore_case */))
1053  {
1054  DetachSubtree(catalogs_[i]);
1055  again = true;
1056  break;
1057  }
1058  }
1059  } while (again);
1060  perf::Inc(statistics_.n_detach_siblings);
1061 }
1062 
1063 
1067 template <class CatalogT>
1069  const CatalogT *catalog,
1070  const int level) const
1071 {
1072  string output;
1073 
1074  // Indent according to level
1075  for (int i = 0; i < level; ++i)
1076  output += " ";
1077 
1078  output += "-> " + string(catalog->mountpoint().GetChars(),
1079  catalog->mountpoint().GetLength())
1080  + "\n";
1081 
1082  CatalogList children = catalog->GetChildren();
1083  typename CatalogList::const_iterator i = children.begin();
1084  typename CatalogList::const_iterator iend = children.end();
1085  for (; i != iend; ++i) {
1086  output += PrintHierarchyRecursively(*i, level + 1);
1087  }
1088 
1089  return output;
1090 }
1091 
1092 
1093 template <class CatalogT>
1095  const CatalogT *catalog) const
1096 {
1097  string result = catalog->PrintMemStatistics() + "\n";
1098 
1099  CatalogList children = catalog->GetChildren();
1100  typename CatalogList::const_iterator i = children.begin();
1101  typename CatalogList::const_iterator iend = children.end();
1102  for (; i != iend; ++i) {
1103  result += PrintMemStatsRecursively(*i);
1104  }
1105  return result;
1106 }
1107 
1108 
1112 template <class CatalogT>
1114  string result;
1115  ReadLock();
1116  result = PrintMemStatsRecursively(GetRootCatalog());
1117  Unlock();
1118  return result;
1119 }
1120 
1121 
1122 template <class CatalogT>
1124  char *mem_enforced =
1125  static_cast<char *>(pthread_getspecific(pkey_sqlitemem_));
1126  if (mem_enforced == NULL) {
1127  sqlite3_soft_heap_limit(kSqliteMemPerThread);
1128  pthread_setspecific(pkey_sqlitemem_, this);
1129  }
1130 }
1131 
1132 } // namespace catalog
1133 
1134 
1135 
1136 
1137 #endif // CVMFS_CATALOG_MGR_IMPL_H_
LoadError ChangeRoot(const shash::Any &root_hash)
void DetachSubtree(CatalogT *catalog)
#define LogCvmfs(source, mask,...)
Definition: logging.h:22
bool GetVOMSAuthz(std::string *authz) const
catalog::Counters LookupCounters(const PathString &path, std::string *subcatalog_path, shash::Any *hash)
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:302
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:40
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
uint64_t size
Definition: catalog.h:51
LoadError Remount(const bool dry_run)
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)
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: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:119
const unsigned kLookupRawSymlink
Definition: catalog_mgr.h:42
bool ListCatalogSkein(const PathString &path, std::vector< PathString > *result_list)
InodeRange AcquireInodes(uint64_t size)
pthread_rwlock_t * rwlock_
Definition: catalog_mgr.h:303
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
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: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:47
void SetInodeAnnotation(InodeAnnotation *new_annotation)