GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/cache_posix.h
Date: 2026-08-09 02:40:25
Exec Total Coverage
Lines: 30 35 85.7%
Branches: 6 12 50.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_CACHE_POSIX_H_
6 #define CVMFS_CACHE_POSIX_H_
7
8 #include <pthread.h>
9 #include <stdint.h>
10 #include <sys/types.h>
11
12 #include <string>
13
14 #include "cache.h"
15 #include "util/pointer.h"
16 #include "duplex_testing.h"
17 #include "fd_refcount_mgr.h"
18 #include "manifest_fetch.h"
19 #include "util/atomic.h"
20
21 namespace catalog {
22 class DirectoryEntry;
23 class Catalog;
24 } // namespace catalog
25
26 namespace download {
27 class DownloadManager;
28 }
29
30 /**
31 * Cache manager implementation using a file system (cache directory) as a
32 * backing storage.
33 */
34 class ListOpenHashesMagicXattr; // FD needed to access fd_mgr_
35 class PosixCacheManager : public CacheManager {
36 FRIEND_TEST(T_CacheManager, CommitTxnQuotaNotifications);
37 FRIEND_TEST(T_CacheManager, CommitTxnRenameFail);
38 FRIEND_TEST(T_CacheManager, Open);
39 FRIEND_TEST(T_CacheManager, OpenFromTxn);
40 FRIEND_TEST(T_CacheManager, OpenPinned);
41 FRIEND_TEST(T_CacheManager, Rename);
42 FRIEND_TEST(T_CacheManager, StartTxn);
43 FRIEND_TEST(T_CacheManager, TearDown2ReadOnly);
44 friend class ListOpenHashesMagicXattr;
45
46 public:
47 enum CacheModes {
48 kCacheReadWrite = 0,
49 kCacheReadOnly,
50 };
51
52 enum RenameWorkarounds {
53 kRenameNormal = 0,
54 kRenameLink,
55 kRenameSamedir
56 };
57
58 /**
59 * As of 25M, a file is considered a "big file", which means it is dangerous
60 * to apply asynchronous semantics. On start of a transaction with a big file
61 * the cache is cleaned up opportunistically.
62 */
63 static const uint64_t kBigFile;
64
65 1284 virtual CacheManagerIds id() { return kPosixCacheManager; }
66 virtual std::string Describe();
67
68 static PosixCacheManager *Create(
69 const std::string &cache_path, const bool alien_cache,
70 const RenameWorkarounds rename_workaround = kRenameNormal,
71 const bool do_refcount = true, const bool cleanup_unused_first = false);
72 22684 virtual ~PosixCacheManager() { pthread_mutex_destroy(&lock_cache_dirs_); }
73 virtual bool AcquireQuotaManager(QuotaManager *quota_mgr);
74
75 virtual int Open(const LabeledObject &object);
76 virtual int64_t GetSize(int fd);
77 virtual int Close(int fd);
78 virtual int64_t Pread(int fd, void *buf, uint64_t size, uint64_t offset);
79 virtual int Dup(int fd);
80 virtual int Readahead(int fd);
81
82 5721 virtual uint32_t SizeOfTxn() { return sizeof(Transaction); }
83 virtual int StartTxn(const shash::Any &id, uint64_t size, void *txn);
84 virtual void CtrlTxn(const Label &label, const int flags, void *txn);
85 virtual int64_t Write(const void *buf, uint64_t size, void *txn);
86 virtual int Reset(void *txn);
87 virtual int OpenFromTxn(void *txn);
88 virtual int AbortTxn(void *txn);
89 virtual int CommitTxn(void *txn);
90
91 virtual void Spawn() { }
92
93 virtual manifest::Breadcrumb LoadBreadcrumb(const std::string &fqrn);
94 virtual bool StoreBreadcrumb(const manifest::Manifest &manifest);
95 bool StoreBreadcrumb(std::string fqrn, manifest::Breadcrumb breadcrumb);
96
97 void TearDown2ReadOnly();
98 CacheModes cache_mode() { return cache_mode_; }
99 bool alien_cache() { return alien_cache_; }
100 132 std::string cache_path() { return cache_path_; }
101 975 bool is_tmpfs() { return is_tmpfs_; }
102 bool do_refcount() const { return do_refcount_; }
103 bool cleanup_unused_first() const { return cleanup_unused_first_; }
104
105 protected:
106 virtual void *DoSaveState();
107 virtual int DoRestoreState(void *data);
108 virtual bool DoFreeState(void *data);
109
110 private:
111 bool InitCacheDirectory(const std::string &cache_path);
112 /**
113 * Physically create the cache directory skeleton (base directory, txn,
114 * quarantaine and the 00..ff content directories) and detect the underlying
115 * file system. Idempotent and thread-safe (double-checked locking on
116 * cache_dirs_created_). For alien caches this is deferred until the first
117 * cache write so that a bogus fqrn (e.g. a stray access under /cvmfs) does
118 * not leave empty directories behind. See issue #4217.
119 */
120 bool EnsureCacheDirectories();
121
122 struct Transaction {
123 6469 Transaction(const shash::Any &id, const std::string &final_path)
124 6469 : buf_pos(0)
125 6469 , size(0)
126 6469 , expected_size(kSizeUnknown)
127 6469 , fd(-1)
128 6469 , label()
129 6469 , tmp_path()
130
1/2
✓ Branch 1 taken 6469 times.
✗ Branch 2 not taken.
6469 , final_path(final_path)
131 6469 , id(id) { }
132
133 unsigned char buffer[4096];
134 unsigned buf_pos;
135 uint64_t size;
136 uint64_t expected_size;
137 int fd;
138 Label label;
139 std::string tmp_path;
140 std::string final_path;
141 shash::Any id;
142 };
143
144 5680 PosixCacheManager(const std::string &cache_path, const bool alien_cache,
145 const bool do_refcount = true,
146 const bool cleanup_unused_first = false)
147 11360 : cache_path_(cache_path)
148
1/2
✓ Branch 1 taken 5680 times.
✗ Branch 2 not taken.
5680 , txn_template_path_(cache_path_ + "/txn/fetchXXXXXX")
149 5680 , alien_cache_(alien_cache)
150 5680 , rename_workaround_(kRenameNormal)
151 5680 , cache_mode_(kCacheReadWrite)
152 5680 , reports_correct_filesize_(true)
153 5680 , is_tmpfs_(false)
154 5680 , do_refcount_(do_refcount)
155
3/6
✓ Branch 1 taken 5680 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5680 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5680 times.
✗ Branch 8 not taken.
5680 , fd_mgr_(new FdRefcountMgr())
156
1/2
✓ Branch 2 taken 5680 times.
✗ Branch 3 not taken.
5680 , cleanup_unused_first_(cleanup_unused_first) {
157 5680 atomic_init32(&no_inflight_txns_);
158 5680 atomic_init32(&cache_dirs_created_);
159 5680 pthread_mutex_init(&lock_cache_dirs_, NULL);
160 5680 }
161
162 std::string GetPathInCache(const shash::Any &id);
163 int Rename(const char *oldpath, const char *newpath);
164 int Flush(Transaction *transaction);
165
166
167 std::string cache_path_;
168 std::string txn_template_path_;
169 bool alien_cache_;
170 RenameWorkarounds rename_workaround_;
171 CacheModes cache_mode_;
172
173 /**
174 * The cache can only degrade to a read-only cache once all writable file
175 * descriptors from transactions are closed. This is indicated by a zero
176 * value in this variable.
177 */
178 atomic_int32 no_inflight_txns_;
179
180 static const char kMagicRefcount = 123;
181 static const char kMagicNoRefcount = '\0';
182 struct SavedState {
183 41 SavedState() : magic_number(kMagicRefcount), version(0), fd_mgr(NULL) { }
184 /// this helps to distinguish from the SavedState of the normal
185 /// posix cache manager
186 char magic_number;
187 unsigned int version;
188 UniquePtr<FdRefcountMgr> fd_mgr;
189 };
190
191 /**
192 * Hack for HDFS which writes file sizes asynchronously.
193 */
194 bool reports_correct_filesize_;
195
196 /**
197 * True if posixcache is on tmpfs (and with this already in RAM)
198 */
199 bool is_tmpfs_;
200 /**
201 * Set to 1 by EnsureCacheDirectories() once the on-disk cache skeleton exists.
202 * For alien caches the skeleton is created lazily on the first write, so this
203 * starts at 0 and the flag is checked (lock-free) on every StartTxn(). See
204 * issue #4217.
205 */
206 atomic_int32 cache_dirs_created_;
207 /**
208 * Serializes the one-time skeleton creation in EnsureCacheDirectories().
209 */
210 pthread_mutex_t lock_cache_dirs_;
211 /**
212 * Refcount and return only unique file descriptors
213 */
214 bool do_refcount_;
215 UniquePtr<FdRefcountMgr> fd_mgr_;
216
217 bool cleanup_unused_first_;
218 }; // class PosixCacheManager
219
220 #endif // CVMFS_CACHE_POSIX_H_
221
222