| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/catalog_mgr_client.cc |
| Date: | 2026-07-26 02:35:14 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 212 | 233 | 91.0% |
| Branches: | 189 | 331 | 57.1% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM file system. | ||
| 3 | */ | ||
| 4 | |||
| 5 | |||
| 6 | #include "catalog_mgr_client.h" | ||
| 7 | |||
| 8 | #include <string> | ||
| 9 | #include <vector> | ||
| 10 | |||
| 11 | #include "cache_posix.h" | ||
| 12 | #include "crypto/signature.h" | ||
| 13 | #include "fetch.h" | ||
| 14 | #include "manifest.h" | ||
| 15 | #include "mountpoint.h" | ||
| 16 | #include "quota.h" | ||
| 17 | #include "statistics.h" | ||
| 18 | #include "util/posix.h" // IWYU pragma: keep | ||
| 19 | #include "util/string.h" | ||
| 20 | |||
| 21 | using namespace std; // NOLINT | ||
| 22 | |||
| 23 | namespace catalog { | ||
| 24 | |||
| 25 | /** | ||
| 26 | * Triggered when the catalog is attached (db file opened) | ||
| 27 | */ | ||
| 28 | 735 | void ClientCatalogManager::ActivateCatalog(Catalog *catalog) { | |
| 29 | const Counters &counters = const_cast<const Catalog *>(catalog) | ||
| 30 | 735 | ->GetCounters(); | |
| 31 |
2/2✓ Branch 1 taken 703 times.
✓ Branch 2 taken 32 times.
|
735 | if (catalog->IsRoot()) { |
| 32 | 703 | all_inodes_ = counters.GetAllEntries(); | |
| 33 | } | ||
| 34 | 735 | loaded_inodes_ += counters.GetSelfEntries(); | |
| 35 | 735 | } | |
| 36 | |||
| 37 | |||
| 38 | 1123 | ClientCatalogManager::ClientCatalogManager(MountPoint *mountpoint) | |
| 39 | : AbstractCatalogManager<Catalog>(mountpoint->statistics()) | ||
| 40 |
1/2✓ Branch 1 taken 1123 times.
✗ Branch 2 not taken.
|
1123 | , repo_name_(mountpoint->fqrn()) |
| 41 | 1123 | , fetcher_(mountpoint->fetcher()) | |
| 42 | 1123 | , signature_mgr_(mountpoint->signature_mgr()) | |
| 43 |
1/2✓ Branch 2 taken 1123 times.
✗ Branch 3 not taken.
|
1123 | , workspace_(mountpoint->file_system()->workspace()) |
| 44 | 1123 | , offline_mode_(false) | |
| 45 | 1123 | , all_inodes_(0) | |
| 46 | 1123 | , loaded_inodes_(0) | |
| 47 |
1/2✓ Branch 1 taken 1123 times.
✗ Branch 2 not taken.
|
1123 | , fixed_root_catalog_() |
| 48 | 1123 | , fixed_alt_root_catalog_(false) | |
| 49 |
2/4✓ Branch 5 taken 1123 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1123 times.
✗ Branch 9 not taken.
|
2246 | , root_fd_(-1) { |
| 50 |
1/2✓ Branch 1 taken 1123 times.
✗ Branch 2 not taken.
|
1123 | LogCvmfs(kLogCatalog, kLogDebug, "constructing client catalog manager"); |
| 51 |
3/6✓ Branch 3 taken 1123 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1123 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1123 times.
✗ Branch 11 not taken.
|
1123 | n_certificate_hits_ = mountpoint->statistics()->Register( |
| 52 | "cache.n_certificate_hits", "Number of certificate hits"); | ||
| 53 |
3/6✓ Branch 3 taken 1123 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 1123 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 1123 times.
✗ Branch 11 not taken.
|
1123 | n_certificate_misses_ = mountpoint->statistics()->Register( |
| 54 | "cache.n_certificate_misses", "Number of certificate misses"); | ||
| 55 | 1123 | } | |
| 56 | |||
| 57 | |||
| 58 | 4112 | ClientCatalogManager::~ClientCatalogManager() { | |
| 59 | 2246 | LogCvmfs(kLogCache, kLogDebug, "unpinning / unloading all catalogs"); | |
| 60 | |||
| 61 | 4492 | for (map<PathString, shash::Any>::iterator i = mounted_catalogs_.begin(), | |
| 62 | 2246 | iend = mounted_catalogs_.end(); | |
| 63 |
2/2✓ Branch 1 taken 733 times.
✓ Branch 2 taken 1123 times.
|
3712 | i != iend; |
| 64 | 1466 | ++i) { | |
| 65 | 1466 | fetcher_->cache_mgr()->quota_mgr()->Unpin(i->second); | |
| 66 | } | ||
| 67 | 4112 | } | |
| 68 | |||
| 69 | |||
| 70 | 735 | Catalog *ClientCatalogManager::CreateCatalog(const PathString &mountpoint, | |
| 71 | const shash::Any &catalog_hash, | ||
| 72 | catalog::Catalog *parent_catalog) { | ||
| 73 | 735 | mounted_catalogs_[mountpoint] = loaded_catalogs_[mountpoint]; | |
| 74 | 735 | loaded_catalogs_.erase(mountpoint); | |
| 75 |
1/2✓ Branch 2 taken 735 times.
✗ Branch 3 not taken.
|
735 | return new Catalog(mountpoint, catalog_hash, parent_catalog); |
| 76 | } | ||
| 77 | |||
| 78 | |||
| 79 | 268 | shash::Any ClientCatalogManager::GetRootHash() { | |
| 80 | 268 | ReadLock(); | |
| 81 |
1/2✓ Branch 2 taken 268 times.
✗ Branch 3 not taken.
|
268 | shash::Any result = mounted_catalogs_[PathString("", 0)]; |
| 82 | 268 | Unlock(); | |
| 83 | 268 | return result; | |
| 84 | } | ||
| 85 | |||
| 86 | |||
| 87 | /** | ||
| 88 | * Specialized initialization that uses a fixed root hash. | ||
| 89 | * | ||
| 90 | * @returns true - root catalog was successfully mounted | ||
| 91 | * false - otherwise | ||
| 92 | */ | ||
| 93 | 373 | bool ClientCatalogManager::InitFixed(const shash::Any &root_hash, | |
| 94 | bool alternative_path) { | ||
| 95 |
1/2✓ Branch 2 taken 373 times.
✗ Branch 3 not taken.
|
373 | LogCvmfs(kLogCatalog, kLogDebug, "Initialize catalog with fixed root hash %s", |
| 96 | 746 | root_hash.ToString().c_str()); | |
| 97 | 373 | WriteLock(); | |
| 98 | 373 | fixed_alt_root_catalog_ = alternative_path; | |
| 99 | 373 | fixed_root_catalog_ = root_hash; | |
| 100 | |||
| 101 |
1/2✓ Branch 2 taken 373 times.
✗ Branch 3 not taken.
|
373 | const bool attached = MountCatalog(PathString("", 0), root_hash, NULL); |
| 102 | 373 | Unlock(); | |
| 103 | |||
| 104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 373 times.
|
373 | if (!attached) { |
| 105 | ✗ | LogCvmfs(kLogCatalog, kLogDebug, "failed to initialize fixed root catalog"); | |
| 106 | } | ||
| 107 | |||
| 108 | 373 | return attached; | |
| 109 | } | ||
| 110 | |||
| 111 | /** | ||
| 112 | * Gets information about the most recent root catalog, including even if it is | ||
| 113 | * a fixed root catalog. This is needed as Remount() does not know what kind of | ||
| 114 | * root catalog will be remounted. | ||
| 115 | * | ||
| 116 | * Checks the locations: mounted, alien cache and remote (server) and sets the | ||
| 117 | * fields of variable "result". For the most recent catalog the location, hash | ||
| 118 | * and revision number are set. | ||
| 119 | * | ||
| 120 | * | ||
| 121 | * @param [out] result All fields but sqlite_path will be set: | ||
| 122 | * mountpoint, root_ctl_location, root_ctlg_revision, hash | ||
| 123 | * @return kLoadUp2Date - if most recent root catalog is already mounted | ||
| 124 | * kLoadNew - otherwise | ||
| 125 | */ | ||
| 126 | 554 | LoadReturn ClientCatalogManager::GetNewRootCatalogContext( | |
| 127 | CatalogContext *result) { | ||
| 128 |
2/4✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 554 times.
✗ Branch 5 not taken.
|
554 | result->SetMountpoint(PathString("", 0)); |
| 129 | |||
| 130 | // quick escape if we have a fixed catalog | ||
| 131 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 554 times.
|
554 | if (!fixed_root_catalog_.IsNull()) { |
| 132 | ✗ | result->SetHash(fixed_root_catalog_); | |
| 133 | ✗ | result->SetRootCtlgRevision(GetRevisionNoLock()); | |
| 134 | |||
| 135 | // it might or might not be already mounted, but we do not care | ||
| 136 | // as we do no need to download and save the manifest | ||
| 137 | // (see LoadCatalogByHash()) as such we must set the location to this | ||
| 138 | ✗ | result->SetRootCtlgLocation(kCtlgLocationMounted); | |
| 139 | ✗ | offline_mode_ = false; | |
| 140 | |||
| 141 | // we can do this here as the very first time fixed catalog is loaded it | ||
| 142 | // call directly MountCatalog() and will skip the call to this function | ||
| 143 | // here | ||
| 144 | ✗ | return catalog::kLoadUp2Date; | |
| 145 | } | ||
| 146 | |||
| 147 | // 1) Get alien cache root catalog (local) | ||
| 148 | |||
| 149 | // Happens only on init/remount, i.e. quota won't delete a cached catalog | ||
| 150 |
1/2✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
|
554 | shash::Any local_newest_hash(shash::kSha1, shash::kSuffixCatalog); |
| 151 |
1/2✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
|
554 | shash::Any mounted_hash(shash::kSha1, shash::kSuffixCatalog); |
| 152 | 554 | uint64_t local_newest_timestamp = 0; | |
| 153 | 554 | uint64_t local_newest_revision = manifest::Breadcrumb::kInvalidRevision; | |
| 154 | |||
| 155 | 554 | const manifest::Breadcrumb breadcrumb = fetcher_->cache_mgr()->LoadBreadcrumb( | |
| 156 |
1/2✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
|
554 | repo_name_); |
| 157 |
3/4✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 138 times.
✓ Branch 4 taken 416 times.
|
554 | if (breadcrumb.IsValid()) { |
| 158 | 138 | local_newest_hash = breadcrumb.catalog_hash; | |
| 159 | 138 | local_newest_timestamp = breadcrumb.timestamp; | |
| 160 | 138 | local_newest_revision = breadcrumb.revision; | |
| 161 |
1/2✓ Branch 3 taken 138 times.
✗ Branch 4 not taken.
|
276 | LogCvmfs(kLogCache, kLogDebug, |
| 162 | "Cached copy publish date %s (hash %s, revision %" PRIu64 ")", | ||
| 163 |
1/2✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
|
276 | StringifyTime(static_cast<int64_t>(local_newest_timestamp), true) |
| 164 | .c_str(), | ||
| 165 |
1/2✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
|
276 | local_newest_hash.ToString().c_str(), breadcrumb.revision); |
| 166 | } else { | ||
| 167 |
1/2✓ Branch 2 taken 416 times.
✗ Branch 3 not taken.
|
416 | LogCvmfs(kLogCache, kLogDebug, "Unable to read local checksum %s", |
| 168 |
1/2✓ Branch 1 taken 416 times.
✗ Branch 2 not taken.
|
832 | breadcrumb.ToString().c_str()); |
| 169 | } | ||
| 170 | |||
| 171 | // 2) Select local newest catalog: mounted vs alien | ||
| 172 | |||
| 173 | 554 | result->SetRootCtlgLocation(kCtlgLocationBreadcrumb); | |
| 174 | 554 | LoadReturn success_code = catalog::kLoadNew; | |
| 175 | |||
| 176 |
2/2✓ Branch 1 taken 102 times.
✓ Branch 2 taken 452 times.
|
554 | if (mounted_catalogs_.size() > 0) { |
| 177 | const std::map<PathString, shash::Any>::iterator | ||
| 178 |
2/4✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
|
102 | curr_hash_itr = mounted_catalogs_.find(PathString("", 0)); |
| 179 | 102 | mounted_hash = curr_hash_itr->second; | |
| 180 | } | ||
| 181 | |||
| 182 | // We only look for currently loaded catalog if the revision is newer than | ||
| 183 | // the breadcrumb revision and both revision numbers are valid (!= -1ul). | ||
| 184 | 554 | if ((local_newest_revision <= GetRevisionNoLock() | |
| 185 |
1/2✓ Branch 0 taken 416 times.
✗ Branch 1 not taken.
|
416 | || local_newest_revision == manifest::Breadcrumb::kInvalidRevision) |
| 186 |
6/6✓ Branch 0 taken 416 times.
✓ Branch 1 taken 138 times.
✓ Branch 3 taken 102 times.
✓ Branch 4 taken 452 times.
✓ Branch 5 taken 102 times.
✓ Branch 6 taken 452 times.
|
970 | && mounted_catalogs_.size() > 0) { |
| 187 | 102 | local_newest_hash = mounted_hash; | |
| 188 | 102 | local_newest_revision = GetRevisionNoLock(); | |
| 189 | // if needed for integration test 707: breadcrumb_timestamp_newer() | ||
| 190 | 102 | local_newest_timestamp = GetTimestampNoLock() > local_newest_timestamp | |
| 191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | ? GetTimestampNoLock() |
| 192 | : local_newest_timestamp; | ||
| 193 | 102 | result->SetRootCtlgLocation(kCtlgLocationMounted); | |
| 194 | 102 | success_code = catalog::kLoadUp2Date; | |
| 195 |
4/6✓ Branch 0 taken 36 times.
✓ Branch 1 taken 416 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 452 times.
|
452 | } else if (local_newest_revision == 0 && mounted_catalogs_.size() > 0) { |
| 196 | // breadcrumb has no revision | ||
| 197 | // TODO(heretherebedragons) this branch can be removed in future versions | ||
| 198 | |||
| 199 | // revisions are better, but if we dont have any we need to compare by | ||
| 200 | // timestamp (you can have multiple revisions in the same timestamp) | ||
| 201 | ✗ | if (local_newest_timestamp < GetTimestampNoLock()) { | |
| 202 | ✗ | local_newest_hash = mounted_hash; | |
| 203 | ✗ | local_newest_revision = GetRevisionNoLock(); | |
| 204 | ✗ | local_newest_timestamp = GetTimestampNoLock(); | |
| 205 | ✗ | result->SetRootCtlgLocation(kCtlgLocationMounted); | |
| 206 | ✗ | success_code = catalog::kLoadUp2Date; | |
| 207 | } | ||
| 208 | } | ||
| 209 | |||
| 210 | // 3) Get remote root catalog (fails if remote catalog is older) | ||
| 211 | manifest::Failures manifest_failure; | ||
| 212 | UniquePtr<CachedManifestEnsemble> ensemble( | ||
| 213 |
2/4✓ Branch 2 taken 554 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 554 times.
✗ Branch 7 not taken.
|
554 | new CachedManifestEnsemble(fetcher_->cache_mgr(), this)); |
| 214 |
2/4✓ Branch 1 taken 554 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 554 times.
✗ Branch 5 not taken.
|
554 | manifest_failure = manifest::Fetch( |
| 215 | 554 | "", repo_name_, local_newest_timestamp, &local_newest_hash, | |
| 216 | 554 | signature_mgr_, fetcher_->download_mgr(), ensemble.weak_ref()); | |
| 217 | |||
| 218 |
2/2✓ Branch 0 taken 381 times.
✓ Branch 1 taken 173 times.
|
554 | if (manifest_failure == manifest::kFailOk) { |
| 219 | // server has newest revision or no valid local revision | ||
| 220 | 381 | if (ensemble->manifest->revision() > local_newest_revision | |
| 221 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 292 times.
|
379 | || local_newest_revision == manifest::Breadcrumb::kInvalidRevision |
| 222 | // if revision is 0 both local and server, load catalog from server | ||
| 223 | // as local is most likely just "initialized" without valid value | ||
| 224 |
6/6✓ Branch 0 taken 379 times.
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 332 times.
✓ Branch 7 taken 49 times.
|
798 | || (ensemble->manifest->revision() == 0 |
| 225 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | && local_newest_revision == 0)) { |
| 226 | 332 | result->SetHash(ensemble->manifest->catalog_hash()); | |
| 227 | 332 | result->SetRootCtlgRevision(ensemble->manifest->revision()); | |
| 228 | 332 | result->SetRootCtlgLocation(kCtlgLocationServer); | |
| 229 | 332 | fixed_alt_root_catalog_ = ensemble->manifest->has_alt_catalog_path(); | |
| 230 | |||
| 231 |
1/2✓ Branch 1 taken 332 times.
✗ Branch 2 not taken.
|
332 | result->TakeManifestEnsemble( |
| 232 | 332 | static_cast<manifest::ManifestEnsemble *>(ensemble.Release())); | |
| 233 | 332 | offline_mode_ = false; | |
| 234 | |||
| 235 | 332 | return catalog::kLoadNew; | |
| 236 | } | ||
| 237 | } | ||
| 238 |
1/2✓ Branch 2 taken 222 times.
✗ Branch 3 not taken.
|
222 | LogCvmfs(kLogCache, kLogDebug, |
| 239 | "Failed fetch manifest from server: " | ||
| 240 | "manifest too old or server unreachable (%d - %s)", | ||
| 241 | manifest_failure, manifest::Code2Ascii(manifest_failure)); | ||
| 242 | |||
| 243 | // total failure: server not reachable and no valid local hash | ||
| 244 |
6/6✓ Branch 0 taken 173 times.
✓ Branch 1 taken 49 times.
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 49 times.
✓ Branch 5 taken 124 times.
✓ Branch 6 taken 98 times.
|
222 | if ((manifest_failure != manifest::kFailOk) && local_newest_hash.IsNull()) { |
| 245 |
1/2✓ Branch 1 taken 124 times.
✗ Branch 2 not taken.
|
124 | LogCvmfs(kLogCache, kLogDebug, "No valid root catalog found!"); |
| 246 | 124 | return catalog::kLoadFail; | |
| 247 | } | ||
| 248 | |||
| 249 | 98 | if (manifest_failure == manifest::kFailOk | |
| 250 |
5/6✓ Branch 0 taken 49 times.
✓ Branch 1 taken 49 times.
✓ Branch 4 taken 49 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 49 times.
✓ Branch 7 taken 49 times.
|
98 | && ensemble->manifest->revision() == local_newest_revision) { |
| 251 | 49 | offline_mode_ = false; | |
| 252 | } else { | ||
| 253 | 49 | offline_mode_ = true; | |
| 254 | } | ||
| 255 | 98 | result->SetHash(local_newest_hash); | |
| 256 | 98 | result->SetRootCtlgRevision(local_newest_revision); | |
| 257 | |||
| 258 | // for integration test 707: breadcrumb_revision_large() | ||
| 259 |
4/8✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 98 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
✗ Branch 9 not taken.
|
98 | if (breadcrumb.IsValid() && breadcrumb.catalog_hash == mounted_hash) { |
| 260 | 98 | success_code = catalog::kLoadUp2Date; | |
| 261 | } | ||
| 262 | |||
| 263 | 98 | return success_code; | |
| 264 | 554 | } | |
| 265 | |||
| 266 | 1143 | std::string ClientCatalogManager::GetCatalogDescription( | |
| 267 | const PathString &mountpoint, const shash::Any &hash) { | ||
| 268 |
2/4✓ Branch 1 taken 1143 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1143 times.
✗ Branch 5 not taken.
|
2286 | return "file catalog at " + repo_name_ + ":" |
| 269 |
2/4✓ Branch 1 taken 1143 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1143 times.
✗ Branch 5 not taken.
|
3429 | + (mountpoint.IsEmpty() |
| 270 |
8/14✓ Branch 0 taken 801 times.
✓ Branch 1 taken 342 times.
✓ Branch 4 taken 801 times.
✗ Branch 5 not taken.
✓ Branch 9 taken 342 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 342 times.
✓ Branch 13 taken 801 times.
✓ Branch 15 taken 801 times.
✓ Branch 16 taken 342 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
|
2628 | ? "/" |
| 271 | 342 | : string(mountpoint.GetChars(), mountpoint.GetLength())) | |
| 272 |
3/6✓ Branch 2 taken 1143 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1143 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1143 times.
✗ Branch 9 not taken.
|
4572 | + " (" + hash.ToString() + ")"; |
| 273 | } | ||
| 274 | |||
| 275 | /** | ||
| 276 | * Loads (and fetches) a catalog by hash for a given mountpoint. | ||
| 277 | * | ||
| 278 | * Special case for root catalog: ctlg_context->root_ctlg_location must be | ||
| 279 | * given. | ||
| 280 | * | ||
| 281 | * @param [in, out] ctlg_context mandatory fields (input): mountpoint, hash | ||
| 282 | * additional mandatory fields for root catalog: root_ctlg_location | ||
| 283 | * output: sqlite_path is set if catalog fetch successful | ||
| 284 | * @return kLoadUp2Date for root catalog that is already mounted | ||
| 285 | * kLoadNew for any other successful load | ||
| 286 | * kLoadFail on failure | ||
| 287 | */ | ||
| 288 | 1127 | LoadReturn ClientCatalogManager::LoadCatalogByHash( | |
| 289 | CatalogContext *ctlg_context) { | ||
| 290 |
1/2✓ Branch 1 taken 1127 times.
✗ Branch 2 not taken.
|
1127 | const string catalog_descr = GetCatalogDescription(ctlg_context->mountpoint(), |
| 291 |
1/2✓ Branch 2 taken 1127 times.
✗ Branch 3 not taken.
|
2254 | ctlg_context->hash()); |
| 292 |
1/2✓ Branch 2 taken 1127 times.
✗ Branch 3 not taken.
|
1127 | string alt_root_catalog_path = ""; |
| 293 | |||
| 294 | // root catalog needs special handling because of alt_root_catalog_path | ||
| 295 |
5/8✓ Branch 1 taken 1127 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 801 times.
✓ Branch 4 taken 326 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 801 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1127 times.
|
1127 | if (ctlg_context->IsRootCatalog() && fixed_alt_root_catalog_) { |
| 296 | ✗ | alt_root_catalog_path = ctlg_context->hash().MakeAlternativePath(); | |
| 297 | } | ||
| 298 | |||
| 299 |
1/2✓ Branch 2 taken 1127 times.
✗ Branch 3 not taken.
|
2254 | const LoadReturn load_ret = FetchCatalogByHash( |
| 300 | 1127 | ctlg_context->hash(), catalog_descr, alt_root_catalog_path, | |
| 301 | ctlg_context->GetSqlitePathPtr()); | ||
| 302 |
2/2✓ Branch 0 taken 1078 times.
✓ Branch 1 taken 49 times.
|
1127 | if (load_ret == catalog::kLoadNew) { |
| 303 |
2/4✓ Branch 2 taken 1078 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1078 times.
✗ Branch 6 not taken.
|
1078 | loaded_catalogs_[ctlg_context->mountpoint()] = ctlg_context->hash(); |
| 304 | |||
| 305 |
3/4✓ Branch 1 taken 1078 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 801 times.
✓ Branch 4 taken 277 times.
|
1078 | if (ctlg_context->IsRootCatalog()) { |
| 306 |
2/2✓ Branch 1 taken 471 times.
✓ Branch 2 taken 330 times.
|
801 | if (ctlg_context->root_ctlg_location() == kCtlgLocationMounted) { |
| 307 | 471 | return kLoadUp2Date; | |
| 308 | } | ||
| 309 | |||
| 310 | // if coming from server: update breadcrumb | ||
| 311 |
1/2✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
|
330 | if (ctlg_context->root_ctlg_location() == kCtlgLocationServer) { |
| 312 | // Keep a copy of the manifest, it backs the repo_metainfo xattr | ||
| 313 | manifest_ = new manifest::Manifest( | ||
| 314 |
4/8✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 330 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 330 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 330 times.
✗ Branch 11 not taken.
|
330 | *ctlg_context->manifest_ensemble()->manifest); |
| 315 | |||
| 316 | // Store new manifest and certificate | ||
| 317 | 330 | CacheManager::Label label; | |
| 318 |
1/2✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
|
330 | label.path = repo_name_; |
| 319 | 330 | label.flags |= CacheManager::kLabelCertificate; | |
| 320 |
3/4✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 293 times.
✓ Branch 4 taken 37 times.
|
330 | if (ctlg_context->manifest_ensemble()->cert_size > 0) { |
| 321 |
1/2✓ Branch 2 taken 293 times.
✗ Branch 3 not taken.
|
586 | fetcher_->cache_mgr()->CommitFromMem( |
| 322 |
1/2✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
|
586 | CacheManager::LabeledObject( |
| 323 | 586 | ctlg_context->manifest_ensemble()->manifest->certificate(), | |
| 324 | label), | ||
| 325 |
1/2✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
|
293 | ctlg_context->manifest_ensemble()->cert_buf, |
| 326 |
2/4✓ Branch 1 taken 293 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 293 times.
✗ Branch 5 not taken.
|
293 | ctlg_context->manifest_ensemble()->cert_size); |
| 327 | } | ||
| 328 | 330 | fetcher_->cache_mgr()->StoreBreadcrumb( | |
| 329 |
2/4✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 330 times.
✗ Branch 5 not taken.
|
330 | *ctlg_context->manifest_ensemble()->manifest); |
| 330 | 330 | } | |
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | 656 | return load_ret; | |
| 335 | 1127 | } | |
| 336 | |||
| 337 | /** | ||
| 338 | * Fetch a catalog by hash either from cache or from remote. | ||
| 339 | * Successful load always returns kLoadNew (independent of the location) and | ||
| 340 | * sets the sqlite_path variable. | ||
| 341 | * | ||
| 342 | * @param [out] sqlite_path of the catalog if successfully fetched | ||
| 343 | * @return kLoadNew on success | ||
| 344 | * kLoadNoSpace out of space, no room on the device to open the catalog | ||
| 345 | * kLoadFail on all other failures | ||
| 346 | */ | ||
| 347 | 1127 | LoadReturn ClientCatalogManager::FetchCatalogByHash( | |
| 348 | const shash::Any &hash, | ||
| 349 | const string &name, | ||
| 350 | const std::string &alt_root_catalog_path, | ||
| 351 | std::string *sqlite_path) { | ||
| 352 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1127 times.
|
1127 | assert(hash.suffix == shash::kSuffixCatalog); |
| 353 | 1127 | CacheManager::Label label; | |
| 354 |
1/2✓ Branch 1 taken 1127 times.
✗ Branch 2 not taken.
|
1127 | label.path = name; |
| 355 | 1127 | label.flags = CacheManager::kLabelCatalog; | |
| 356 |
2/4✓ Branch 1 taken 1127 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1127 times.
✗ Branch 5 not taken.
|
1127 | const int fd = fetcher_->Fetch(CacheManager::LabeledObject(hash, label), |
| 357 | alt_root_catalog_path); | ||
| 358 |
2/2✓ Branch 0 taken 1078 times.
✓ Branch 1 taken 49 times.
|
1127 | if (fd >= 0) { |
| 359 |
2/2✓ Branch 0 taken 701 times.
✓ Branch 1 taken 377 times.
|
1078 | if (root_fd_ < 0) { |
| 360 | 701 | root_fd_ = fd; | |
| 361 | } | ||
| 362 | |||
| 363 |
1/2✓ Branch 1 taken 1078 times.
✗ Branch 2 not taken.
|
1078 | LogCvmfs(kLogCatalog, kLogDebug, "FetchCatalogByHash filedescriptor %d", |
| 364 | fd); | ||
| 365 |
2/4✓ Branch 1 taken 1078 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1078 times.
✗ Branch 5 not taken.
|
1078 | *sqlite_path = "@" + StringifyInt(fd); |
| 366 | 1078 | return kLoadNew; | |
| 367 | } | ||
| 368 | |||
| 369 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | if (fd == -ENOSPC) |
| 370 | ✗ | return kLoadNoSpace; | |
| 371 | |||
| 372 | 49 | return kLoadFail; | |
| 373 | 1127 | } | |
| 374 | |||
| 375 | 16 | void ClientCatalogManager::StageNestedCatalogByHash( | |
| 376 | const shash::Any &hash, const PathString &mountpoint) { | ||
| 377 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | assert(hash.suffix == shash::kSuffixCatalog); |
| 378 | |||
| 379 | 16 | CacheManager::Label label; | |
| 380 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | label.path = GetCatalogDescription(mountpoint, hash); |
| 381 | 16 | label.flags = CacheManager::kLabelCatalog; | |
| 382 |
3/6✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
|
16 | const int fd = fetcher_->Fetch(CacheManager::LabeledObject(hash, label)); |
| 383 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if (fd >= 0) |
| 384 |
1/2✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | fetcher_->cache_mgr()->Close(fd); |
| 385 | 16 | } | |
| 386 | |||
| 387 | 2 | void ClientCatalogManager::UnloadCatalog(const Catalog *catalog) { | |
| 388 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | LogCvmfs(kLogCache, kLogDebug, "unloading catalog %s", |
| 389 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | catalog->mountpoint().c_str()); |
| 390 | |||
| 391 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | const map<PathString, shash::Any>::iterator iter = mounted_catalogs_.find( |
| 392 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
4 | catalog->mountpoint()); |
| 393 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | assert(iter != mounted_catalogs_.end()); |
| 394 |
1/2✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | fetcher_->cache_mgr()->quota_mgr()->Unpin(iter->second); |
| 395 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | mounted_catalogs_.erase(iter); |
| 396 | 2 | const catalog::Counters &counters = catalog->GetCounters(); | |
| 397 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | loaded_inodes_ -= counters.GetSelfEntries(); |
| 398 | 2 | } | |
| 399 | |||
| 400 | |||
| 401 | /** | ||
| 402 | * Checks if the current repository revision is blacklisted. The format | ||
| 403 | * of the blacklist lines is '<REPO N' where REPO is the repository name, | ||
| 404 | * N is the revision number, and the two parts are separated by whitespace. | ||
| 405 | * Any revision of REPO less than N is blacklisted. | ||
| 406 | * Note: no extra characters are allowed after N, not even whitespace. | ||
| 407 | * @return true if it is blacklisted, false otherwise | ||
| 408 | */ | ||
| 409 | 701 | bool ClientCatalogManager::IsRevisionBlacklisted() { | |
| 410 | 701 | const uint64_t revision = GetRevision(); | |
| 411 | |||
| 412 |
1/2✓ Branch 2 taken 701 times.
✗ Branch 3 not taken.
|
701 | LogCvmfs(kLogCache, kLogDebug, |
| 413 | "checking if %s revision %" PRIu64 " is blacklisted", | ||
| 414 | repo_name_.c_str(), revision); | ||
| 415 | |||
| 416 |
1/2✓ Branch 1 taken 701 times.
✗ Branch 2 not taken.
|
701 | vector<string> blacklist = signature_mgr_->GetBlacklist(); |
| 417 |
2/2✓ Branch 1 taken 36 times.
✓ Branch 2 taken 665 times.
|
701 | for (unsigned i = 0; i < blacklist.size(); ++i) { |
| 418 |
1/2✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
|
36 | std::string line = blacklist[i]; |
| 419 |
2/4✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
|
36 | if (line[0] != '<') |
| 420 | ✗ | continue; | |
| 421 | 36 | unsigned idx = repo_name_.length() + 1; | |
| 422 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
|
36 | if (line.length() <= idx) |
| 423 | ✗ | continue; | |
| 424 |
3/10✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 36 times.
|
36 | if ((line[idx] != ' ') && (line[idx] != '\t')) |
| 425 | ✗ | continue; | |
| 426 |
2/4✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
|
36 | if (line.substr(1, idx - 1) != repo_name_) |
| 427 | ✗ | continue; | |
| 428 | 36 | ++idx; | |
| 429 |
5/10✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 36 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 36 times.
|
36 | while ((line[idx] == ' ') || (line[idx] == '\t')) |
| 430 | ✗ | ++idx; | |
| 431 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
|
36 | if (idx >= line.length()) |
| 432 | ✗ | continue; | |
| 433 | uint64_t rev; | ||
| 434 |
3/6✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 36 times.
|
36 | if (!String2Uint64Parse(line.substr(idx), &rev)) |
| 435 | ✗ | continue; | |
| 436 |
1/2✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
|
36 | if (revision < rev) |
| 437 | 36 | return true; | |
| 438 |
1/3✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
|
36 | } |
| 439 | |||
| 440 | 665 | return false; | |
| 441 | 701 | } | |
| 442 | |||
| 443 | |||
| 444 | //------------------------------------------------------------------------------ | ||
| 445 | |||
| 446 | |||
| 447 | 366 | void CachedManifestEnsemble::FetchCertificate(const shash::Any &hash) { | |
| 448 | 366 | CacheManager::Label label; | |
| 449 | 366 | label.flags |= CacheManager::kLabelCertificate; | |
| 450 |
1/2✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
|
366 | label.path = catalog_mgr_->repo_name(); |
| 451 | uint64_t size; | ||
| 452 |
1/2✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
|
366 | const bool retval = cache_mgr_->Open2Mem( |
| 453 |
1/2✓ Branch 1 taken 366 times.
✗ Branch 2 not taken.
|
732 | CacheManager::LabeledObject(hash, label), &cert_buf, &size); |
| 454 | 366 | cert_size = size; | |
| 455 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 364 times.
|
366 | if (retval) |
| 456 | 2 | perf::Inc(catalog_mgr_->n_certificate_hits_); | |
| 457 | else | ||
| 458 | 364 | perf::Inc(catalog_mgr_->n_certificate_misses_); | |
| 459 | 366 | } | |
| 460 | |||
| 461 | } // namespace catalog | ||
| 462 |