Directory: | cvmfs/ |
---|---|
File: | cvmfs/glue_buffer.cc |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 209 | 282 | 74.1% |
Branches: | 77 | 184 | 41.8% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #define __STDC_FORMAT_MACROS | ||
6 | |||
7 | |||
8 | #include "glue_buffer.h" | ||
9 | |||
10 | #include <errno.h> | ||
11 | #include <poll.h> | ||
12 | #include <unistd.h> | ||
13 | |||
14 | #include <cassert> | ||
15 | #include <cstdlib> | ||
16 | #include <cstring> | ||
17 | |||
18 | #include <string> | ||
19 | #include <vector> | ||
20 | |||
21 | #include "util/exception.h" | ||
22 | #include "util/logging.h" | ||
23 | #include "util/mutex.h" | ||
24 | #include "util/platform.h" | ||
25 | #include "util/posix.h" | ||
26 | #include "util/smalloc.h" | ||
27 | |||
28 | using namespace std; // NOLINT | ||
29 | |||
30 | namespace glue { | ||
31 | |||
32 | ✗ | PathStore &PathStore::operator= (const PathStore &other) { | |
33 | ✗ | if (&other == this) | |
34 | ✗ | return *this; | |
35 | |||
36 | ✗ | delete string_heap_; | |
37 | ✗ | CopyFrom(other); | |
38 | ✗ | return *this; | |
39 | } | ||
40 | |||
41 | |||
42 | ✗ | PathStore::PathStore(const PathStore &other) { | |
43 | ✗ | CopyFrom(other); | |
44 | } | ||
45 | |||
46 | |||
47 | ✗ | void PathStore::CopyFrom(const PathStore &other) { | |
48 | ✗ | map_ = other.map_; | |
49 | |||
50 | ✗ | string_heap_ = new StringHeap(other.string_heap_->used()); | |
51 | ✗ | shash::Md5 empty_path = map_.empty_key(); | |
52 | ✗ | for (unsigned i = 0; i < map_.capacity(); ++i) { | |
53 | ✗ | if (map_.keys()[i] != empty_path) { | |
54 | ✗ | (map_.values() + i)->name = | |
55 | ✗ | string_heap_->AddString(map_.values()[i].name.length(), | |
56 | ✗ | map_.values()[i].name.data()); | |
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | |||
62 | //------------------------------------------------------------------------------ | ||
63 | |||
64 | |||
65 | 30 | void InodeTracker::InitLock() { | |
66 | 30 | lock_ = | |
67 | 30 | reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t))); | |
68 | 30 | int retval = pthread_mutex_init(lock_, NULL); | |
69 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | assert(retval == 0); |
70 | 30 | } | |
71 | |||
72 | |||
73 | ✗ | void InodeTracker::CopyFrom(const InodeTracker &other) { | |
74 | ✗ | assert(other.version_ == kVersion); | |
75 | ✗ | version_ = kVersion; | |
76 | ✗ | path_map_ = other.path_map_; | |
77 | ✗ | inode_ex_map_ = other.inode_ex_map_; | |
78 | ✗ | inode_references_ = other.inode_references_; | |
79 | ✗ | statistics_ = other.statistics_; | |
80 | } | ||
81 | |||
82 | |||
83 |
2/4✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 30 times.
✗ Branch 6 not taken.
|
30 | InodeTracker::InodeTracker() { |
84 | 30 | version_ = kVersion; | |
85 | 30 | InitLock(); | |
86 | 30 | } | |
87 | |||
88 | |||
89 | ✗ | InodeTracker::InodeTracker(const InodeTracker &other) { | |
90 | ✗ | CopyFrom(other); | |
91 | ✗ | InitLock(); | |
92 | } | ||
93 | |||
94 | |||
95 | ✗ | InodeTracker &InodeTracker::operator= (const InodeTracker &other) { | |
96 | ✗ | if (&other == this) | |
97 | ✗ | return *this; | |
98 | |||
99 | ✗ | CopyFrom(other); | |
100 | ✗ | return *this; | |
101 | } | ||
102 | |||
103 | |||
104 | 30 | InodeTracker::~InodeTracker() { | |
105 | 30 | pthread_mutex_destroy(lock_); | |
106 | 30 | free(lock_); | |
107 | 30 | } | |
108 | |||
109 | |||
110 | //------------------------------------------------------------------------------ | ||
111 | |||
112 | 22 | DentryTracker::DentryTracker() : version_(kVersion), is_active_(true) { | |
113 | 22 | pipe_terminate_[0] = pipe_terminate_[1] = -1; | |
114 | 22 | cleaning_interval_ms_ = -1; | |
115 | 22 | InitLock(); | |
116 | 22 | } | |
117 | |||
118 | |||
119 | 25 | DentryTracker::~DentryTracker() { | |
120 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 24 times.
|
25 | if (pipe_terminate_[1] >= 0) { |
121 | 1 | char t = 'T'; | |
122 | 1 | WritePipe(pipe_terminate_[1], &t, 1); | |
123 | 1 | pthread_join(thread_cleaner_, NULL); | |
124 | 1 | ClosePipe(pipe_terminate_); | |
125 | } | ||
126 | 25 | pthread_mutex_destroy(lock_); | |
127 | 25 | free(lock_); | |
128 | 25 | } | |
129 | |||
130 | |||
131 | 4 | DentryTracker::DentryTracker(const DentryTracker &other) { | |
132 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | CopyFrom(other); |
133 | 4 | pipe_terminate_[0] = pipe_terminate_[1] = -1; | |
134 | 4 | cleaning_interval_ms_ = -1; | |
135 | 4 | InitLock(); | |
136 | 4 | } | |
137 | |||
138 | |||
139 | ✗ | DentryTracker &DentryTracker::operator= (const DentryTracker &other) { | |
140 | ✗ | if (&other == this) | |
141 | ✗ | return *this; | |
142 | |||
143 | ✗ | Lock(); | |
144 | ✗ | CopyFrom(other); | |
145 | ✗ | Unlock(); | |
146 | ✗ | return *this; | |
147 | } | ||
148 | |||
149 | |||
150 | 4 | void DentryTracker::CopyFrom(const DentryTracker &other) { | |
151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | assert(other.version_ == kVersion); |
152 | |||
153 | 4 | version_ = kVersion; | |
154 | 4 | statistics_ = other.statistics_; | |
155 | 4 | is_active_ = other.is_active_; | |
156 | 4 | entries_ = other.entries_; | |
157 | 4 | } | |
158 | |||
159 | |||
160 | 4 | DentryTracker *DentryTracker::Move() { | |
161 | 4 | Lock(); | |
162 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | DentryTracker *new_tracker = new DentryTracker(*this); |
163 | 4 | statistics_.num_remove += entries_.size(); | |
164 | 4 | entries_.Clear(); | |
165 | 4 | Unlock(); | |
166 | 4 | return new_tracker; | |
167 | } | ||
168 | |||
169 | |||
170 | 1 | void DentryTracker::SpawnCleaner(unsigned interval_s) { | |
171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(pipe_terminate_[0] == -1); |
172 | 1 | cleaning_interval_ms_ = interval_s * 1000; | |
173 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (cleaning_interval_ms_ == 0) cleaning_interval_ms_ = -1; |
174 | 1 | MakePipe(pipe_terminate_); | |
175 | 1 | int retval = pthread_create(&thread_cleaner_, NULL, MainCleaner, this); | |
176 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(retval == 0); |
177 | 1 | } | |
178 | |||
179 | |||
180 | 1 | void *DentryTracker::MainCleaner(void *data) { | |
181 | 1 | DentryTracker *tracker = reinterpret_cast<DentryTracker *>(data); | |
182 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | LogCvmfs(kLogCvmfs, kLogDebug, "starting negative entry cache cleaner"); |
183 | |||
184 | struct pollfd watch_term; | ||
185 | 1 | watch_term.fd = tracker->pipe_terminate_[0]; | |
186 | 1 | watch_term.events = POLLIN | POLLPRI; | |
187 | 1 | int timeout_ms = tracker->cleaning_interval_ms_;; | |
188 | 1 | uint64_t deadline = platform_monotonic_time() + timeout_ms / 1000; | |
189 | while (true) { | ||
190 | 4 | watch_term.revents = 0; | |
191 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | int retval = poll(&watch_term, 1, timeout_ms); |
192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (retval < 0) { |
193 | ✗ | if (errno == EINTR) { | |
194 | ✗ | if (timeout_ms >= 0) { | |
195 | ✗ | uint64_t now = platform_monotonic_time(); | |
196 | ✗ | timeout_ms = (now > deadline) ? 0 : (deadline - now) * 1000; | |
197 | } | ||
198 | 3 | continue; | |
199 | } | ||
200 | ✗ | abort(); | |
201 | } | ||
202 | 4 | timeout_ms = tracker->cleaning_interval_ms_; | |
203 | 4 | deadline = platform_monotonic_time() + timeout_ms / 1000; | |
204 | |||
205 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (retval == 0) { |
206 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | LogCvmfs(kLogCvmfs, kLogDebug, "negative entry cleaner: pruning"); |
207 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | tracker->Prune(); |
208 | 3 | continue; | |
209 | } | ||
210 | |||
211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(watch_term.revents != 0); |
212 | |||
213 | 1 | char c = 0; | |
214 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | ReadPipe(tracker->pipe_terminate_[0], &c, 1); |
215 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(c == 'T'); |
216 | 1 | break; | |
217 | 3 | } | |
218 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | LogCvmfs(kLogCvmfs, kLogDebug, "stopping negative entry cache cleaner"); |
219 | 1 | return NULL; | |
220 | } | ||
221 | |||
222 | |||
223 | 26 | void DentryTracker::InitLock() { | |
224 | 26 | lock_ = | |
225 | 26 | reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t))); | |
226 | 26 | int retval = pthread_mutex_init(lock_, NULL); | |
227 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | assert(retval == 0); |
228 | 26 | } | |
229 | |||
230 | |||
231 | 7 | void DentryTracker::Prune() { | |
232 | 7 | Lock(); | |
233 | 7 | DoPrune(platform_monotonic_time()); | |
234 | 7 | Unlock(); | |
235 | 7 | } | |
236 | |||
237 | |||
238 | 10 | DentryTracker::Cursor DentryTracker::BeginEnumerate() { | |
239 | 10 | Entry *head = NULL; | |
240 | 10 | Lock(); | |
241 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | entries_.Peek(&head); |
242 | 10 | return Cursor(head); | |
243 | } | ||
244 | |||
245 | |||
246 | 1292 | bool DentryTracker::NextEntry(Cursor *cursor, | |
247 | uint64_t *inode_parent, NameString *name) | ||
248 | { | ||
249 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1286 times.
|
1292 | if (cursor->head == NULL) |
250 | 6 | return false; | |
251 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1283 times.
|
1286 | if (cursor->pos >= entries_.size()) |
252 | 3 | return false; | |
253 | 1283 | Entry *e = cursor->head + cursor->pos; | |
254 | 1283 | *inode_parent = e->inode_parent; | |
255 | 1283 | *name = e->name; | |
256 | 1283 | cursor->pos++; | |
257 | 1283 | return true; | |
258 | } | ||
259 | |||
260 | |||
261 | 10 | void DentryTracker::EndEnumerate(Cursor * /* cursor */) { | |
262 | 10 | Unlock(); | |
263 | 10 | } | |
264 | |||
265 | |||
266 | //------------------------------------------------------------------------------ | ||
267 | |||
268 | |||
269 |
1/2✓ Branch 3 taken 19 times.
✗ Branch 4 not taken.
|
19 | PageCacheTracker::PageCacheTracker() : version_(kVersion), is_active_(true) { |
270 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | map_.Init(16, 0, hasher_inode); |
271 | 19 | InitLock(); | |
272 | 19 | } | |
273 | |||
274 | |||
275 | 19 | PageCacheTracker::~PageCacheTracker() { | |
276 | 19 | pthread_mutex_destroy(lock_); | |
277 | 19 | free(lock_); | |
278 | 19 | } | |
279 | |||
280 | |||
281 | ✗ | PageCacheTracker::PageCacheTracker(const PageCacheTracker &other) { | |
282 | ✗ | CopyFrom(other); | |
283 | ✗ | InitLock(); | |
284 | } | ||
285 | |||
286 | |||
287 | ✗ | PageCacheTracker &PageCacheTracker::operator= (const PageCacheTracker &other) { | |
288 | ✗ | if (&other == this) | |
289 | ✗ | return *this; | |
290 | |||
291 | ✗ | MutexLockGuard guard(lock_); | |
292 | ✗ | CopyFrom(other); | |
293 | ✗ | return *this; | |
294 | } | ||
295 | |||
296 | |||
297 | ✗ | void PageCacheTracker::CopyFrom(const PageCacheTracker &other) { | |
298 | ✗ | assert(other.version_ == kVersion); | |
299 | |||
300 | ✗ | version_ = kVersion; | |
301 | ✗ | is_active_ = other.is_active_; | |
302 | ✗ | statistics_ = other.statistics_; | |
303 | |||
304 | ✗ | map_.Init(16, 0, hasher_inode); | |
305 | ✗ | map_ = other.map_; | |
306 | ✗ | stat_store_ = other.stat_store_; | |
307 | } | ||
308 | |||
309 | |||
310 | 19 | void PageCacheTracker::InitLock() { | |
311 | 19 | lock_ = | |
312 | 19 | reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t))); | |
313 | 19 | int retval = pthread_mutex_init(lock_, NULL); | |
314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | assert(retval == 0); |
315 | 19 | } | |
316 | |||
317 | 10 | PageCacheTracker::OpenDirectives PageCacheTracker::Open( | |
318 | uint64_t inode, const shash::Any &hash, const struct stat &info) | ||
319 | { | ||
320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | assert(inode == info.st_ino); |
321 | |||
322 | 10 | OpenDirectives open_directives; | |
323 | // Old behavior: always flush page cache on open | ||
324 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
|
10 | if (!is_active_) |
325 | 1 | return open_directives; | |
326 | |||
327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (inode != info.st_ino) { |
328 | ✗ | PANIC(kLogStderr | kLogDebug, | |
329 | "invalid entry on open: %" PRIu64 " with st_ino=%" PRIu64, | ||
330 | " hash=%s size=%" PRIu64, | ||
331 | inode, info.st_ino, hash.ToString().c_str(), info.st_size); | ||
332 | } | ||
333 | |||
334 | 9 | MutexLockGuard guard(lock_); | |
335 | |||
336 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | Entry entry; |
337 |
1/2✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
|
9 | bool retval = map_.Lookup(inode, &entry); |
338 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
|
9 | if (!retval) { |
339 | 3 | open_directives.keep_cache = true; | |
340 | 3 | open_directives.direct_io = false; | |
341 | 3 | statistics_.n_insert++; | |
342 | 3 | statistics_.n_open_cached++; | |
343 | |||
344 | 3 | entry.nopen = 1; | |
345 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | entry.idx_stat = stat_store_.Add(info); |
346 | 3 | entry.hash = hash; | |
347 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | map_.Insert(inode, entry); |
348 | 3 | return open_directives; | |
349 | } | ||
350 | |||
351 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
|
6 | if (entry.hash == hash) { |
352 | 4 | open_directives.direct_io = false; | |
353 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
|
4 | if (entry.nopen < 0) { |
354 | // The page cache is still in the transition phase and may contain old | ||
355 | // content. So trigger a flush of the cache in any case. | ||
356 | 1 | open_directives.keep_cache = false; | |
357 | 1 | statistics_.n_open_flush++; | |
358 | 1 | entry.nopen--; | |
359 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | map_.Insert(inode, entry); |
360 | 1 | return open_directives; | |
361 | } else { | ||
362 | 3 | open_directives.keep_cache = true; | |
363 | 3 | statistics_.n_open_cached++; | |
364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (entry.nopen++ == 0) |
365 | ✗ | entry.idx_stat = stat_store_.Add(info); | |
366 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | map_.Insert(inode, entry); |
367 | 3 | return open_directives; | |
368 | } | ||
369 | } | ||
370 | |||
371 | // Page cache mismatch and old data has still open file attached to it, | ||
372 | // circumvent the page cache entirely and use direct I/O. In this case, | ||
373 | // cvmfs_close() will _not_ call Close(). | ||
374 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (entry.nopen != 0) { |
375 | 1 | open_directives.keep_cache = true; | |
376 | 1 | open_directives.direct_io = true; | |
377 | 1 | statistics_.n_open_direct++; | |
378 | 1 | return open_directives; | |
379 | } | ||
380 | |||
381 | // Stale data in the page cache, start the transition phase in which newly | ||
382 | // opened files flush the page cache and re-populate it with the new hash. | ||
383 | // The first file to reach Close() will finish the transition phase and | ||
384 | // mark the new hash as committed. | ||
385 | 1 | open_directives.direct_io = false; | |
386 | 1 | open_directives.keep_cache = false; | |
387 | 1 | statistics_.n_open_flush++; | |
388 | 1 | entry.hash = hash; | |
389 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | entry.idx_stat = stat_store_.Add(info); |
390 | 1 | entry.nopen = -1; | |
391 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | map_.Insert(inode, entry); |
392 | 1 | return open_directives; | |
393 | 9 | } | |
394 | |||
395 | ✗ | PageCacheTracker::OpenDirectives PageCacheTracker::OpenDirect() { | |
396 | ✗ | OpenDirectives open_directives(true, true); | |
397 | // Old behavior: always flush page cache on open | ||
398 | ✗ | if (!is_active_) | |
399 | ✗ | return open_directives; | |
400 | |||
401 | ✗ | MutexLockGuard guard(lock_); | |
402 | ✗ | statistics_.n_open_direct++; | |
403 | ✗ | return open_directives; | |
404 | } | ||
405 | |||
406 | 8 | void PageCacheTracker::Close(uint64_t inode) { | |
407 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
|
8 | if (!is_active_) |
408 | 1 | return; | |
409 | |||
410 | 7 | MutexLockGuard guard(lock_); | |
411 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | Entry entry; |
412 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | bool retval = map_.Lookup(inode, &entry); |
413 | |||
414 | 7 | if (!AssertOrLog(retval, kLogCvmfs, kLogSyslogWarn | kLogDebug, | |
415 | "PageCacheTracker::Close Race condition? " | ||
416 | "Did not find inode %lu", | ||
417 | inode) | ||
418 |
3/6✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7 times.
|
7 | || !AssertOrLog(entry.nopen != 0, kLogCvmfs, kLogSyslogWarn | kLogDebug, |
419 | "PageCacheTracker::Close Race condition? " | ||
420 | "Inode %lu has no open entries", | ||
421 | inode)) { | ||
422 | ✗ | return; | |
423 | } | ||
424 | |||
425 | 7 | const int32_t old_open = entry.nopen; | |
426 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if (entry.nopen < 0) { |
427 | // At this point we know that any stale data has been flushed from the | ||
428 | // cache and only data related to the currently booked content hash | ||
429 | // can be present. So clear the transition bit (sign bit). | ||
430 | 1 | entry.nopen = -entry.nopen; | |
431 | } | ||
432 | 7 | entry.nopen--; | |
433 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
|
7 | if (entry.nopen == 0) { |
434 | // File closed, remove struct stat information | ||
435 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (entry.idx_stat < 0) { |
436 | ✗ | PANIC(kLogSyslogErr | kLogDebug, | |
437 | "page cache tracker: missing stat entry! Entry info: inode %" PRIu64 | ||
438 | " - open counter %d - hash %s", | ||
439 | inode, old_open, entry.hash.ToString().c_str()); | ||
440 | } | ||
441 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | uint64_t inode_update = stat_store_.Erase(entry.idx_stat); |
442 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | Entry entry_update; |
443 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | retval = map_.Lookup(inode_update, &entry_update); |
444 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!retval) { |
445 | ✗ | PANIC(kLogSyslogErr | kLogDebug, | |
446 | "invalid inode in page cache tracker: inode %" PRIu64 | ||
447 | ", replacing %" PRIu64, inode_update, inode); | ||
448 | } | ||
449 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | assert(retval); |
450 | 3 | entry_update.idx_stat = entry.idx_stat; | |
451 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | map_.Insert(inode_update, entry_update); |
452 | 3 | entry.idx_stat = -1; | |
453 | } | ||
454 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | map_.Insert(inode, entry); |
455 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | } |
456 | |||
457 | 2 | PageCacheTracker::EvictRaii::EvictRaii(PageCacheTracker *t) | |
458 | 2 | : tracker_(t) | |
459 | { | ||
460 | 2 | int retval = pthread_mutex_lock(tracker_->lock_); | |
461 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | assert(retval == 0); |
462 | 2 | } | |
463 | |||
464 | 2 | PageCacheTracker::EvictRaii::~EvictRaii() { | |
465 | 2 | int retval = pthread_mutex_unlock(tracker_->lock_); | |
466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | assert(retval == 0); |
467 | 2 | } | |
468 | |||
469 | 2 | void PageCacheTracker::EvictRaii::Evict(uint64_t inode) { | |
470 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (!tracker_->is_active_) |
471 | 1 | return; | |
472 | |||
473 | 1 | bool contained_inode = tracker_->map_.Erase(inode); | |
474 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (contained_inode) |
475 | 1 | tracker_->statistics_.n_remove++; | |
476 | } | ||
477 | |||
478 | } // namespace glue | ||
479 |