5 #ifndef CVMFS_CATALOG_MGR_IMPL_H_
6 #define CVMFS_CATALOG_MGR_IMPL_H_
8 #ifndef __STDC_FORMAT_MACROS
9 #define __STDC_FORMAT_MACROS
12 #include "cvmfs_config.h"
27 template <
class CatalogT>
41 reinterpret_cast<pthread_rwlock_t *
>(smalloc(
sizeof(pthread_rwlock_t)));
42 int retval = pthread_rwlock_init(
rwlock_, NULL);
48 template <
class CatalogT>
51 pthread_key_delete(pkey_sqlitemem_);
52 pthread_rwlock_destroy(rwlock_);
56 template <
class CatalogT>
60 assert(catalogs_.empty() || (new_annotation == inode_annotation_));
61 inode_annotation_ = new_annotation;
64 template <
class CatalogT>
72 template <
class CatalogT>
74 catalog_watermark_ = limit;
77 template <
class CatalogT>
79 if (inode_watermark_status_ > 0)
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) {
89 inode_watermark_status_++;
98 template <
class CatalogT>
118 template <
class CatalogT>
121 "dryrun remounting repositories");
123 return GetNewRootCatalogContext(&ctlg_context);
126 template <
class CatalogT>
131 if (GetNewRootCatalogContext(&ctlg_context) !=
kLoadNew
132 && GetNewRootCatalogContext(&ctlg_context) !=
kLoadUp2Date) {
134 "Did not find any valid root catalog to mount");
140 const LoadReturn load_error = LoadCatalogByHash(&ctlg_context);
143 inode_t old_inode_gauge = inode_gauge_;
147 CatalogT *new_root = CreateCatalog(ctlg_context.
mountpoint(),
148 ctlg_context.
hash(), NULL);
150 bool retval = AttachCatalog(ctlg_context.
sqlite_path(), new_root);
153 if (inode_annotation_) {
154 inode_annotation_->IncGeneration(old_inode_gauge);
157 CheckInodeWatermark();
166 template <
class CatalogT>
172 "switching to root hash %s", root_hash.
ToString().c_str());
181 const LoadReturn load_error = LoadCatalogByHash(&ctlg_context);
184 inode_t old_inode_gauge = inode_gauge_;
191 bool retval = AttachCatalog(ctlg_context.
sqlite_path(), new_root);
194 if (inode_annotation_) {
195 inode_annotation_->IncGeneration(old_inode_gauge);
198 CheckInodeWatermark();
208 template <
class CatalogT>
211 if (catalogs_.empty()) {
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();
232 template <
class CatalogT>
237 CatalogT *catalog = FindCatalog(mountpoint);
239 if (catalog->mountpoint() == mountpoint) {
240 catalog = catalog->parent();
245 catalog->FindNested(mountpoint, &result, &size);
259 template <
class CatalogT>
272 EnforceSqliteMemLimit();
275 CatalogT *best_fit = FindCatalog(path);
280 path.
c_str(), best_fit->mountpoint().c_str());
281 bool found = best_fit->LookupPath(path, dirent);
284 if (!found && MountSubtree(path, best_fit,
false , NULL)) {
287 StageNestedCatalogAndUnlock(path, best_fit,
false );
290 best_fit = FindCatalog(path);
293 found = best_fit->LookupPath(path, dirent);
297 "entry not found, we may have to load nested catalogs");
299 CatalogT *nested_catalog;
301 MountSubtree(path, best_fit,
false , &nested_catalog);
305 "failed to load nested catalog for '%s'", path.
c_str());
306 goto lookup_path_notfound;
309 if (nested_catalog != best_fit) {
311 found = nested_catalog->LookupPath(path, dirent);
314 "nested catalogs loaded but entry '%s' was still not found",
316 if (dirent != NULL) *dirent = dirent_negative;
317 goto lookup_path_notfound;
319 best_fit = nested_catalog;
323 if (dirent != NULL) *dirent = dirent_negative;
324 goto lookup_path_notfound;
332 if (dirent != NULL) *dirent = dirent_negative;
333 goto lookup_path_notfound;
337 path.
c_str(), best_fit->mountpoint().c_str());
341 bool retval = best_fit->LookupRawSymlink(path, &raw_symlink);
349 lookup_path_notfound:
369 template <
class CatalogT>
376 EnforceSqliteMemLimit();
382 catalog_path.
Append(
"/.cvmfscatalog", 14);
385 CatalogT *best_fit = FindCatalog(catalog_path);
386 CatalogT *catalog = best_fit;
387 if (MountSubtree(catalog_path, best_fit,
false , NULL)) {
388 StageNestedCatalogAndUnlock(path, best_fit,
false);
391 best_fit = FindCatalog(catalog_path);
393 MountSubtree(catalog_path, best_fit,
false , &catalog);
402 if (catalog->HasParent()) {
403 result = catalog->parent()->FindNested(catalog->root_prefix(), hash,
size);
407 mountpoint->
Assign(catalog->root_prefix());
414 *hash = GetRootCatalog()->hash();
433 template <
class CatalogT>
436 std::vector<PathString> *result_list
438 EnforceSqliteMemLimit();
444 test.
Append(
"/.cvmfscatalog", 14);
447 CatalogT *best_fit = FindCatalog(test);
448 CatalogT *catalog = best_fit;
450 if (MountSubtree(test, best_fit,
false , NULL)) {
451 StageNestedCatalogAndUnlock(path, best_fit,
false);
454 best_fit = FindCatalog(test);
455 result = MountSubtree(test, best_fit,
false , &catalog);
464 CatalogT *cur_parent = catalog->parent();
467 std::vector<catalog::Catalog*> parents;
468 while (cur_parent->HasParent()) {
469 parents.push_back(cur_parent);
470 cur_parent = cur_parent->parent();
472 parents.push_back(cur_parent);
473 while (!parents.empty()) {
475 result_list->push_back(parents.back()->root_prefix());
480 result_list->push_back(catalog->root_prefix());
485 for (
unsigned i = 0; i < children.size(); i++) {
486 result_list->push_back(children.at(i).mountpoint);
494 template <
class CatalogT>
499 EnforceSqliteMemLimit();
504 CatalogT *best_fit = FindCatalog(path);
505 CatalogT *catalog = best_fit;
506 if (MountSubtree(path, best_fit,
false , NULL)) {
507 StageNestedCatalogAndUnlock(path, best_fit,
false);
510 best_fit = FindCatalog(path);
511 result = MountSubtree(path, best_fit,
false , &catalog);
519 result = catalog->LookupXattrsPath(path, xattrs);
532 template <
class CatalogT>
535 const bool expand_symlink)
537 EnforceSqliteMemLimit();
542 CatalogT *best_fit = FindCatalog(path);
543 CatalogT *catalog = best_fit;
544 if (MountSubtree(path, best_fit,
true , NULL)) {
545 StageNestedCatalogAndUnlock(path, best_fit,
true );
548 best_fit = FindCatalog(path);
549 result = MountSubtree(path, best_fit,
true , &catalog);
557 result = catalog->ListingPath(path, listing, expand_symlink);
570 template <
class CatalogT>
574 EnforceSqliteMemLimit();
579 CatalogT *best_fit = FindCatalog(path);
580 CatalogT *catalog = best_fit;
581 if (MountSubtree(path, best_fit,
true , NULL)) {
582 StageNestedCatalogAndUnlock(path, best_fit,
true );
585 best_fit = FindCatalog(path);
586 result = MountSubtree(path, best_fit,
true , &catalog);
594 result = catalog->ListingPathStat(path, listing);
608 template <
class CatalogT>
614 EnforceSqliteMemLimit();
619 CatalogT *best_fit = FindCatalog(path);
620 CatalogT *catalog = best_fit;
621 if (MountSubtree(path, best_fit,
false , NULL)) {
622 StageNestedCatalogAndUnlock(path, best_fit,
false);
625 best_fit = FindCatalog(path);
626 result = MountSubtree(path, best_fit,
false , &catalog);
633 result = catalog->ListPathChunks(path, interpret_hashes_as, chunks);
639 template <
class CatalogT>
642 std::string *subcatalog_path,
646 EnforceSqliteMemLimit();
652 catalog_path.
Append(
"/.cvmfscatalog", 14);
655 CatalogT *best_fit = FindCatalog(catalog_path);
656 CatalogT *catalog = best_fit;
657 if (MountSubtree(catalog_path, best_fit,
false , NULL)) {
658 StageNestedCatalogAndUnlock(path, best_fit,
false );
661 best_fit = FindCatalog(catalog_path);
663 MountSubtree(catalog_path, best_fit,
false , &catalog);
667 *subcatalog_path =
"error: failed to load catalog!";
673 *hash = catalog->hash();
674 *subcatalog_path = catalog->mountpoint().
ToString();
681 template <
class CatalogT>
684 const uint64_t revision = GetRevisionNoLock();
695 template <
class CatalogT>
697 return revision_cache_;
700 template <
class CatalogT>
703 const uint64_t timestamp = GetTimestampNoLock();
714 template <
class CatalogT>
716 return timestamp_cache_;
719 template <
class CatalogT>
722 const bool has_authz = has_authz_cache_;
723 if (has_authz && authz)
724 *authz = authz_cache_;
730 template <
class CatalogT>
733 const bool result = GetRootCatalog()->HasExplicitTTL();
739 template <
class CatalogT>
742 const uint64_t ttl = GetRootCatalog()->GetTTL();
748 template <
class CatalogT>
751 int result = catalogs_.size();
760 template <
class CatalogT>
763 string output = PrintHierarchyRecursively(GetRootCatalog(), 0);
772 template <
class CatalogT>
775 result.
offset = inode_gauge_;
778 inode_gauge_ +=
size;
780 result.
offset + 1, inode_gauge_);
791 template <
class CatalogT>
803 template <
class CatalogT>
806 assert(catalogs_.size() > 0);
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)
828 template <
class CatalogT>
830 CatalogT **attached_catalog)
const
832 if (catalogs_.size() == 0)
835 CatalogT *best_fit = FindCatalog(root_path);
836 if (best_fit->mountpoint() != root_path)
839 if (attached_catalog != NULL) *attached_catalog = best_fit;
844 template <
class CatalogT>
847 const CatalogT *parent,
851 const unsigned path_len = path.
GetLength();
854 typedef typename CatalogT::NestedCatalogList NestedCatalogList;
855 const NestedCatalogList& nested_catalogs = parent->ListNestedCatalogs();
857 for (
typename NestedCatalogList::const_iterator i = nested_catalogs.begin(),
858 iEnd = nested_catalogs.end(); i != iEnd; ++i)
866 const unsigned mountpoint_len = i->mountpoint.GetLength();
867 if (path_len > mountpoint_len && path.
GetChars()[mountpoint_len] !=
'/')
871 if (!is_listable && (path_len == mountpoint_len))
876 i->mountpoint.c_str(), i->hash.ToString().c_str());
877 StageNestedCatalogByHash(i->hash, i->mountpoint);
892 template <
class CatalogT>
895 const CatalogT *entry_point,
897 CatalogT **leaf_catalog)
900 CatalogT *parent = (entry_point == NULL) ?
901 GetRootCatalog() :
const_cast<CatalogT *
>(entry_point);
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)
919 unsigned mountpoint_len = i->mountpoint.GetLength();
920 if (path_len > mountpoint_len && path.
GetChars()[mountpoint_len] !=
'/')
924 if (!is_listable && (path_len == mountpoint_len))
927 if (leaf_catalog == NULL)
929 CatalogT *new_nested;
931 i->mountpoint.c_str());
934 if (i->hash.IsNull())
936 new_nested = MountCatalog(i->mountpoint, i->hash, parent);
940 result = MountSubtree(path, new_nested, is_listable, &parent);
945 if (leaf_catalog == NULL)
947 *leaf_catalog = parent;
956 template <
class CatalogT>
960 CatalogT *parent_catalog)
962 CatalogT *attached_catalog = NULL;
963 if (IsAttached(mountpoint, &attached_catalog)) {
964 return attached_catalog;
970 if (GetNewRootCatalogContext(&ctlg_context) ==
kLoadFail) {
972 "failed to retrieve valid root catalog '%s'",
978 const LoadReturn retval = LoadCatalogByHash(&ctlg_context);
985 attached_catalog = CreateCatalog(ctlg_context.
mountpoint(),
990 if (!AttachCatalog(ctlg_context.
sqlite_path(), attached_catalog)) {
993 UnloadCatalog(attached_catalog);
997 if ((catalog_watermark_ > 0) && (catalogs_.size() >= catalog_watermark_)) {
998 DetachSiblings(mountpoint);
1001 return attached_catalog;
1009 template <
class CatalogT>
1017 const LoadReturn load_ret = LoadCatalogByHash(&ctlg_context);
1023 CatalogT *catalog = CatalogT::AttachFreely(mountpoint.
ToString(),
1024 ctlg_context.sqlite_path(),
1025 ctlg_context.hash());
1026 catalog->TakeDatabaseFileOwnership();
1037 template <
class CatalogT>
1039 CatalogT *new_catalog)
1045 if (!new_catalog->OpenDatabase(db_path)) {
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_);
1059 if (!new_catalog->IsInitialized()) {
1061 "catalog initialization failed (obscure data)");
1062 inode_gauge_ -= inode_chunk_size;
1065 CheckInodeWatermark();
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();
1076 catalogs_.push_back(new_catalog);
1077 ActivateCatalog(new_catalog);
1090 template <
class CatalogT>
1092 if (catalog->HasParent())
1093 catalog->parent()->RemoveChild(catalog);
1095 ReleaseInodes(catalog->inode_range());
1096 UnloadCatalog(catalog);
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) {
1119 template <
class CatalogT>
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();
1131 DetachCatalog(catalog);
1139 template <
class CatalogT>
1146 unsigned N = catalogs_.size();
1147 for (
unsigned i = 0; i < N; ++i) {
1149 catalogs_[i]->mountpoint().ToString(),
1152 DetachSubtree(catalogs_[i]);
1165 template <
class CatalogT>
1167 const CatalogT *catalog,
1168 const int level)
const
1173 for (
int i = 0; i < level; ++i)
1176 output +=
"-> " + string(catalog->mountpoint().GetChars(),
1177 catalog->mountpoint().GetLength())
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);
1191 template <
class CatalogT>
1193 const CatalogT *catalog)
const
1195 string result = catalog->PrintMemStatistics() +
"\n";
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);
1210 template <
class CatalogT>
1214 result = PrintMemStatsRecursively(GetRootCatalog());
1220 template <
class CatalogT>
1222 char *mem_enforced =
1223 static_cast<char *
>(pthread_getspecific(pkey_sqlitemem_));
1224 if (mem_enforced == NULL) {
1226 pthread_setspecific(pkey_sqlitemem_,
this);
1235 #endif // CVMFS_CATALOG_MGR_IMPL_H_
void DetachSubtree(CatalogT *catalog)
bool GetVOMSAuthz(std::string *authz) const
catalog::Counters LookupCounters(const PathString &path, std::string *subcatalog_path, shash::Any *hash)
pthread_key_t pkey_sqlitemem_
virtual ~AbstractCatalogManager()
virtual void EnforceSqliteMemLimit()
CatalogT * LoadFreeCatalog(const PathString &mountpoint, const shash::Any &hash)
bool HasExplicitTTL() const
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 ¤t_tree)
InodeAnnotation * inode_annotation_
std::string ToString(const bool with_suffix=false) const
void Assign(const char *chars, const unsigned length)
std::string PrintHierarchyRecursively(const CatalogT *catalog, const int level) const
void set_symlink(const LinkString &symlink)
uint64_t GetTimestamp() const
perf::Statistics * statistics_
void DetachCatalog(CatalogT *catalog)
bool IsAttached(const PathString &root_path, CatalogT **attached_catalog) const
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
unsigned catalog_watermark_
std::string sqlite_path() const
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
uint64_t GetTimestampNoLock() const
LoadReturn RemountDryrun()
shash::Any GetNestedCatalogHash(const PathString &mountpoint)
void Append(const char *chars, const unsigned length)
void CheckInodeWatermark()
void Inc(class Counter *counter)
bool HasPrefix(const string &str, const string &prefix, const bool ignore_case)
std::vector< CatalogT * > CatalogList
const unsigned kLookupRawSymlink
bool ListCatalogSkein(const PathString &path, std::vector< PathString > *result_list)
InodeRange AcquireInodes(uint64_t size)
pthread_rwlock_t * rwlock_
std::string ToString() const
uint64_t GetRevision() const
std::vector< NestedCatalog > NestedCatalogList
uint64_t GetRevisionNoLock() const
int GetNumCatalogs() const
bool ListFileChunks(const PathString &path, const shash::Algorithms interpret_hashes_as, FileChunkList *chunks)
ShortString< kDefaultMaxPath, 0 > PathString
const char * Code2Ascii(const LoadReturn error)
uint64_t timestamp_cache_
bool LookupXattrs(const PathString &path, XattrList *xattrs)
PathString mountpoint() const
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
void SetCatalogWatermark(unsigned limit)
void SetOwnerMaps(const OwnerMap &uid_map, const OwnerMap &gid_map)
unsigned GetLength() const
void ReleaseInodes(const InodeRange chunk)
CatalogT * FindCatalog(const PathString &path) const
const char * c_str() const
int inode_watermark_status_
const char * GetChars() const
std::string PrintHierarchy() const
std::string PrintMemStatsRecursively(const CatalogT *catalog) const
std::string PrintAllMemStatistics() const
void SetInodeAnnotation(InodeAnnotation *new_annotation)
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)