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