GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog_mgr_rw.h
Date: 2025-05-11 02:35:43
Exec Total Coverage
Lines: 10 18 55.6%
Branches: 2 8 25.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 *
4 * A WritableCatalogManager adds write functionality to the catalog
5 * manager. It is used for the server side of CVMFS
6 * All nested catalog loading functionality is inherited from
7 * AbstractCatalogManager.
8 *
9 * The WritableCatalogManager is provided with DirectoryEntryBase objects from
10 * the underlying sync infrastructure (namely SyncMediator) on the server side
11 * of CVMFS. In contrast to a full DirectoryEntry object DirectoryEntryBase con-
12 * tains only pure file system specific meta data (i.e. mtime, mode, filename).
13 * WritableCatalogManager is responsible for the addition and management of all
14 * CVMFS-specific meta data in a full DirectoryEntry, which is then saved into
15 * the actual Catalog databases.
16 *
17 * The inode assignment is based on the fact that the number of entries in a
18 * catalog do not change (except on reload). As we do exactly that with the
19 * WritableCatalogManager here, inode numbers derived from WritableCatalogs
20 * and the WritableCatalogManager may (and will) be screwed. This is not an
21 * issue in the current implementation, as they are not used in the syncing
22 * process. Just keep in mind.
23 *
24 * The WritableCatalogManager starts with a base repository (given by the
25 * root hash), and downloads and uncompresses all required catalogs into
26 * temporary storage.
27 */
28
29 #ifndef CVMFS_CATALOG_MGR_RW_H_
30 #define CVMFS_CATALOG_MGR_RW_H_
31
32 #include <pthread.h>
33 #include <stdint.h>
34
35 #include <map>
36 #include <set>
37 #include <string>
38
39 #include "catalog_mgr_ro.h"
40 #include "catalog_rw.h"
41 #include "file_chunk.h"
42 #include "upload_spooler_result.h"
43 #include "util/future.h"
44 #include "xattr.h"
45
46 class XattrList;
47 namespace upload {
48 class Spooler;
49 }
50
51 namespace download {
52 class DownloadManager;
53 }
54
55 namespace manifest {
56 class Manifest;
57 }
58
59 namespace perf {
60 class Statistics;
61 }
62
63 namespace catalog {
64 template <class CatalogMgrT>
65 class CatalogBalancer;
66 }
67
68 namespace catalog {
69
70 class WritableCatalogManager : public SimpleCatalogManager {
71 friend class CatalogBalancer<WritableCatalogManager>;
72 // TODO(jblomer): only needed to get Spooler's hash algorithm. Remove me
73 // after refactoring of the swissknife utility.
74 friend class VirtualCatalog;
75
76 public:
77 WritableCatalogManager(const shash::Any &base_hash,
78 const std::string &stratum0,
79 const std::string &dir_temp,
80 upload::Spooler *spooler,
81 download::DownloadManager *download_manager,
82 bool enforce_limits,
83 const unsigned nested_kcatalog_limit,
84 const unsigned root_kcatalog_limit,
85 const unsigned file_mbyte_limit,
86 perf::Statistics *statistics,
87 bool is_balanceable,
88 unsigned max_weight,
89 unsigned min_weight,
90 const std::string &dir_cache = "");
91 ~WritableCatalogManager();
92 static manifest::Manifest *CreateRepository(const std::string &dir_temp,
93 const bool volatile_content,
94 const std::string &voms_authz,
95 upload::Spooler *spooler);
96
97 // DirectoryEntry handling
98 157 void AddFile(const DirectoryEntryBase &entry,
99 const XattrList &xattrs,
100 const std::string &parent_directory)
101 {
102
1/2
✓ Branch 2 taken 157 times.
✗ Branch 3 not taken.
157 AddFile(DirectoryEntry(entry), xattrs, parent_directory);
103 157 }
104 void AddChunkedFile(const DirectoryEntryBase &entry,
105 const XattrList &xattrs,
106 const std::string &parent_directory,
107 const FileChunkList &file_chunks);
108 void RemoveFile(const std::string &file_path);
109
110 void AddDirectory(const DirectoryEntryBase &entry,
111 const XattrList &xattrs,
112 const std::string &parent_directory);
113 void TouchDirectory(const DirectoryEntryBase &entry,
114 const XattrList &xattrs,
115 const std::string &directory_path);
116 void RemoveDirectory(const std::string &directory_path);
117
118 void Clone(const std::string from, const std::string to);
119 void CloneTree(const std::string &from_dir, const std::string &to_dir);
120
121 // Hardlink group handling
122 void AddHardlinkGroup(const DirectoryEntryBaseList &entries,
123 const XattrList &xattrs,
124 const std::string &parent_directory,
125 const FileChunkList &file_chunks);
126 void ShrinkHardlinkGroup(const std::string &remove_path);
127
128 // Nested catalog handling
129 void CreateNestedCatalog(const std::string &mountpoint);
130 void RemoveNestedCatalog(const std::string &mountpoint,
131 const bool merge = true);
132 void SwapNestedCatalog(const string &mountpoint, const shash::Any &new_hash,
133 const uint64_t new_size);
134 void GraftNestedCatalog(const string &mountpoint, const shash::Any &new_hash,
135 const uint64_t new_size);
136 bool IsTransitionPoint(const std::string &mountpoint);
137 WritableCatalog *GetHostingCatalog(const std::string &path);
138
139 inline bool IsBalanceable() const { return is_balanceable_; }
140 /**
141 * TODO
142 */
143 void PrecalculateListings();
144
145 void SetTTL(const uint64_t new_ttl);
146 bool SetVOMSAuthz(const std::string &voms_authz);
147 bool Commit(const bool stop_for_tweaks,
148 const uint64_t manual_revision,
149 manifest::Manifest *manifest);
150
151 void Balance() {
152 if (IsBalanceable()) {
153 DoBalance();
154 } else {
155 LogCvmfs(kLogCatalog, kLogVerboseMsg, "Not balancing the catalog "
156 "manager because it is not balanceable");
157 }
158 }
159
160 protected:
161 55 void EnforceSqliteMemLimit() { }
162
163 Catalog *CreateCatalog(const PathString &mountpoint,
164 const shash::Any &catalog_hash,
165 Catalog *parent_catalog);
166 void ActivateCatalog(Catalog *catalog);
167
168 void AddFile(const DirectoryEntry &entry,
169 const XattrList &xattrs,
170 const std::string &parent_directory);
171
172 private:
173 bool FindCatalog(const std::string &path,
174 WritableCatalog **result,
175 DirectoryEntry *dirent = NULL);
176 void DoBalance();
177 void FixWeight(WritableCatalog *catalog);
178
179 void CloneTreeImpl(const PathString &source_dir,
180 const std::string &dest_parent_dir,
181 const NameString &dest_name);
182
183 struct CatalogInfo {
184 uint64_t ttl;
185 size_t size;
186 shash::Any content_hash;
187 uint64_t revision;
188 };
189
190 struct CatalogUploadContext {
191 Future<CatalogInfo>* root_catalog_info;
192 bool stop_for_tweaks;
193 };
194
195 CatalogInfo SnapshotCatalogs(const bool stop_for_tweaks);
196 void FinalizeCatalog(WritableCatalog *catalog,
197 const bool stop_for_tweaks);
198 void ScheduleCatalogProcessing(WritableCatalog *catalog);
199
200 22 void GetModifiedCatalogLeafs(WritableCatalogList *result) const {
201 22 const bool dirty = GetModifiedCatalogLeafsRecursively(GetRootCatalog(),
202 result);
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 assert(dirty);
204 22 }
205 bool GetModifiedCatalogLeafsRecursively(Catalog *catalog,
206 WritableCatalogList *result) const;
207
208 void CatalogUploadCallback(const upload::SpoolerResult &result,
209 const CatalogUploadContext clg_upload_context);
210
211 bool CopyCatalogToLocalCache(const upload::SpoolerResult &result);
212
213 private:
214 436 inline void SyncLock() { pthread_mutex_lock(sync_lock_); }
215 435 inline void SyncUnlock() { pthread_mutex_unlock(sync_lock_); }
216
217 //****************************************************************************
218 // Workaround -- Serialized Catalog Committing
219 void GetModifiedCatalogs(WritableCatalogList *result) const {
220 const unsigned int number_of_dirty_catalogs =
221 GetModifiedCatalogsRecursively(GetRootCatalog(), result);
222 assert(number_of_dirty_catalogs <= result->size());
223 }
224 int GetModifiedCatalogsRecursively(const Catalog *catalog,
225 WritableCatalogList *result) const;
226 void CatalogUploadSerializedCallback(
227 const upload::SpoolerResult &result,
228 const CatalogUploadContext unused);
229 CatalogInfo SnapshotCatalogsSerialized(const bool stop_for_tweaks);
230 //****************************************************************************
231
232 // defined in catalog_mgr_rw.cc
233 static const std::string kCatalogFilename;
234
235 // private lock of WritableCatalogManager
236 pthread_mutex_t *sync_lock_;
237 upload::Spooler *spooler_;
238
239 pthread_mutex_t *catalog_processing_lock_;
240 std::map<std::string, WritableCatalog*> catalog_processing_map_;
241
242 // TODO(jblomer): catalog limits should become its own struct
243 bool enforce_limits_;
244 unsigned nested_kcatalog_limit_;
245 unsigned root_kcatalog_limit_;
246 unsigned file_mbyte_limit_;
247
248 /**
249 * Directories don't have extended attributes at this point.
250 */
251 XattrList empty_xattrs;
252
253 /**
254 * It indicates whether this catalog manager supports balancing operations
255 */
256 const bool is_balanceable_;
257
258 /**
259 * Defines the maximum weight an autogenerated catalog can have. If after a
260 * publishing operation the catalog's weight is greater than this threshold it
261 * will be considered overflowed and will automatically be split in different
262 * sub-catalogs.
263 */
264 const unsigned max_weight_;
265
266 /**
267 * Defines the minimum weight an autogenerated catalog can have. If after a
268 * publishing operation the catalog's weight is lesser than this threshold it
269 * will be considered underflowed and will automatically be merged with its
270 * parent.
271 * This last operation can provoke an overflow in the parent, though.
272 */
273 const unsigned min_weight_;
274
275 /**
276 * Defines the threshold that will be used to balance a catalog that has been
277 * overflowed. Its value should be lesser than max_weight_ and greater than
278 * min_weight. By default it is set to max_weight / 2.
279 */
280 const unsigned balance_weight_;
281 }; // class WritableCatalogManager
282
283 } // namespace catalog
284
285 #endif // CVMFS_CATALOG_MGR_RW_H_
286