GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/catalog_mgr.h Lines: 53 61 86.9 %
Date: 2019-02-03 02:48:13 Branches: 8 14 57.1 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#ifndef CVMFS_CATALOG_MGR_H_
6
#define CVMFS_CATALOG_MGR_H_
7
8
#ifndef __STDC_FORMAT_MACROS
9
#define __STDC_FORMAT_MACROS
10
#endif
11
12
#include <inttypes.h>
13
#include <pthread.h>
14
15
#include <cassert>
16
#include <map>
17
#include <string>
18
#include <vector>
19
20
#include "atomic.h"
21
#include "catalog.h"
22
#include "directory_entry.h"
23
#include "file_chunk.h"
24
#include "hash.h"
25
#include "logging.h"
26
#include "statistics.h"
27
28
class XattrList;
29
30
namespace catalog {
31
32
const unsigned kSqliteMemPerThread = 1*1024*1024;
33
34
/**
35
 * Lookup a directory entry including its parent entry or not.
36
 */
37
enum LookupOptions {
38
  kLookupSole        = 0x01,
39
  // kLookupFull        = 0x02  not used anymore
40
  kLookupRawSymlink  = 0x10,
41
};
42
43
44
/**
45
 * Results upon loading a catalog file.
46
 */
47
enum LoadError {
48
  kLoadNew = 0,
49
  kLoadUp2Date,
50
  kLoadNoSpace,
51
  kLoadFail,
52
53
  kLoadNumEntries
54
};
55
56
11
inline const char *Code2Ascii(const LoadError error) {
57
  const char *texts[kLoadNumEntries + 1];
58
11
  texts[0] = "loaded new catalog";
59
11
  texts[1] = "catalog was up to date";
60
11
  texts[2] = "not enough space to load catalog";
61
11
  texts[3] = "failed to load catalog";
62
11
  texts[4] = "no text";
63
11
  return texts[error];
64
}
65
66
67
struct Statistics {
68
  perf::Counter *n_lookup_inode;
69
  perf::Counter *n_lookup_path;
70
  perf::Counter *n_lookup_path_negative;
71
  perf::Counter *n_lookup_xattrs;
72
  perf::Counter *n_listing;
73
  perf::Counter *n_nested_listing;
74
75
84
  explicit Statistics(perf::Statistics *statistics) {
76
    n_lookup_inode = statistics->Register("catalog_mgr.n_lookup_inode",
77
84
        "Number of inode lookups");
78
    n_lookup_path = statistics->Register("catalog_mgr.n_lookup_path",
79
84
        "Number of path lookups");
80
    n_lookup_path_negative = statistics->Register(
81
        "catalog_mgr.n_lookup_path_negative",
82
84
        "Number of negative path lookups");
83
    n_lookup_xattrs = statistics->Register("catalog_mgr.n_lookup_xattrs",
84
84
        "Number of xattrs lookups");
85
    n_listing = statistics->Register("catalog_mgr.n_listing",
86
84
        "Number of listings");
87
    n_nested_listing = statistics->Register("catalog_mgr.n_nested_listing",
88
84
        "Number of listings of nested catalogs");
89
84
  }
90
};
91
92
93
class InodeGenerationAnnotation : public InodeAnnotation {
94
 public:
95
58
  InodeGenerationAnnotation() { inode_offset_ = 0; }
96
115
  ~InodeGenerationAnnotation() { }
97
  bool ValidInode(const uint64_t inode) {
98
    return inode >= inode_offset_;
99
  }
100
1
  inode_t Annotate(const inode_t raw_inode) {
101
1
    return raw_inode + inode_offset_;
102
  }
103
  inode_t Strip(const inode_t annotated_inode) {
104
    return annotated_inode - inode_offset_;
105
  }
106
1
  void IncGeneration(const uint64_t by) {
107
1
    inode_offset_ += by;
108
    LogCvmfs(kLogCatalog, kLogDebug, "set inode generation to %lu",
109
1
             inode_offset_);
110
1
  }
111
36
  inode_t GetGeneration() { return inode_offset_; }
112
113
 private:
114
  uint64_t inode_offset_;
115
};
116
117
template <class CatalogT>
118
class AbstractCatalogManager;
119
120
121
/**
122
 * This class provides the read-only interface to a tree of catalogs
123
 * representing a (subtree of a) repository.
124
 * Mostly lookup functions filling DirectoryEntry objects.
125
 * Reloading of expired catalogs, attaching of nested catalogs and delegating
126
 * of lookups to the appropriate catalog is done transparently.
127
 *
128
 * The loading / creating of catalogs is up to derived classes.
129
 *
130
 * CatalogT is either Catalog or MockCatalog.
131
 *
132
 * Usage:
133
 *   DerivedCatalogManager *catalog_manager = new DerivedCatalogManager();
134
 *   catalog_manager->Init();
135
 *   catalog_manager->Lookup(<inode>, &<result_entry>);
136
 */
137
template <class CatalogT>
138
class AbstractCatalogManager : public SingleCopy {
139
 public:
140
  typedef std::vector<CatalogT*> CatalogList;
141
  typedef CatalogT catalog_t;
142
143
  static const inode_t kInodeOffset = 255;
144
  explicit AbstractCatalogManager(perf::Statistics *statistics);
145
  virtual ~AbstractCatalogManager();
146
147
  void SetInodeAnnotation(InodeAnnotation *new_annotation);
148
  virtual bool Init();
149
  LoadError Remount(const bool dry_run);
150
  void DetachNested();
151
152
  bool LookupPath(const PathString &path, const LookupOptions options,
153
                  DirectoryEntry *entry);
154
15
  bool LookupPath(const std::string &path, const LookupOptions options,
155
                  DirectoryEntry *entry)
156
  {
157
15
    PathString p;
158
15
    p.Assign(&path[0], path.length());
159
15
    return LookupPath(p, options, entry);
160
  }
161
  bool LookupXattrs(const PathString &path, XattrList *xattrs);
162
163
  bool LookupNested(const PathString &path,
164
                    PathString *mountpoint,
165
                    shash::Any *hash,
166
                    uint64_t *size);
167
  bool ListCatalogSkein(const PathString &path,
168
                        std::vector<PathString> *result_list);
169
170
  bool Listing(const PathString &path, DirectoryEntryList *listing);
171
17
  bool Listing(const std::string &path, DirectoryEntryList *listing) {
172
17
    PathString p;
173
17
    p.Assign(&path[0], path.length());
174
17
    return Listing(p, listing);
175
  }
176
  bool ListingStat(const PathString &path, StatEntryList *listing);
177
178
  bool ListFileChunks(const PathString &path,
179
                      const shash::Algorithms interpret_hashes_as,
180
                      FileChunkList *chunks);
181
  void SetOwnerMaps(const OwnerMap &uid_map, const OwnerMap &gid_map);
182
  void SetCatalogWatermark(unsigned limit);
183
184
  shash::Any GetNestedCatalogHash(const PathString &mountpoint);
185
186
1
  Statistics statistics() const { return statistics_; }
187
  uint64_t inode_gauge() {
188
    ReadLock(); uint64_t r = inode_gauge_; Unlock(); return r;
189
  }
190
38
  bool volatile_flag() const { return volatile_flag_; }
191
  uint64_t GetRevision() const;
192
  uint64_t GetTTL() const;
193
  bool HasExplicitTTL() const;
194
  bool GetVOMSAuthz(std::string *authz) const;
195
  int GetNumCatalogs() const;
196
  std::string PrintHierarchy() const;
197
  std::string PrintAllMemStatistics() const;
198
199
  /**
200
   * Get the inode number of the root DirectoryEntry
201
   * ('root' means the root of the whole file system)
202
   * @return the root inode number
203
   */
204
2
  inline inode_t GetRootInode() const {
205
    return inode_annotation_ ?
206
2
      inode_annotation_->Annotate(kInodeOffset + 1) : kInodeOffset + 1;
207
  }
208
290
  inline CatalogT* GetRootCatalog() const { return catalogs_.front(); }
209
  /**
210
   * Inodes are ambiquitous under some circumstances, to prevent problems
211
   * they must be passed through this method first
212
   * @param inode the raw inode
213
   * @return the revised inode
214
   */
215
  inline inode_t MangleInode(const inode_t inode) const {
216
    return (inode <= kInodeOffset) ? GetRootInode() : inode;
217
  }
218
219
 protected:
220
  /**
221
   * Load the catalog and return a file name and the catalog hash. Derived
222
   * class can decide if it wants to use the hash or the path.
223
   * Both the input as well as the output hash can be 0.
224
   */
225
  virtual LoadError LoadCatalog(const PathString &mountpoint,
226
                                const shash::Any &hash,
227
                                std::string  *catalog_path,
228
                                shash::Any   *catalog_hash) = 0;
229
98
  virtual void UnloadCatalog(const CatalogT *catalog) { }
230
31
  virtual void ActivateCatalog(CatalogT *catalog) { }
231
1
  const std::vector<CatalogT*>& GetCatalogs() const { return catalogs_; }
232
233
  /**
234
   * Create a new Catalog object.
235
   * Every derived class has to implement this and return a newly
236
   * created (derived) Catalog structure of it's desired type.
237
   * @param mountpoint      the future mountpoint of the catalog to create
238
   * @param catalog_hash    the content hash of the catalog database
239
   * @param parent_catalog  the parent of the catalog to create
240
   * @return a newly created (derived) Catalog
241
   */
242
  virtual CatalogT* CreateCatalog(const PathString  &mountpoint,
243
                                  const shash::Any  &catalog_hash,
244
                                  CatalogT *parent_catalog) = 0;
245
246
  CatalogT *MountCatalog(const PathString &mountpoint, const shash::Any &hash,
247
                         CatalogT *parent_catalog);
248
  bool MountSubtree(const PathString &path, const CatalogT *entry_point,
249
                    CatalogT **leaf_catalog);
250
251
  bool AttachCatalog(const std::string &db_path, CatalogT *new_catalog);
252
  void DetachCatalog(CatalogT *catalog);
253
  void DetachSubtree(CatalogT *catalog);
254
  void DetachSiblings(const PathString &current_tree);
255
85
  void DetachAll() { if (!catalogs_.empty()) DetachSubtree(GetRootCatalog()); }
256
  bool IsAttached(const PathString &root_path,
257
                  CatalogT **attached_catalog) const;
258
259
  CatalogT *FindCatalog(const PathString &path) const;
260
261
178
  inline void ReadLock() const {
262
178
    int retval = pthread_rwlock_rdlock(rwlock_);
263
178
    assert(retval == 0);
264
178
  }
265
97
  inline void WriteLock() const {
266
97
    int retval = pthread_rwlock_wrlock(rwlock_);
267
97
    assert(retval == 0);
268
97
  }
269
275
  inline void Unlock() const {
270
275
    int retval = pthread_rwlock_unlock(rwlock_);
271
275
    assert(retval == 0);
272
275
  }
273
  virtual void EnforceSqliteMemLimit();
274
275
 private:
276
  void CheckInodeWatermark();
277
278
  /**
279
   * The flat list of all attached catalogs.
280
   */
281
  CatalogList catalogs_;
282
  int inode_watermark_status_;  /**< 0: OK, 1: > 32bit */
283
  uint64_t inode_gauge_;  /**< highest issued inode */
284
  uint64_t revision_cache_;
285
  /**
286
   * Try to keep number of nested catalogs below the given limit. Zero means no
287
   * limit. Surpassing the watermark on mounting a catalog triggers
288
   * a DetachSiblings() call.
289
   */
290
  unsigned catalog_watermark_;
291
  /**
292
   * Not protected by a read lock because it can only change when the root
293
   * catalog is exchanged (during big global lock of the file system).
294
   */
295
  bool volatile_flag_;
296
  /**
297
   * Saves the result of GetVOMSAuthz when a root catalog is attached
298
   */
299
  bool has_authz_cache_;
300
  /**
301
   * Saves the VOMS requirements when a root catalog is attached
302
   */
303
  std::string authz_cache_;
304
  /**
305
   * Counts how often the inodes have been invalidated.
306
   */
307
  uint64_t incarnation_;
308
  // TODO(molina) we could just add an atomic global counter instead
309
  InodeAnnotation *inode_annotation_;  /**< applied to all catalogs */
310
  pthread_rwlock_t *rwlock_;
311
  Statistics statistics_;
312
  pthread_key_t pkey_sqlitemem_;
313
  OwnerMap uid_map_;
314
  OwnerMap gid_map_;
315
316
  // Not needed anymore since there are the glue buffers
317
  // Catalog *Inode2Catalog(const inode_t inode);
318
  std::string PrintHierarchyRecursively(const CatalogT *catalog,
319
                                        const int level) const;
320
  std::string PrintMemStatsRecursively(const CatalogT *catalog) const;
321
322
  InodeRange AcquireInodes(uint64_t size);
323
  void ReleaseInodes(const InodeRange chunk);
324
};  // class CatalogManager
325
326
}  // namespace catalog
327
328
#include "catalog_mgr_impl.h"
329
330
#endif  // CVMFS_CATALOG_MGR_H_