Directory: | cvmfs/ |
---|---|
File: | cvmfs/file_chunk.cc |
Date: | 2025-06-22 02:36:02 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 108 | 136 | 79.4% |
Branches: | 63 | 110 | 57.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | |||
6 | #include "file_chunk.h" | ||
7 | |||
8 | #include <cassert> | ||
9 | |||
10 | #include "util/murmur.hxx" | ||
11 | #include "util/platform.h" | ||
12 | |||
13 | using namespace std; // NOLINT | ||
14 | |||
15 | ✗ | static inline uint32_t hasher_uint64t(const uint64_t &value) { | |
16 | ✗ | return MurmurHash2(&value, sizeof(value), 0x07387a4f); | |
17 | } | ||
18 | |||
19 | |||
20 | //------------------------------------------------------------------------------ | ||
21 | |||
22 | |||
23 | 200 | unsigned FileChunkReflist::FindChunkIdx(const uint64_t off) { | |
24 |
2/4✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
|
200 | assert(list && (list->size() > 0)); |
25 | 200 | unsigned idx_low = 0; | |
26 | 200 | unsigned idx_high = list->size() - 1; | |
27 | 200 | unsigned chunk_idx = idx_high / 2; | |
28 |
2/2✓ Branch 0 taken 340 times.
✓ Branch 1 taken 160 times.
|
500 | while (idx_low < idx_high) { |
29 |
2/2✓ Branch 2 taken 60 times.
✓ Branch 3 taken 280 times.
|
340 | if (static_cast<uint64_t>(list->AtPtr(chunk_idx)->offset()) > off) { |
30 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
|
60 | assert(idx_high > 0); |
31 | 60 | idx_high = chunk_idx - 1; | |
32 | } else { | ||
33 | 280 | if ((chunk_idx == list->size() - 1) | |
34 |
5/6✓ Branch 0 taken 280 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 40 times.
✓ Branch 5 taken 240 times.
✓ Branch 6 taken 40 times.
✓ Branch 7 taken 240 times.
|
280 | || (static_cast<uint64_t>(list->AtPtr(chunk_idx + 1)->offset()) |
35 | > off)) { | ||
36 | 40 | break; | |
37 | } | ||
38 | 240 | idx_low = chunk_idx + 1; | |
39 | } | ||
40 | 300 | chunk_idx = idx_low + (idx_high - idx_low) / 2; | |
41 | } | ||
42 | 200 | return chunk_idx; | |
43 | } | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Returns a consistent hash over hashes of the chunks. Used by libcvmfs. | ||
48 | */ | ||
49 | 20 | shash::Any FileChunkReflist::HashChunkList() { | |
50 | 20 | const shash::Algorithms algo = list->AtPtr(0)->content_hash().algorithm; | |
51 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | shash::ContextPtr ctx(algo); |
52 | 20 | ctx.buffer = alloca(ctx.size); | |
53 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | shash::Init(ctx); |
54 |
2/2✓ Branch 1 taken 40 times.
✓ Branch 2 taken 20 times.
|
60 | for (unsigned i = 0; i < list->size(); ++i) { |
55 | 40 | shash::Update( | |
56 |
1/2✓ Branch 3 taken 40 times.
✗ Branch 4 not taken.
|
40 | list->AtPtr(i)->content_hash().digest, shash::kDigestSizes[algo], ctx); |
57 | } | ||
58 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | shash::Any result(algo); |
59 |
1/2✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
|
20 | shash::Final(ctx, &result); |
60 | 40 | return result; | |
61 | } | ||
62 | |||
63 | |||
64 | //------------------------------------------------------------------------------ | ||
65 | |||
66 | |||
67 | 781 | void ChunkTables::InitLocks() { | |
68 | 781 | lock = reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t))); | |
69 | 781 | const int retval = pthread_mutex_init(lock, NULL); | |
70 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 781 times.
|
781 | assert(retval == 0); |
71 | |||
72 |
2/2✓ Branch 0 taken 99968 times.
✓ Branch 1 taken 781 times.
|
100749 | for (unsigned i = 0; i < kNumHandleLocks; ++i) { |
73 | pthread_mutex_t *m = reinterpret_cast<pthread_mutex_t *>( | ||
74 | 99968 | smalloc(sizeof(pthread_mutex_t))); | |
75 | 99968 | const int retval = pthread_mutex_init(m, NULL); | |
76 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 99968 times.
|
99968 | assert(retval == 0); |
77 |
1/2✓ Branch 1 taken 99968 times.
✗ Branch 2 not taken.
|
99968 | handle_locks.PushBack(m); |
78 | } | ||
79 | 781 | } | |
80 | |||
81 | |||
82 | 781 | void ChunkTables::InitHashmaps() { | |
83 | 781 | handle2uniqino.Init(16, 0, hasher_uint64t); | |
84 | 781 | handle2fd.Init(16, 0, hasher_uint64t); | |
85 | 781 | inode2chunks.Init(16, 0, hasher_uint64t); | |
86 | 781 | inode2references.Init(16, 0, hasher_uint64t); | |
87 | 781 | } | |
88 | |||
89 | |||
90 |
4/8✓ Branch 2 taken 781 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 781 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 781 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 781 times.
✗ Branch 12 not taken.
|
781 | ChunkTables::ChunkTables() { |
91 | 781 | next_handle = 2; | |
92 | 781 | version = kVersion; | |
93 |
1/2✓ Branch 1 taken 781 times.
✗ Branch 2 not taken.
|
781 | InitLocks(); |
94 |
1/2✓ Branch 1 taken 781 times.
✗ Branch 2 not taken.
|
781 | InitHashmaps(); |
95 | 781 | } | |
96 | |||
97 | |||
98 | 781 | ChunkTables::~ChunkTables() { | |
99 | 781 | pthread_mutex_destroy(lock); | |
100 | 781 | free(lock); | |
101 |
2/2✓ Branch 0 taken 99968 times.
✓ Branch 1 taken 781 times.
|
100749 | for (unsigned i = 0; i < kNumHandleLocks; ++i) { |
102 | 99968 | pthread_mutex_destroy(handle_locks.At(i)); | |
103 | 99968 | free(handle_locks.At(i)); | |
104 | } | ||
105 | 781 | } | |
106 | |||
107 | |||
108 | ✗ | ChunkTables::ChunkTables(const ChunkTables &other) { | |
109 | ✗ | version = kVersion; | |
110 | ✗ | InitLocks(); | |
111 | ✗ | InitHashmaps(); | |
112 | ✗ | CopyFrom(other); | |
113 | } | ||
114 | |||
115 | |||
116 | ✗ | ChunkTables &ChunkTables::operator=(const ChunkTables &other) { | |
117 | ✗ | if (&other == this) | |
118 | ✗ | return *this; | |
119 | |||
120 | ✗ | handle2uniqino.Clear(); | |
121 | ✗ | handle2fd.Clear(); | |
122 | ✗ | inode2chunks.Clear(); | |
123 | ✗ | inode2references.Clear(); | |
124 | ✗ | CopyFrom(other); | |
125 | ✗ | return *this; | |
126 | } | ||
127 | |||
128 | |||
129 | ✗ | void ChunkTables::CopyFrom(const ChunkTables &other) { | |
130 | ✗ | assert(version == other.version); | |
131 | ✗ | next_handle = other.next_handle; | |
132 | ✗ | inode2references = other.inode2references; | |
133 | ✗ | inode2chunks = other.inode2chunks; | |
134 | ✗ | handle2fd = other.handle2fd; | |
135 | ✗ | handle2uniqino = other.handle2uniqino; | |
136 | } | ||
137 | |||
138 | |||
139 | ✗ | pthread_mutex_t *ChunkTables::Handle2Lock(const uint64_t handle) const { | |
140 | ✗ | const uint32_t hash = hasher_uint64t(handle); | |
141 | ✗ | const double bucket = static_cast<double>(hash) | |
142 | ✗ | * static_cast<double>(kNumHandleLocks) | |
143 | / static_cast<double>((uint32_t)(-1)); | ||
144 | ✗ | return handle_locks.At((uint32_t)bucket % kNumHandleLocks); | |
145 | } | ||
146 | |||
147 | |||
148 | //------------------------------------------------------------------------------ | ||
149 | |||
150 | |||
151 | 353 | SimpleChunkTables::SimpleChunkTables() { | |
152 | 353 | lock_ = reinterpret_cast<pthread_mutex_t *>(smalloc(sizeof(pthread_mutex_t))); | |
153 | 353 | const int retval = pthread_mutex_init(lock_, NULL); | |
154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 353 times.
|
353 | assert(retval == 0); |
155 | 353 | } | |
156 | |||
157 | |||
158 | 351 | SimpleChunkTables::~SimpleChunkTables() { | |
159 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 351 times.
|
372 | for (unsigned i = 0; i < fd_table_.size(); ++i) { |
160 |
1/2✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
|
21 | delete fd_table_[i].chunk_reflist.list; |
161 | } | ||
162 | 351 | pthread_mutex_destroy(lock_); | |
163 | 351 | free(lock_); | |
164 | 351 | } | |
165 | |||
166 | |||
167 | 168 | int SimpleChunkTables::Add(FileChunkReflist chunks) { | |
168 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 168 times.
|
168 | assert(chunks.list != NULL); |
169 |
1/2✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
|
168 | OpenChunks new_entry; |
170 |
1/2✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
|
168 | new_entry.chunk_reflist = chunks; |
171 |
1/2✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
|
168 | new_entry.chunk_fd = new ChunkFd(); |
172 | 168 | unsigned i = 0; | |
173 | 168 | Lock(); | |
174 |
2/2✓ Branch 1 taken 315 times.
✓ Branch 2 taken 147 times.
|
462 | for (; i < fd_table_.size(); ++i) { |
175 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 294 times.
|
315 | if (fd_table_[i].chunk_reflist.list == NULL) { |
176 |
1/2✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | fd_table_[i] = new_entry; |
177 | 21 | Unlock(); | |
178 | 21 | return i; | |
179 | } | ||
180 | } | ||
181 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
147 | fd_table_.push_back(new_entry); |
182 | 147 | Unlock(); | |
183 | 147 | return i; | |
184 | 168 | } | |
185 | |||
186 | |||
187 | 63 | SimpleChunkTables::OpenChunks SimpleChunkTables::Get(int fd) { | |
188 | 63 | OpenChunks result; | |
189 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 42 times.
|
63 | if (fd < 0) |
190 | 21 | return result; | |
191 | |||
192 | 42 | const unsigned idx = static_cast<unsigned>(fd); | |
193 | 42 | Lock(); | |
194 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 21 times.
|
42 | if (idx < fd_table_.size()) |
195 |
1/2✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | result = fd_table_[idx]; |
196 | 42 | Unlock(); | |
197 | 42 | return result; | |
198 | } | ||
199 | |||
200 | |||
201 | 189 | void SimpleChunkTables::Release(int fd) { | |
202 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 168 times.
|
189 | if (fd < 0) |
203 | 21 | return; | |
204 | |||
205 | 168 | Lock(); | |
206 | 168 | const unsigned idx = static_cast<unsigned>(fd); | |
207 |
2/2✓ Branch 1 taken 21 times.
✓ Branch 2 taken 147 times.
|
168 | if (idx >= fd_table_.size()) { |
208 | 21 | Unlock(); | |
209 | 21 | return; | |
210 | } | ||
211 | |||
212 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
147 | delete fd_table_[idx].chunk_reflist.list; |
213 | 147 | fd_table_[idx].chunk_reflist.list = NULL; | |
214 | 147 | fd_table_[idx].chunk_reflist.path.Assign("", 0); | |
215 |
1/2✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
|
147 | delete fd_table_[idx].chunk_fd; |
216 | 147 | fd_table_[idx].chunk_fd = NULL; | |
217 |
6/6✓ Branch 1 taken 252 times.
✓ Branch 2 taken 21 times.
✓ Branch 4 taken 126 times.
✓ Branch 5 taken 126 times.
✓ Branch 6 taken 126 times.
✓ Branch 7 taken 147 times.
|
273 | while (!fd_table_.empty() && (fd_table_.back().chunk_reflist.list == NULL)) { |
218 | 126 | fd_table_.pop_back(); | |
219 | } | ||
220 | 147 | Unlock(); | |
221 | } | ||
222 |