Directory: | cvmfs/ |
---|---|
File: | cvmfs/catalog.cc |
Date: | 2025-07-06 02:35:01 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 407 | 439 | 92.7% |
Branches: | 324 | 606 | 53.5% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #include "catalog.h" | ||
6 | |||
7 | #include <alloca.h> | ||
8 | #include <errno.h> | ||
9 | |||
10 | #include <algorithm> | ||
11 | #include <cassert> | ||
12 | |||
13 | #include "catalog_mgr.h" | ||
14 | #include "util/concurrency.h" | ||
15 | #include "util/logging.h" | ||
16 | #include "util/platform.h" | ||
17 | #include "util/smalloc.h" | ||
18 | |||
19 | using namespace std; // NOLINT | ||
20 | |||
21 | namespace catalog { | ||
22 | |||
23 | const shash::Md5 Catalog::kMd5PathEmpty("", 0); | ||
24 | |||
25 | |||
26 | /** | ||
27 | * Open a catalog outside the framework of a catalog manager. | ||
28 | */ | ||
29 | 556 | Catalog *Catalog::AttachFreely(const string &imaginary_mountpoint, | |
30 | const string &file, | ||
31 | const shash::Any &catalog_hash, | ||
32 | Catalog *parent, | ||
33 | const bool is_nested) { | ||
34 | Catalog *catalog = new Catalog( | ||
35 | 556 | PathString(imaginary_mountpoint.data(), imaginary_mountpoint.length()), | |
36 | catalog_hash, | ||
37 | parent, | ||
38 |
2/4✓ Branch 1 taken 556 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 556 times.
✗ Branch 5 not taken.
|
556 | is_nested); |
39 | 556 | const bool successful_init = catalog->InitStandalone(file); | |
40 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 517 times.
|
556 | if (!successful_init) { |
41 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | delete catalog; |
42 | 39 | return NULL; | |
43 | } | ||
44 | 517 | return catalog; | |
45 | } | ||
46 | |||
47 | |||
48 | 4391 | Catalog::Catalog(const PathString &mountpoint, | |
49 | const shash::Any &catalog_hash, | ||
50 | Catalog *parent, | ||
51 | 4391 | const bool is_nested) | |
52 | 4391 | : catalog_hash_(catalog_hash) | |
53 |
1/2✓ Branch 1 taken 4391 times.
✗ Branch 2 not taken.
|
4391 | , mountpoint_(mountpoint) |
54 |
1/2✓ Branch 1 taken 4391 times.
✗ Branch 2 not taken.
|
4391 | , is_regular_mountpoint_(mountpoint_ == root_prefix_) |
55 | 4391 | , volatile_flag_(false) | |
56 |
3/4✓ Branch 0 taken 3003 times.
✓ Branch 1 taken 1388 times.
✓ Branch 2 taken 3003 times.
✗ Branch 3 not taken.
|
4391 | , is_root_(parent == NULL && !is_nested) |
57 | 4391 | , managed_database_(false) | |
58 | 4391 | , parent_(parent) | |
59 | 4391 | , nested_catalog_cache_dirty_(true) | |
60 | 4391 | , voms_authz_status_(kVomsUnknown) | |
61 |
1/2✓ Branch 8 taken 4391 times.
✗ Branch 9 not taken.
|
8782 | , initialized_(false) { |
62 | 4391 | max_row_id_ = 0; | |
63 | 4391 | inode_annotation_ = NULL; | |
64 | 4391 | lock_ = reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t))); | |
65 | 4391 | const int retval = pthread_mutex_init(lock_, NULL); | |
66 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4391 times.
|
4391 | assert(retval == 0); |
67 | |||
68 | 4391 | database_ = NULL; | |
69 | 4391 | uid_map_ = NULL; | |
70 | 4391 | gid_map_ = NULL; | |
71 | 4391 | sql_listing_ = NULL; | |
72 | 4391 | sql_lookup_md5path_ = NULL; | |
73 | 4391 | sql_lookup_nested_ = NULL; | |
74 | 4391 | sql_list_nested_ = NULL; | |
75 | 4391 | sql_own_list_nested_ = NULL; | |
76 | 4391 | sql_all_chunks_ = NULL; | |
77 | 4391 | sql_chunks_listing_ = NULL; | |
78 | 4391 | sql_lookup_xattrs_ = NULL; | |
79 | 4391 | } | |
80 | |||
81 | |||
82 | 12004 | Catalog::~Catalog() { | |
83 | 8624 | pthread_mutex_destroy(lock_); | |
84 | 8624 | free(lock_); | |
85 | 8624 | FinalizePreparedStatements(); | |
86 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
8624 | delete database_; |
87 | 12004 | } | |
88 | |||
89 | |||
90 | /** | ||
91 | * InitPreparedStatement uses polymorphism in case of a r/w catalog. | ||
92 | * FinalizePreparedStatements is called in the destructor where | ||
93 | * polymorphism does not work any more and has to be called both in | ||
94 | * the WritableCatalog and the Catalog destructor | ||
95 | */ | ||
96 | 4085 | void Catalog::InitPreparedStatements() { | |
97 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_listing_ = new SqlListing(database()); |
98 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_lookup_md5path_ = new SqlLookupPathHash(database()); |
99 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_lookup_nested_ = new SqlNestedCatalogLookup(database()); |
100 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_list_nested_ = new SqlNestedCatalogListing(database()); |
101 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_own_list_nested_ = new SqlOwnNestedCatalogListing(database()); |
102 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_all_chunks_ = new SqlAllChunks(database()); |
103 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_chunks_listing_ = new SqlChunksListing(database()); |
104 |
1/2✓ Branch 3 taken 4085 times.
✗ Branch 4 not taken.
|
4085 | sql_lookup_xattrs_ = new SqlLookupXattrs(database()); |
105 | 4085 | } | |
106 | |||
107 | |||
108 | 4312 | void Catalog::FinalizePreparedStatements() { | |
109 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_lookup_xattrs_; |
110 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_chunks_listing_; |
111 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_all_chunks_; |
112 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_listing_; |
113 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_lookup_md5path_; |
114 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_lookup_nested_; |
115 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_list_nested_; |
116 |
2/2✓ Branch 0 taken 4008 times.
✓ Branch 1 taken 304 times.
|
4312 | delete sql_own_list_nested_; |
117 | 4312 | } | |
118 | |||
119 | |||
120 | 1390 | bool Catalog::InitStandalone(const std::string &database_file) { | |
121 |
1/2✓ Branch 1 taken 1390 times.
✗ Branch 2 not taken.
|
1390 | const bool retval = OpenDatabase(database_file); |
122 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1351 times.
|
1390 | if (!retval) { |
123 | 39 | return false; | |
124 | } | ||
125 | |||
126 | 1351 | InodeRange inode_range; | |
127 | 1351 | inode_range.MakeDummy(); | |
128 | 1351 | set_inode_range(inode_range); | |
129 | 1351 | return true; | |
130 | } | ||
131 | |||
132 | |||
133 | 5932 | bool Catalog::ReadCatalogCounters() { | |
134 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5932 times.
|
5932 | assert(database_ != NULL); |
135 | bool statistics_loaded; | ||
136 | 5932 | if (database().schema_version() < CatalogDatabase::kLatestSupportedSchema | |
137 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 5858 times.
|
5932 | - CatalogDatabase::kSchemaEpsilon) { |
138 | 74 | statistics_loaded = counters_.ReadFromDatabase(database(), | |
139 | LegacyMode::kLegacy); | ||
140 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 5858 times.
|
5858 | } else if (database().schema_revision() < 2) { |
141 | ✗ | statistics_loaded = counters_.ReadFromDatabase(database(), | |
142 | LegacyMode::kNoXattrs); | ||
143 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 5858 times.
|
5858 | } else if (database().schema_revision() < 3) { |
144 | ✗ | statistics_loaded = counters_.ReadFromDatabase(database(), | |
145 | LegacyMode::kNoExternals); | ||
146 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 5858 times.
|
5858 | } else if (database().schema_revision() < 5) { |
147 | ✗ | statistics_loaded = counters_.ReadFromDatabase(database(), | |
148 | LegacyMode::kNoSpecials); | ||
149 | } else { | ||
150 | 5858 | statistics_loaded = counters_.ReadFromDatabase(database()); | |
151 | } | ||
152 | 5932 | return statistics_loaded; | |
153 | } | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Establishes the database structures and opens the sqlite database file. | ||
158 | * @param db_path the absolute path to the database file on local file system | ||
159 | * @return true on successful initialization otherwise false | ||
160 | */ | ||
161 | 4163 | bool Catalog::OpenDatabase(const string &db_path) { | |
162 |
2/4✓ Branch 1 taken 4163 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4163 times.
✗ Branch 5 not taken.
|
4163 | database_ = CatalogDatabase::Open(db_path, DatabaseOpenMode()); |
163 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 4085 times.
|
4163 | if (NULL == database_) { |
164 | 78 | return false; | |
165 | } | ||
166 | |||
167 |
2/2✓ Branch 2 taken 74 times.
✓ Branch 3 taken 4011 times.
|
4085 | if (database_->IsEqualSchema(database_->schema_version(), 1.0)) { |
168 | // Possible fix-up for database layout lacking the content hash of | ||
169 | // nested catalogs | ||
170 | SqlCatalog sql_has_nested_sha1( | ||
171 | 74 | database(), | |
172 | "SELECT count(*) FROM sqlite_master " | ||
173 |
2/4✓ Branch 2 taken 74 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 74 times.
✗ Branch 6 not taken.
|
222 | "WHERE type='table' AND name='nested_catalogs' AND sql LIKE '%sha1%';"); |
174 |
1/2✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
|
74 | const bool retval = sql_has_nested_sha1.FetchRow(); |
175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
|
74 | assert(retval == true); |
176 |
1/2✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
|
74 | const bool has_nested_sha1 = sql_has_nested_sha1.RetrieveInt64(0); |
177 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 37 times.
|
74 | if (!has_nested_sha1) { |
178 | 37 | database_->EnforceSchema(0.9, 0); | |
179 | } | ||
180 | 74 | } | |
181 | |||
182 |
1/2✓ Branch 1 taken 4085 times.
✗ Branch 2 not taken.
|
4085 | InitPreparedStatements(); |
183 | |||
184 | // Set the database file ownership if requested | ||
185 |
2/2✓ Branch 0 taken 164 times.
✓ Branch 1 taken 3921 times.
|
4085 | if (managed_database_) { |
186 |
1/2✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
|
164 | database_->TakeFileOwnership(); |
187 | } | ||
188 | |||
189 | // Find out the maximum row id of this database file | ||
190 |
2/4✓ Branch 2 taken 4085 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 4085 times.
✗ Branch 7 not taken.
|
8170 | SqlCatalog sql_max_row_id(database(), "SELECT MAX(rowid) FROM catalog;"); |
191 |
2/4✓ Branch 1 taken 4085 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4085 times.
|
4085 | if (!sql_max_row_id.FetchRow()) { |
192 | ✗ | LogCvmfs(kLogCatalog, kLogDebug, | |
193 | "Cannot retrieve maximal row id for database file %s " | ||
194 | "(SqliteErrorcode: %d)", | ||
195 | db_path.c_str(), sql_max_row_id.GetLastError()); | ||
196 | ✗ | return false; | |
197 | } | ||
198 |
1/2✓ Branch 1 taken 4085 times.
✗ Branch 2 not taken.
|
4085 | max_row_id_ = sql_max_row_id.RetrieveInt64(0); |
199 | |||
200 | // Get root prefix | ||
201 |
4/6✓ Branch 2 taken 4085 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4085 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1458 times.
✓ Branch 10 taken 2627 times.
|
4085 | if (database_->HasProperty("root_prefix")) { |
202 | 1458 | const std::string root_prefix = database_->GetProperty<std::string>( | |
203 |
2/4✓ Branch 2 taken 1458 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1458 times.
✗ Branch 6 not taken.
|
2916 | "root_prefix"); |
204 |
1/2✓ Branch 3 taken 1458 times.
✗ Branch 4 not taken.
|
1458 | root_prefix_.Assign(root_prefix.data(), root_prefix.size()); |
205 |
1/2✓ Branch 3 taken 1458 times.
✗ Branch 4 not taken.
|
1458 | LogCvmfs(kLogCatalog, kLogDebug, |
206 | "found root prefix %s in root catalog file %s", | ||
207 | root_prefix_.c_str(), db_path.c_str()); | ||
208 |
1/2✓ Branch 1 taken 1458 times.
✗ Branch 2 not taken.
|
1458 | is_regular_mountpoint_ = (root_prefix_ == mountpoint_); |
209 | 1458 | } else { | |
210 |
1/2✓ Branch 2 taken 2627 times.
✗ Branch 3 not taken.
|
2627 | LogCvmfs(kLogCatalog, kLogDebug, "no root prefix for root catalog file %s", |
211 | db_path.c_str()); | ||
212 | } | ||
213 | |||
214 | // Get volatile content flag | ||
215 |
2/4✓ Branch 1 taken 4085 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4085 times.
✗ Branch 5 not taken.
|
4085 | volatile_flag_ = database_->GetPropertyDefault<bool>("volatile", |
216 | 4085 | volatile_flag_); | |
217 | |||
218 | // Read Catalog Counter Statistics | ||
219 |
2/4✓ Branch 1 taken 4085 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4085 times.
|
4085 | if (!ReadCatalogCounters()) { |
220 | ✗ | LogCvmfs(kLogCatalog, kLogStderr, | |
221 | "failed to load statistics counters for catalog %s (file %s)", | ||
222 | mountpoint_.c_str(), db_path.c_str()); | ||
223 | ✗ | return false; | |
224 | } | ||
225 | |||
226 |
2/2✓ Branch 1 taken 1388 times.
✓ Branch 2 taken 2697 times.
|
4085 | if (HasParent()) { |
227 |
1/2✓ Branch 1 taken 1388 times.
✗ Branch 2 not taken.
|
1388 | parent_->AddChild(this); |
228 | } | ||
229 | |||
230 | 4085 | initialized_ = true; | |
231 | 4085 | return true; | |
232 | 4085 | } | |
233 | |||
234 | |||
235 | /** | ||
236 | * Removes the mountpoint and prepends the root prefix to path | ||
237 | */ | ||
238 | 15873 | shash::Md5 Catalog::NormalizePath(const PathString &path) const { | |
239 |
2/2✓ Branch 0 taken 15689 times.
✓ Branch 1 taken 184 times.
|
15873 | if (is_regular_mountpoint_) |
240 |
1/2✓ Branch 3 taken 15689 times.
✗ Branch 4 not taken.
|
15689 | return shash::Md5(path.GetChars(), path.GetLength()); |
241 | |||
242 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 184 times.
|
184 | assert(path.GetLength() >= mountpoint_.GetLength()); |
243 | // Piecewise hash calculation: root_prefix plus tail of path | ||
244 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | shash::Any result(shash::kMd5); |
245 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | shash::ContextPtr ctx(shash::kMd5); |
246 | 184 | ctx.buffer = alloca(ctx.size); | |
247 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | shash::Init(ctx); |
248 |
1/2✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
368 | shash::Update( |
249 | 184 | reinterpret_cast<const unsigned char *>(root_prefix_.GetChars()), | |
250 | root_prefix_.GetLength(), | ||
251 | ctx); | ||
252 | 184 | shash::Update(reinterpret_cast<const unsigned char *>(path.GetChars()) | |
253 |
1/2✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
|
184 | + mountpoint_.GetLength(), |
254 | 184 | path.GetLength() - mountpoint_.GetLength(), | |
255 | ctx); | ||
256 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | shash::Final(ctx, &result); |
257 |
1/2✓ Branch 1 taken 184 times.
✗ Branch 2 not taken.
|
184 | return result.CastToMd5(); |
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Same as NormalizePath but returns a PathString instead of an Md5 hash. | ||
263 | */ | ||
264 | 1388 | PathString Catalog::NormalizePath2(const PathString &path) const { | |
265 |
2/2✓ Branch 0 taken 1232 times.
✓ Branch 1 taken 156 times.
|
1388 | if (is_regular_mountpoint_) |
266 |
1/2✓ Branch 1 taken 1232 times.
✗ Branch 2 not taken.
|
1232 | return path; |
267 | |||
268 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
|
156 | assert(path.GetLength() >= mountpoint_.GetLength()); |
269 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | PathString result = root_prefix_; |
270 |
1/2✓ Branch 2 taken 156 times.
✗ Branch 3 not taken.
|
156 | const PathString suffix = path.Suffix(mountpoint_.GetLength()); |
271 |
1/2✓ Branch 3 taken 156 times.
✗ Branch 4 not taken.
|
156 | result.Append(suffix.GetChars(), suffix.GetLength()); |
272 |
1/2✓ Branch 1 taken 156 times.
✗ Branch 2 not taken.
|
156 | return result; |
273 | 156 | } | |
274 | |||
275 | |||
276 | /** | ||
277 | * The opposite of NormalizePath: from a full path remove the root prefix and | ||
278 | * add the catalogs current mountpoint. Needed for normalized paths from the | ||
279 | * SQlite tables, such as nested catalog entry points. | ||
280 | */ | ||
281 | 1397 | PathString Catalog::PlantPath(const PathString &path) const { | |
282 |
2/2✓ Branch 0 taken 1249 times.
✓ Branch 1 taken 148 times.
|
1397 | if (is_regular_mountpoint_) |
283 |
1/2✓ Branch 1 taken 1249 times.
✗ Branch 2 not taken.
|
1249 | return path; |
284 | |||
285 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
|
148 | assert(path.GetLength() >= root_prefix_.GetLength()); |
286 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | PathString result = mountpoint_; |
287 |
1/2✓ Branch 2 taken 148 times.
✗ Branch 3 not taken.
|
148 | const PathString suffix = path.Suffix(root_prefix_.GetLength()); |
288 |
1/2✓ Branch 3 taken 148 times.
✗ Branch 4 not taken.
|
148 | result.Append(suffix.GetChars(), suffix.GetLength()); |
289 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | return result; |
290 | 148 | } | |
291 | |||
292 | |||
293 | /** | ||
294 | * Performs a lookup on this Catalog for a given MD5 path hash. | ||
295 | * @param md5path the MD5 hash of the searched path | ||
296 | * @param expand_symlink indicates if variables in symlink should be resolved | ||
297 | * @param dirent will be set to the found DirectoryEntry | ||
298 | * @return true if DirectoryEntry was successfully found, false otherwise | ||
299 | */ | ||
300 | 13706 | bool Catalog::LookupEntry(const shash::Md5 &md5path, const bool expand_symlink, | |
301 | DirectoryEntry *dirent) const { | ||
302 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13706 times.
|
13706 | assert(IsInitialized()); |
303 | |||
304 | 13706 | const MutexLockGuard m(lock_); | |
305 |
1/2✓ Branch 1 taken 13706 times.
✗ Branch 2 not taken.
|
13706 | sql_lookup_md5path_->BindPathHash(md5path); |
306 |
1/2✓ Branch 1 taken 13706 times.
✗ Branch 2 not taken.
|
13706 | const bool found = sql_lookup_md5path_->FetchRow(); |
307 |
4/4✓ Branch 0 taken 13249 times.
✓ Branch 1 taken 457 times.
✓ Branch 2 taken 13242 times.
✓ Branch 3 taken 7 times.
|
13706 | if (found && (dirent != NULL)) { |
308 |
2/4✓ Branch 1 taken 13242 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13242 times.
✗ Branch 5 not taken.
|
13242 | *dirent = sql_lookup_md5path_->GetDirent(this, expand_symlink); |
309 |
1/2✓ Branch 1 taken 13242 times.
✗ Branch 2 not taken.
|
13242 | FixTransitionPoint(md5path, dirent); |
310 | } | ||
311 |
1/2✓ Branch 1 taken 13706 times.
✗ Branch 2 not taken.
|
13706 | sql_lookup_md5path_->Reset(); |
312 | |||
313 | 13706 | return found; | |
314 | 13706 | } | |
315 | |||
316 | |||
317 | /** | ||
318 | * Performs a lookup on this Catalog for a given MD5 path hash. | ||
319 | * @param md5path the MD5 hash of the searched path | ||
320 | * @param dirent will be set to the found DirectoryEntry | ||
321 | * @return true if DirectoryEntry was successfully found, false otherwise | ||
322 | */ | ||
323 | 13669 | bool Catalog::LookupMd5Path(const shash::Md5 &md5path, | |
324 | DirectoryEntry *dirent) const { | ||
325 | 13669 | return LookupEntry(md5path, true, dirent); | |
326 | } | ||
327 | |||
328 | |||
329 | 37 | bool Catalog::LookupRawSymlink(const PathString &path, | |
330 | LinkString *raw_symlink) const { | ||
331 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | DirectoryEntry dirent; |
332 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
37 | const bool result = (LookupEntry(NormalizePath(path), false, &dirent)); |
333 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | if (result) |
334 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
37 | raw_symlink->Assign(dirent.symlink()); |
335 | 37 | return result; | |
336 | 37 | } | |
337 | |||
338 | |||
339 | 37 | bool Catalog::LookupXattrsMd5Path(const shash::Md5 &md5path, | |
340 | XattrList *xattrs) const { | ||
341 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
|
37 | assert(IsInitialized()); |
342 | |||
343 | 37 | const MutexLockGuard m(lock_); | |
344 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | sql_lookup_xattrs_->BindPathHash(md5path); |
345 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | const bool found = sql_lookup_xattrs_->FetchRow(); |
346 |
2/4✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
|
37 | if (found && (xattrs != NULL)) { |
347 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | *xattrs = sql_lookup_xattrs_->GetXattrs(); |
348 | } | ||
349 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | sql_lookup_xattrs_->Reset(); |
350 | |||
351 | 37 | return found; | |
352 | 37 | } | |
353 | |||
354 | |||
355 | /** | ||
356 | * Perform a listing of the directory with the given MD5 path hash. | ||
357 | * @param path_hash the MD5 hash of the path of the directory to list | ||
358 | * @param listing will be set to the resulting DirectoryEntryList | ||
359 | * @return true on successful listing, false otherwise | ||
360 | */ | ||
361 | 195 | bool Catalog::ListingMd5PathStat(const shash::Md5 &md5path, | |
362 | StatEntryList *listing) const { | ||
363 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
|
195 | assert(IsInitialized()); |
364 | |||
365 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | DirectoryEntry dirent; |
366 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | StatEntry entry; |
367 | |||
368 | 195 | const MutexLockGuard m(lock_); | |
369 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | sql_listing_->BindPathHash(md5path); |
370 |
3/4✓ Branch 1 taken 669 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 474 times.
✓ Branch 4 taken 195 times.
|
669 | while (sql_listing_->FetchRow()) { |
371 |
2/4✓ Branch 1 taken 474 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 474 times.
✗ Branch 5 not taken.
|
474 | dirent = sql_listing_->GetDirent(this); |
372 |
2/2✓ Branch 1 taken 37 times.
✓ Branch 2 taken 437 times.
|
474 | if (dirent.IsHidden()) |
373 | 37 | continue; | |
374 |
1/2✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
|
437 | FixTransitionPoint(md5path, &dirent); |
375 |
2/4✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 437 times.
✗ Branch 5 not taken.
|
437 | entry.name = dirent.name(); |
376 |
1/2✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
|
437 | entry.info = dirent.GetStatStructure(); |
377 |
1/2✓ Branch 1 taken 437 times.
✗ Branch 2 not taken.
|
437 | listing->PushBack(entry); |
378 | } | ||
379 |
1/2✓ Branch 1 taken 195 times.
✗ Branch 2 not taken.
|
195 | sql_listing_->Reset(); |
380 | |||
381 | 195 | return true; | |
382 | 195 | } | |
383 | |||
384 | |||
385 | /** | ||
386 | * Perform a listing of the directory with the given MD5 path hash. | ||
387 | * Returns only struct stat values | ||
388 | * @param path_hash the MD5 hash of the path of the directory to list | ||
389 | * @param listing will be set to the resulting DirectoryEntryList | ||
390 | * @param expand_symlink defines if magic symlinks should be resolved | ||
391 | * @return true on successful listing, false otherwise | ||
392 | */ | ||
393 | 1942 | bool Catalog::ListingMd5Path(const shash::Md5 &md5path, | |
394 | DirectoryEntryList *listing, | ||
395 | const bool expand_symlink) const { | ||
396 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1942 times.
|
1942 | assert(IsInitialized()); |
397 | |||
398 | 1942 | const MutexLockGuard m(lock_); | |
399 | |||
400 |
1/2✓ Branch 1 taken 1942 times.
✗ Branch 2 not taken.
|
1942 | sql_listing_->BindPathHash(md5path); |
401 |
3/4✓ Branch 1 taken 5564 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3622 times.
✓ Branch 4 taken 1942 times.
|
5564 | while (sql_listing_->FetchRow()) { |
402 |
1/2✓ Branch 1 taken 3622 times.
✗ Branch 2 not taken.
|
3622 | DirectoryEntry dirent = sql_listing_->GetDirent(this, expand_symlink); |
403 |
1/2✓ Branch 1 taken 3622 times.
✗ Branch 2 not taken.
|
3622 | FixTransitionPoint(md5path, &dirent); |
404 |
1/2✓ Branch 1 taken 3622 times.
✗ Branch 2 not taken.
|
3622 | listing->push_back(dirent); |
405 | 3622 | } | |
406 |
1/2✓ Branch 1 taken 1942 times.
✗ Branch 2 not taken.
|
1942 | sql_listing_->Reset(); |
407 | |||
408 | 1942 | return true; | |
409 | 1942 | } | |
410 | |||
411 | |||
412 | 74 | bool Catalog::AllChunksBegin() { return sql_all_chunks_->Open(); } | |
413 | |||
414 | |||
415 | 407 | bool Catalog::AllChunksNext(shash::Any *hash, | |
416 | zlib::Algorithms *compression_alg) { | ||
417 | 407 | return sql_all_chunks_->Next(hash, compression_alg); | |
418 | } | ||
419 | |||
420 | |||
421 | 74 | bool Catalog::AllChunksEnd() { return sql_all_chunks_->Close(); } | |
422 | |||
423 | |||
424 | /** | ||
425 | * Hash algorithm is given by the unchunked file. | ||
426 | * Could be figured out by a join but it is faster if the user of this | ||
427 | * method tells us. | ||
428 | */ | ||
429 | 37 | bool Catalog::ListMd5PathChunks(const shash::Md5 &md5path, | |
430 | const shash::Algorithms interpret_hashes_as, | ||
431 | FileChunkList *chunks) const { | ||
432 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
37 | assert(IsInitialized() && chunks->IsEmpty()); |
433 | |||
434 | 37 | const MutexLockGuard m(lock_); | |
435 | |||
436 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | sql_chunks_listing_->BindPathHash(md5path); |
437 |
3/4✓ Branch 1 taken 74 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 37 times.
|
74 | while (sql_chunks_listing_->FetchRow()) { |
438 |
2/4✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
37 | chunks->PushBack(sql_chunks_listing_->GetFileChunk(interpret_hashes_as)); |
439 | } | ||
440 |
1/2✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
|
37 | sql_chunks_listing_->Reset(); |
441 | |||
442 | 37 | return true; | |
443 | 37 | } | |
444 | |||
445 | |||
446 | /** | ||
447 | * Only used by the garbage collection | ||
448 | */ | ||
449 | 76 | const Catalog::HashVector &Catalog::GetReferencedObjects() const { | |
450 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
|
76 | if (!referenced_hashes_.empty()) { |
451 | ✗ | return referenced_hashes_; | |
452 | } | ||
453 | |||
454 | // retrieve all referenced content hashes of both files and file chunks | ||
455 |
1/2✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
76 | SqlListContentHashes list_content_hashes(database()); |
456 |
3/4✓ Branch 1 taken 573 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 497 times.
✓ Branch 4 taken 76 times.
|
573 | while (list_content_hashes.FetchRow()) { |
457 |
2/4✓ Branch 1 taken 497 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 497 times.
✗ Branch 5 not taken.
|
497 | referenced_hashes_.push_back(list_content_hashes.GetHash()); |
458 | } | ||
459 | |||
460 | 76 | return referenced_hashes_; | |
461 | 76 | } | |
462 | |||
463 | |||
464 | 2129 | void Catalog::TakeDatabaseFileOwnership() { | |
465 | 2129 | managed_database_ = true; | |
466 |
2/2✓ Branch 0 taken 1965 times.
✓ Branch 1 taken 164 times.
|
2129 | if (NULL != database_) { |
467 | 1965 | database_->TakeFileOwnership(); | |
468 | } | ||
469 | 2129 | } | |
470 | |||
471 | |||
472 | 39 | void Catalog::DropDatabaseFileOwnership() { | |
473 | 39 | managed_database_ = false; | |
474 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | if (NULL != database_) { |
475 | 39 | database_->DropFileOwnership(); | |
476 | } | ||
477 | 39 | } | |
478 | |||
479 | |||
480 | 615 | uint64_t Catalog::GetTTL() const { | |
481 | 615 | const MutexLockGuard m(lock_); | |
482 |
2/4✓ Branch 3 taken 615 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 615 times.
✗ Branch 7 not taken.
|
1230 | return database().GetPropertyDefault<uint64_t>("TTL", kDefaultTTL); |
483 | 615 | } | |
484 | |||
485 | |||
486 | ✗ | bool Catalog::HasExplicitTTL() const { | |
487 | ✗ | const MutexLockGuard m(lock_); | |
488 | ✗ | return database().HasProperty("TTL"); | |
489 | } | ||
490 | |||
491 | |||
492 | 1726 | bool Catalog::GetVOMSAuthz(string *authz) const { | |
493 | bool result; | ||
494 | 1726 | const MutexLockGuard m(lock_); | |
495 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1726 times.
|
1726 | if (voms_authz_status_ == kVomsPresent) { |
496 | ✗ | if (authz) { | |
497 | ✗ | *authz = voms_authz_; | |
498 | } | ||
499 | ✗ | result = true; | |
500 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1726 times.
|
1726 | } else if (voms_authz_status_ == kVomsNone) { |
501 | ✗ | result = false; | |
502 | } else { | ||
503 |
3/6✓ Branch 3 taken 1726 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1726 times.
✗ Branch 7 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1726 times.
|
1726 | if (database().HasProperty("voms_authz")) { |
504 | ✗ | voms_authz_ = database().GetProperty<string>("voms_authz"); | |
505 | ✗ | if (authz) { | |
506 | ✗ | *authz = voms_authz_; | |
507 | } | ||
508 | ✗ | voms_authz_status_ = kVomsPresent; | |
509 | } else { | ||
510 | 1726 | voms_authz_status_ = kVomsNone; | |
511 | } | ||
512 | 1726 | result = (voms_authz_status_ == kVomsPresent); | |
513 | } | ||
514 | 1726 | return result; | |
515 | 1726 | } | |
516 | |||
517 | 3688 | uint64_t Catalog::GetRevision() const { | |
518 | 3688 | const MutexLockGuard m(lock_); | |
519 |
2/4✓ Branch 3 taken 3688 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 3688 times.
✗ Branch 7 not taken.
|
7376 | return database().GetPropertyDefault<uint64_t>("revision", 0); |
520 | 3688 | } | |
521 | |||
522 | 1802 | uint64_t Catalog::GetLastModified() const { | |
523 |
1/2✓ Branch 2 taken 1802 times.
✗ Branch 3 not taken.
|
1802 | const std::string prop_name = "last_modified"; |
524 |
1/2✓ Branch 2 taken 1802 times.
✗ Branch 3 not taken.
|
1802 | return (database().HasProperty(prop_name)) |
525 |
2/4✓ Branch 0 taken 1802 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1802 times.
✗ Branch 5 not taken.
|
1802 | ? database().GetProperty<int>(prop_name) |
526 | 1802 | : 0u; | |
527 | 1802 | } | |
528 | |||
529 | |||
530 | ✗ | uint64_t Catalog::GetNumChunks() const { | |
531 | ✗ | return counters_.Get("self_regular") + counters_.Get("self_chunks"); | |
532 | } | ||
533 | |||
534 | |||
535 | 78 | uint64_t Catalog::GetNumEntries() const { | |
536 |
1/2✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
78 | const string sql = "SELECT count(*) FROM catalog;"; |
537 | |||
538 | 78 | const MutexLockGuard m(lock_); | |
539 |
1/2✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
|
78 | SqlCatalog stmt(database(), sql); |
540 |
3/6✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
|
156 | return (stmt.FetchRow()) ? stmt.RetrieveInt64(0) : 0; |
541 | 78 | } | |
542 | |||
543 | |||
544 | 76 | shash::Any Catalog::GetPreviousRevision() const { | |
545 | 76 | const MutexLockGuard m(lock_); | |
546 | 76 | const std::string hash_string = database().GetPropertyDefault<std::string>( | |
547 |
3/6✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 76 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 76 times.
✗ Branch 10 not taken.
|
152 | "previous_revision", ""); |
548 | 76 | return (!hash_string.empty()) | |
549 |
1/2✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
|
37 | ? shash::MkFromHexPtr(shash::HexPtr(hash_string), |
550 | shash::kSuffixCatalog) | ||
551 |
3/4✓ Branch 0 taken 37 times.
✓ Branch 1 taken 39 times.
✓ Branch 3 taken 39 times.
✗ Branch 4 not taken.
|
152 | : shash::Any(); |
552 | 76 | } | |
553 | |||
554 | |||
555 | 39 | string Catalog::PrintMemStatistics() const { | |
556 | 39 | sqlite::MemStatistics stats; | |
557 | { | ||
558 | 39 | const MutexLockGuard m(lock_); | |
559 |
1/2✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
|
39 | database().GetMemStatistics(&stats); |
560 | 39 | } | |
561 |
4/8✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 39 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 39 times.
✗ Branch 14 not taken.
|
78 | return string(mountpoint().GetChars(), mountpoint().GetLength()) + ": " |
562 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.lookaside_slots_used) + " / " |
563 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.lookaside_slots_max) + " slots -- " |
564 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.lookaside_hit) + " hits, " |
565 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.lookaside_miss_size) + " misses-size, " |
566 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.lookaside_miss_full) + " misses-full -- " |
567 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.page_cache_used / 1024) + " kB pages -- " |
568 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.page_cache_hit) + " hits, " |
569 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.page_cache_miss) + " misses -- " |
570 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.schema_used / 1024) + " kB schema -- " |
571 |
3/6✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 39 times.
✗ Branch 8 not taken.
|
156 | + StringifyInt(stats.stmt_used / 1024) + " kB statements"; |
572 | } | ||
573 | |||
574 | |||
575 | /** | ||
576 | * Determine the actual inode of a DirectoryEntry. | ||
577 | * The first used entry from a hardlink group deterimines the inode of the | ||
578 | * others. | ||
579 | * @param row_id the row id of a read row in the sqlite database | ||
580 | * @param hardlink_group the id of a possibly present hardlink group | ||
581 | * @return the assigned inode number | ||
582 | */ | ||
583 | 17338 | inode_t Catalog::GetMangledInode(const uint64_t row_id, | |
584 | const uint64_t hardlink_group) const { | ||
585 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17338 times.
|
17338 | assert(IsInitialized()); |
586 | |||
587 |
2/2✓ Branch 1 taken 627 times.
✓ Branch 2 taken 16711 times.
|
17338 | if (inode_range_.IsDummy()) { |
588 | 627 | return DirectoryEntry::kInvalidInode; | |
589 | } | ||
590 | |||
591 | 16711 | inode_t inode = row_id + inode_range_.offset; | |
592 | |||
593 | // Hardlinks are encoded in catalog-wide unique hard link group ids. | ||
594 | // These ids must be resolved to actual inode relationships at runtime. | ||
595 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16711 times.
|
16711 | if (hardlink_group > 0) { |
596 | ✗ | const HardlinkGroupMap::const_iterator inode_iter = hardlink_groups_.find( | |
597 | ✗ | hardlink_group); | |
598 | |||
599 | // Use cached entry if possible | ||
600 | ✗ | if (inode_iter == hardlink_groups_.end()) { | |
601 | ✗ | hardlink_groups_[hardlink_group] = inode; | |
602 | } else { | ||
603 | ✗ | inode = inode_iter->second; | |
604 | } | ||
605 | } | ||
606 | |||
607 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16711 times.
|
16711 | if (inode_annotation_) { |
608 | ✗ | inode = inode_annotation_->Annotate(inode); | |
609 | } | ||
610 | |||
611 | 16711 | return inode; | |
612 | } | ||
613 | |||
614 | |||
615 | /** | ||
616 | * Get a list of all registered nested catalogs and bind mountpoints in this | ||
617 | * catalog. | ||
618 | * @return a list of all nested catalog and bind mountpoints. | ||
619 | */ | ||
620 | 10076 | const Catalog::NestedCatalogList &Catalog::ListNestedCatalogs() const { | |
621 | 10076 | const MutexLockGuard m(lock_); | |
622 | |||
623 |
2/2✓ Branch 0 taken 2077 times.
✓ Branch 1 taken 7999 times.
|
10076 | if (nested_catalog_cache_dirty_) { |
624 |
1/2✓ Branch 2 taken 2077 times.
✗ Branch 3 not taken.
|
2077 | LogCvmfs(kLogCatalog, kLogDebug, "refreshing nested catalog cache of '%s'", |
625 |
1/2✓ Branch 1 taken 2077 times.
✗ Branch 2 not taken.
|
4154 | mountpoint().c_str()); |
626 |
3/4✓ Branch 1 taken 3047 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 970 times.
✓ Branch 4 taken 2077 times.
|
3047 | while (sql_list_nested_->FetchRow()) { |
627 |
1/2✓ Branch 1 taken 970 times.
✗ Branch 2 not taken.
|
970 | NestedCatalog nested; |
628 |
3/6✓ Branch 1 taken 970 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 970 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 970 times.
✗ Branch 8 not taken.
|
970 | nested.mountpoint = PlantPath(sql_list_nested_->GetPath()); |
629 |
1/2✓ Branch 1 taken 970 times.
✗ Branch 2 not taken.
|
970 | nested.hash = sql_list_nested_->GetContentHash(); |
630 |
1/2✓ Branch 1 taken 970 times.
✗ Branch 2 not taken.
|
970 | nested.size = sql_list_nested_->GetSize(); |
631 |
1/2✓ Branch 1 taken 970 times.
✗ Branch 2 not taken.
|
970 | nested_catalog_cache_.push_back(nested); |
632 | 970 | } | |
633 |
1/2✓ Branch 1 taken 2077 times.
✗ Branch 2 not taken.
|
2077 | sql_list_nested_->Reset(); |
634 | 2077 | nested_catalog_cache_dirty_ = false; | |
635 | } | ||
636 | |||
637 | 10076 | return nested_catalog_cache_; | |
638 | 10076 | } | |
639 | |||
640 | |||
641 | /** | ||
642 | * Get a list of all registered nested catalogs without bind mountpoints. Used | ||
643 | * for replication and garbage collection. | ||
644 | * @return a list of all nested catalogs. | ||
645 | */ | ||
646 | 843 | const Catalog::NestedCatalogList Catalog::ListOwnNestedCatalogs() const { | |
647 | 843 | NestedCatalogList result; | |
648 | |||
649 | 843 | const MutexLockGuard m(lock_); | |
650 | |||
651 |
3/4✓ Branch 1 taken 1048 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 205 times.
✓ Branch 4 taken 843 times.
|
1048 | while (sql_own_list_nested_->FetchRow()) { |
652 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | NestedCatalog nested; |
653 |
3/6✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 205 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 205 times.
✗ Branch 8 not taken.
|
205 | nested.mountpoint = PlantPath(sql_own_list_nested_->GetPath()); |
654 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | nested.hash = sql_own_list_nested_->GetContentHash(); |
655 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | nested.size = sql_own_list_nested_->GetSize(); |
656 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | result.push_back(nested); |
657 | 205 | } | |
658 |
1/2✓ Branch 1 taken 843 times.
✗ Branch 2 not taken.
|
843 | sql_own_list_nested_->Reset(); |
659 | |||
660 | 1686 | return result; | |
661 | 843 | } | |
662 | |||
663 | |||
664 | /** | ||
665 | * Drops the nested catalog cache. Usually this is only useful in subclasses | ||
666 | * that implement writable catalogs. | ||
667 | * | ||
668 | * Note: this action is _not_ secured by the catalog's mutex. If serialisation | ||
669 | * is required the subclass needs to ensure that. | ||
670 | */ | ||
671 | 1739 | void Catalog::ResetNestedCatalogCacheUnprotected() { | |
672 | 1739 | nested_catalog_cache_.clear(); | |
673 | 1739 | nested_catalog_cache_dirty_ = true; | |
674 | 1739 | } | |
675 | |||
676 | |||
677 | /** | ||
678 | * Looks for a specific registered nested catalog based on a path. | ||
679 | */ | ||
680 | 1154 | bool Catalog::FindNested(const PathString &mountpoint, shash::Any *hash, | |
681 | uint64_t *size) const { | ||
682 | 1154 | const MutexLockGuard m(lock_); | |
683 |
1/2✓ Branch 1 taken 1154 times.
✗ Branch 2 not taken.
|
1154 | const PathString normalized_mountpoint = NormalizePath2(mountpoint); |
684 |
1/2✓ Branch 1 taken 1154 times.
✗ Branch 2 not taken.
|
1154 | sql_lookup_nested_->BindSearchPath(normalized_mountpoint); |
685 |
1/2✓ Branch 1 taken 1154 times.
✗ Branch 2 not taken.
|
1154 | const bool found = sql_lookup_nested_->FetchRow(); |
686 |
3/4✓ Branch 0 taken 1110 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 1110 times.
✗ Branch 3 not taken.
|
1154 | if (found && (hash != NULL)) { |
687 |
1/2✓ Branch 1 taken 1110 times.
✗ Branch 2 not taken.
|
1110 | *hash = sql_lookup_nested_->GetContentHash(); |
688 |
1/2✓ Branch 1 taken 1110 times.
✗ Branch 2 not taken.
|
1110 | *size = sql_lookup_nested_->GetSize(); |
689 | } | ||
690 |
1/2✓ Branch 1 taken 1154 times.
✗ Branch 2 not taken.
|
1154 | sql_lookup_nested_->Reset(); |
691 | |||
692 | 1154 | return found; | |
693 | 1154 | } | |
694 | |||
695 | |||
696 | /** | ||
697 | * Sets a new object to do inode annotations (or set to NULL) | ||
698 | * The annotation object is not owned by the catalog. | ||
699 | */ | ||
700 | 2695 | void Catalog::SetInodeAnnotation(InodeAnnotation *new_annotation) { | |
701 | 2695 | const MutexLockGuard m(lock_); | |
702 | // Since annotated inodes could come back to the catalog in order to | ||
703 | // get stripped, exchanging the annotation is not allowed | ||
704 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 2695 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
2695 | assert((inode_annotation_ == NULL) || (inode_annotation_ == new_annotation)); |
705 | 2695 | inode_annotation_ = new_annotation; | |
706 | 2695 | } | |
707 | |||
708 | |||
709 | 2695 | void Catalog::SetOwnerMaps(const OwnerMap *uid_map, const OwnerMap *gid_map) { | |
710 |
2/4✓ Branch 0 taken 2695 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2695 times.
|
2695 | uid_map_ = (uid_map && uid_map->HasEffect()) ? uid_map : NULL; |
711 |
2/4✓ Branch 0 taken 2695 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2695 times.
|
2695 | gid_map_ = (gid_map && gid_map->HasEffect()) ? gid_map : NULL; |
712 | 2695 | } | |
713 | |||
714 | |||
715 | /** | ||
716 | * Add a Catalog as child to this Catalog. | ||
717 | * @param child the Catalog to define as child | ||
718 | */ | ||
719 | 1388 | void Catalog::AddChild(Catalog *child) { | |
720 |
3/7✓ Branch 1 taken 1388 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1388 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1388 times.
|
1388 | assert(NULL == FindChild(child->mountpoint())); |
721 | |||
722 | 1388 | const MutexLockGuard m(lock_); | |
723 |
2/4✓ Branch 1 taken 1388 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1388 times.
✗ Branch 5 not taken.
|
1388 | children_[child->mountpoint()] = child; |
724 | 1388 | child->set_parent(this); | |
725 | 1388 | } | |
726 | |||
727 | |||
728 | /** | ||
729 | * Removes a Catalog from the children list of this Catalog | ||
730 | * @param child the Catalog to delete as child | ||
731 | */ | ||
732 | 967 | void Catalog::RemoveChild(Catalog *child) { | |
733 |
3/7✓ Branch 1 taken 967 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 967 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 967 times.
|
967 | assert(NULL != FindChild(child->mountpoint())); |
734 | |||
735 | 967 | const MutexLockGuard m(lock_); | |
736 | 967 | child->set_parent(NULL); | |
737 |
2/4✓ Branch 1 taken 967 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 967 times.
✗ Branch 5 not taken.
|
967 | children_.erase(child->mountpoint()); |
738 | 967 | } | |
739 | |||
740 | |||
741 | 3896 | CatalogList Catalog::GetChildren() const { | |
742 | 3896 | CatalogList result; | |
743 | |||
744 | 3896 | const MutexLockGuard m(lock_); | |
745 | 7792 | for (NestedCatalogMap::const_iterator i = children_.begin(), | |
746 | 3896 | iEnd = children_.end(); | |
747 |
2/2✓ Branch 1 taken 1553 times.
✓ Branch 2 taken 3896 times.
|
5449 | i != iEnd; |
748 | 1553 | ++i) { | |
749 |
1/2✓ Branch 2 taken 1553 times.
✗ Branch 3 not taken.
|
1553 | result.push_back(i->second); |
750 | } | ||
751 | |||
752 | 7792 | return result; | |
753 | 3896 | } | |
754 | |||
755 | |||
756 | /** | ||
757 | * Find the nested catalog that serves the given path. | ||
758 | * It might be possible that the path is in fact served by a child of the found | ||
759 | * nested catalog. | ||
760 | * @param path the path to find a best fitting catalog for | ||
761 | * @return a pointer to the best fitting child or NULL if it does not fit at all | ||
762 | */ | ||
763 | 10633 | Catalog *Catalog::FindSubtree(const PathString &path) const { | |
764 | // Check if this catalog fits the beginning of the path. | ||
765 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 10633 times.
|
10633 | if (!path.StartsWith(mountpoint_)) |
766 | ✗ | return NULL; | |
767 | |||
768 |
1/2✓ Branch 2 taken 10633 times.
✗ Branch 3 not taken.
|
10633 | PathString remaining(path.Suffix(mountpoint_.GetLength())); |
769 |
1/2✓ Branch 1 taken 10633 times.
✗ Branch 2 not taken.
|
10633 | remaining.Append("/", 1); |
770 | |||
771 | // now we recombine the path elements successively | ||
772 | // in order to find a child which serves a part of the path | ||
773 |
1/2✓ Branch 1 taken 10633 times.
✗ Branch 2 not taken.
|
10633 | PathString path_prefix(mountpoint_); |
774 | 10633 | Catalog *result = NULL; | |
775 | // Skip the first '/' | ||
776 |
1/2✓ Branch 1 taken 10633 times.
✗ Branch 2 not taken.
|
10633 | path_prefix.Append("/", 1); |
777 | 10633 | const char *c = remaining.GetChars() + 1; | |
778 |
2/2✓ Branch 1 taken 89706 times.
✓ Branch 2 taken 9268 times.
|
98974 | for (unsigned i = 1; i < remaining.GetLength(); ++i, ++c) { |
779 |
2/2✓ Branch 0 taken 20230 times.
✓ Branch 1 taken 69476 times.
|
89706 | if (*c == '/') { |
780 |
1/2✓ Branch 1 taken 20230 times.
✗ Branch 2 not taken.
|
20230 | result = FindChild(path_prefix); |
781 | |||
782 | // If we found a child serving a part of the path we can stop searching. | ||
783 | // Remaining sub path elements are possibly served by a grand child. | ||
784 |
2/2✓ Branch 0 taken 1365 times.
✓ Branch 1 taken 18865 times.
|
20230 | if (result != NULL) |
785 | 1365 | break; | |
786 | } | ||
787 |
1/2✓ Branch 1 taken 88341 times.
✗ Branch 2 not taken.
|
88341 | path_prefix.Append(c, 1); |
788 | } | ||
789 | |||
790 | 10633 | return result; | |
791 | 10633 | } | |
792 | |||
793 | |||
794 | /** | ||
795 | * Looks for a child catalog, which is a subset of all registered nested | ||
796 | * catalogs. | ||
797 | */ | ||
798 | 22687 | Catalog *Catalog::FindChild(const PathString &mountpoint) const { | |
799 | 22687 | NestedCatalogMap::const_iterator nested_iter; | |
800 | |||
801 | 22687 | const MutexLockGuard m(lock_); | |
802 |
1/2✓ Branch 1 taken 22687 times.
✗ Branch 2 not taken.
|
22687 | nested_iter = children_.find(mountpoint); |
803 |
2/2✓ Branch 2 taken 20309 times.
✓ Branch 3 taken 2378 times.
|
25065 | Catalog *result = (nested_iter == children_.end()) ? NULL |
804 | 2378 | : nested_iter->second; | |
805 | |||
806 | 22687 | return result; | |
807 | 22687 | } | |
808 | |||
809 | |||
810 | /** | ||
811 | * For the transition points for nested catalogs and bind mountpoints, the inode | ||
812 | * is ambiguous. It has to be set to the parent inode because nested catalogs | ||
813 | * are lazily loaded. | ||
814 | * @param md5path the MD5 hash of the entry to check | ||
815 | * @param dirent the DirectoryEntry to perform coherence fixes on | ||
816 | */ | ||
817 | 17301 | void Catalog::FixTransitionPoint(const shash::Md5 &md5path, | |
818 | DirectoryEntry *dirent) const { | ||
819 |
2/2✓ Branch 1 taken 13857 times.
✓ Branch 2 taken 3444 times.
|
17301 | if (!HasParent()) |
820 | 13857 | return; | |
821 | |||
822 |
2/2✓ Branch 1 taken 232 times.
✓ Branch 2 taken 3212 times.
|
3444 | if (dirent->IsNestedCatalogRoot()) { |
823 | // Normal nested catalog | ||
824 |
1/2✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
|
232 | DirectoryEntry parent_dirent; |
825 |
1/2✓ Branch 1 taken 232 times.
✗ Branch 2 not taken.
|
232 | const bool retval = parent_->LookupMd5Path(md5path, &parent_dirent); |
826 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 232 times.
|
232 | assert(retval); |
827 | 232 | dirent->set_inode(parent_dirent.inode()); | |
828 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 3212 times.
|
3444 | } else if (md5path == kMd5PathEmpty) { |
829 | // Bind mountpoint | ||
830 | ✗ | DirectoryEntry parent_dirent; | |
831 | ✗ | const bool retval = parent_->LookupPath(mountpoint_, &parent_dirent); | |
832 | ✗ | assert(retval); | |
833 | ✗ | dirent->set_inode(parent_dirent.inode()); | |
834 | } | ||
835 | } | ||
836 | |||
837 | } // namespace catalog | ||
838 |