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 
673  return revision;
674 }
675 
676 
677 template <class CatalogT>
678 bool AbstractCatalogManager<CatalogT>::GetVOMSAuthz(std::string *authz) const {
679  ReadLock();
680  const bool has_authz = has_authz_cache_;
681  if (has_authz && authz)
682  *authz = authz_cache_;
683  Unlock();
684  return has_authz;
685 }
686 
687 
688 template <class CatalogT>
690  ReadLock();
691  const bool result = GetRootCatalog()->HasExplicitTTL();
692  Unlock();
693  return result;
694 }
695 
696 
697 template <class CatalogT>
699  ReadLock();
700  const uint64_t ttl = GetRootCatalog()->GetTTL();
701  Unlock();
702  return ttl;
703 }
704 
705 
706 template <class CatalogT>
708  ReadLock();
709  int result = catalogs_.size();
710  Unlock();
711  return result;
712 }
713 
714 
718 template <class CatalogT>
720  ReadLock();
721  string output = PrintHierarchyRecursively(GetRootCatalog(), 0);
722  Unlock();
723  return output;
724 }
725 
726 
730 template <class CatalogT>
732  InodeRange result;
733  result.offset = inode_gauge_;
734  result.size = size;
735 
736  inode_gauge_ += size;
737  LogCvmfs(kLogCatalog, kLogDebug, "allocating inodes from %d to %d.",
738  result.offset + 1, inode_gauge_);
739 
740  return result;
741 }
742 
743 
749 template <class CatalogT>
751  // TODO(jblomer) currently inodes are only released on remount
752 }
753 
754 
761 template <class CatalogT>
763  const PathString &path) const {
764  assert(catalogs_.size() > 0);
765 
766  // Start at the root catalog and successively go down the catalog tree
767  CatalogT *best_fit = GetRootCatalog();
768  CatalogT *next_fit = NULL;
769  while (best_fit->mountpoint() != path) {
770  next_fit = best_fit->FindSubtree(path);
771  if (next_fit == NULL)
772  break;
773  best_fit = next_fit;
774  }
775 
776  return best_fit;
777 }
778 
779 
786 template <class CatalogT>
788  CatalogT **attached_catalog) const
789 {
790  if (catalogs_.size() == 0)
791  return false;
792 
793  CatalogT *best_fit = FindCatalog(root_path);
794  if (best_fit->mountpoint() != root_path)
795  return false;
796 
797  if (attached_catalog != NULL) *attached_catalog = best_fit;
798  return true;
799 }
800 
801 
811 template <class CatalogT>
813  const PathString &path,
814  const CatalogT *entry_point,
815  bool is_listable,
816  CatalogT **leaf_catalog)
817 {
818  bool result = true;
819  CatalogT *parent = (entry_point == NULL) ?
820  GetRootCatalog() : const_cast<CatalogT *>(entry_point);
821  assert(path.StartsWith(parent->mountpoint()));
822 
823  unsigned path_len = path.GetLength();
824 
825  // Try to find path as a super string of nested catalog mount points
826  perf::Inc(statistics_.n_nested_listing);
827  typedef typename CatalogT::NestedCatalogList NestedCatalogList;
828  const NestedCatalogList& nested_catalogs =
829  parent->ListNestedCatalogs();
830  for (typename NestedCatalogList::const_iterator i = nested_catalogs.begin(),
831  iEnd = nested_catalogs.end(); i != iEnd; ++i)
832  {
833  // Next nesting level
834  if (path.StartsWith(i->mountpoint)) {
835  // in this case the path doesn't start with
836  // the mountpoint in a file path sense
837  // (e.g. path is /a/bc and mountpoint is /a/b), and will be ignored
838  unsigned mountpoint_len = i->mountpoint.GetLength();
839  if (path_len > mountpoint_len && path.GetChars()[mountpoint_len] != '/')
840  continue;
841 
842  // Found a nested catalog transition point
843  if (!is_listable && (path_len == mountpoint_len))
844  break;
845 
846  if (leaf_catalog == NULL)
847  return true;
848  CatalogT *new_nested;
849  LogCvmfs(kLogCatalog, kLogDebug, "load nested catalog at %s",
850  i->mountpoint.c_str());
851  // prevent endless recursion with corrupted catalogs
852  // (due to reloading root)
853  if (i->hash.IsNull())
854  return false;
855  new_nested = MountCatalog(i->mountpoint, i->hash, parent);
856  if (!new_nested)
857  return false;
858 
859  result = MountSubtree(path, new_nested, is_listable, &parent);
860  break;
861  }
862  }
863 
864  if (leaf_catalog == NULL)
865  return false;
866  *leaf_catalog = parent;
867  return result;
868 }
869 
870 
875 template <class CatalogT>
877  const PathString &mountpoint,
878  const shash::Any &hash,
879  CatalogT *parent_catalog)
880 {
881  CatalogT *attached_catalog = NULL;
882  if (IsAttached(mountpoint, &attached_catalog))
883  return attached_catalog;
884 
885  string catalog_path;
886  shash::Any catalog_hash;
887  const LoadError retval =
888  LoadCatalog(mountpoint, hash, &catalog_path, &catalog_hash);
889  if ((retval == kLoadFail) || (retval == kLoadNoSpace)) {
890  LogCvmfs(kLogCatalog, kLogDebug, "failed to load catalog '%s' (%d - %s)",
891  mountpoint.c_str(), retval, Code2Ascii(retval));
892  return NULL;
893  }
894 
895  attached_catalog = CreateCatalog(mountpoint, catalog_hash, parent_catalog);
896 
897  // Attach loaded catalog
898  if (!AttachCatalog(catalog_path, attached_catalog)) {
899  LogCvmfs(kLogCatalog, kLogDebug, "failed to attach catalog '%s'",
900  mountpoint.c_str());
901  UnloadCatalog(attached_catalog);
902  return NULL;
903  }
904 
905  if ((catalog_watermark_ > 0) && (catalogs_.size() >= catalog_watermark_)) {
906  DetachSiblings(mountpoint);
907  }
908 
909  return attached_catalog;
910 }
911 
912 
917 template <class CatalogT>
919  const PathString &mountpoint,
920  const shash::Any &hash)
921 {
922  string new_path;
923  shash::Any check_hash;
924  const LoadError load_error = LoadCatalog(mountpoint, hash, &new_path,
925  &check_hash);
926  if (load_error != kLoadNew)
927  return NULL;
928  assert(hash == check_hash);
929  CatalogT *catalog = CatalogT::AttachFreely(mountpoint.ToString(),
930  new_path, hash);
931  catalog->TakeDatabaseFileOwnership();
932  return catalog;
933 }
934 
935 
942 template <class CatalogT>
944  CatalogT *new_catalog)
945 {
946  LogCvmfs(kLogCatalog, kLogDebug, "attaching catalog file %s",
947  db_path.c_str());
948 
949  // Initialize the new catalog
950  if (!new_catalog->OpenDatabase(db_path)) {
951  LogCvmfs(kLogCatalog, kLogDebug, "initialization of catalog %s failed",
952  db_path.c_str());
953  return false;
954  }
955 
956  // Determine the inode offset of this catalog
957  uint64_t inode_chunk_size = new_catalog->max_row_id();
958  InodeRange range = AcquireInodes(inode_chunk_size);
959  new_catalog->set_inode_range(range);
960  new_catalog->SetInodeAnnotation(inode_annotation_);
961  new_catalog->SetOwnerMaps(&uid_map_, &gid_map_);
962 
963  // Add catalog to the manager
964  if (!new_catalog->IsInitialized()) {
966  "catalog initialization failed (obscure data)");
967  inode_gauge_ -= inode_chunk_size;
968  return false;
969  }
970  CheckInodeWatermark();
971 
972  // The revision of the catalog tree is given by the root catalog revision
973  if (catalogs_.empty()) {
974  revision_cache_ = new_catalog->GetRevision();
975  statistics_.catalog_revision->Set(revision_cache_);
976  has_authz_cache_ = new_catalog->GetVOMSAuthz(&authz_cache_);
977  volatile_flag_ = new_catalog->volatile_flag();
978  }
979 
980  catalogs_.push_back(new_catalog);
981  ActivateCatalog(new_catalog);
982  return true;
983 }
984 
985 
994 template <class CatalogT>
996  if (catalog->HasParent())
997  catalog->parent()->RemoveChild(catalog);
998 
999  ReleaseInodes(catalog->inode_range());
1000  UnloadCatalog(catalog);
1001 
1002  // Delete catalog from internal lists
1003  typename CatalogList::iterator i;
1004  typename CatalogList::const_iterator iend;
1005  for (i = catalogs_.begin(), iend = catalogs_.end(); i != iend; ++i) {
1006  if (*i == catalog) {
1007  catalogs_.erase(i);
1008  delete catalog;
1009  return;
1010  }
1011  }
1012 
1013  assert(false);
1014 }
1015 
1016 
1023 template <class CatalogT>
1025  // Detach all child catalogs recursively
1026  typename CatalogList::const_iterator i;
1027  typename CatalogList::const_iterator iend;
1028  CatalogList catalogs_to_detach = catalog->GetChildren();
1029  for (i = catalogs_to_detach.begin(), iend = catalogs_to_detach.end();
1030  i != iend; ++i)
1031  {
1032  DetachSubtree(*i);
1033  }
1034 
1035  DetachCatalog(catalog);
1036 }
1037 
1038 
1043 template <class CatalogT>
1045  const PathString &current_tree)
1046 {
1047  bool again;
1048  do {
1049  again = false;
1050  unsigned N = catalogs_.size();
1051  for (unsigned i = 0; i < N; ++i) {
1052  if (!HasPrefix(current_tree.ToString(),
1053  catalogs_[i]->mountpoint().ToString(),
1054  false /* ignore_case */))
1055  {
1056  DetachSubtree(catalogs_[i]);
1057  again = true;
1058  break;
1059  }
1060  }
1061  } while (again);
1062  perf::Inc(statistics_.n_detach_siblings);
1063 }
1064 
1065 
1069 template <class CatalogT>
1071  const CatalogT *catalog,
1072  const int level) const
1073 {
1074  string output;
1075 
1076  // Indent according to level
1077  for (int i = 0; i < level; ++i)
1078  output += " ";
1079 
1080  output += "-> " + string(catalog->mountpoint().GetChars(),
1081  catalog->mountpoint().GetLength())
1082  + "\n";
1083 
1084  CatalogList children = catalog->GetChildren();
1085  typename CatalogList::const_iterator i = children.begin();
1086  typename CatalogList::const_iterator iend = children.end();
1087  for (; i != iend; ++i) {
1088  output += PrintHierarchyRecursively(*i, level + 1);
1089  }
1090 
1091  return output;
1092 }
1093 
1094 
1095 template <class CatalogT>
1097  const CatalogT *catalog) const
1098 {
1099  string result = catalog->PrintMemStatistics() + "\n";
1100 
1101  CatalogList children = catalog->GetChildren();
1102  typename CatalogList::const_iterator i = children.begin();
1103  typename CatalogList::const_iterator iend = children.end();
1104  for (; i != iend; ++i) {
1105  result += PrintMemStatsRecursively(*i);
1106  }
1107  return result;
1108 }
1109 
1110 
1114 template <class CatalogT>
1116  string result;
1117  ReadLock();
1118  result = PrintMemStatsRecursively(GetRootCatalog());
1119  Unlock();
1120  return result;
1121 }
1122 
1123 
1124 template <class CatalogT>
1126  char *mem_enforced =
1127  static_cast<char *>(pthread_getspecific(pkey_sqlitemem_));
1128  if (mem_enforced == NULL) {
1129  sqlite3_soft_heap_limit(kSqliteMemPerThread);
1130  pthread_setspecific(pkey_sqlitemem_, this);
1131  }
1132 }
1133 
1134 } // namespace catalog
1135 
1136 
1137 
1138 
1139 #endif // CVMFS_CATALOG_MGR_IMPL_H_
LoadError ChangeRoot(const shash::Any &root_hash)
void DetachSubtree(CatalogT *catalog)
#define LogCvmfs(source, mask,...)
Definition: logging.h:25
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:305
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:122
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:306
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:54
void SetInodeAnnotation(InodeAnnotation *new_annotation)