Directory: | cvmfs/ |
---|---|
File: | cvmfs/cache_extern.cc |
Date: | 2025-06-22 02:36:02 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 553 | 719 | 76.9% |
Branches: | 319 | 717 | 44.5% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #include "cache_extern.h" | ||
6 | |||
7 | #include <errno.h> | ||
8 | #include <fcntl.h> | ||
9 | #include <inttypes.h> | ||
10 | #include <stdint.h> | ||
11 | #include <sys/socket.h> | ||
12 | #include <unistd.h> | ||
13 | |||
14 | #include <algorithm> | ||
15 | #include <cassert> | ||
16 | #ifdef __APPLE__ | ||
17 | #include <cstdlib> | ||
18 | #endif | ||
19 | #include <cstring> | ||
20 | #include <map> | ||
21 | #include <new> | ||
22 | #include <set> | ||
23 | #include <string> | ||
24 | |||
25 | #include "cache.pb.h" | ||
26 | #include "crypto/hash.h" | ||
27 | #include "util/atomic.h" | ||
28 | #include "util/concurrency.h" | ||
29 | #include "util/exception.h" | ||
30 | #include "util/logging.h" | ||
31 | #include "util/pointer.h" | ||
32 | #include "util/posix.h" | ||
33 | #ifdef __APPLE__ | ||
34 | #include "util/smalloc.h" | ||
35 | #endif | ||
36 | #include "util/string.h" | ||
37 | |||
38 | using namespace std; // NOLINT | ||
39 | |||
40 | namespace { | ||
41 | |||
42 | 22616 | int Ack2Errno(cvmfs::EnumStatus status_code) { | |
43 |
4/12✓ Branch 0 taken 22544 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 30 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 19 times.
✗ Branch 11 not taken.
|
22616 | switch (status_code) { |
44 | 22544 | case cvmfs::STATUS_OK: | |
45 | 22544 | return 0; | |
46 | ✗ | case cvmfs::STATUS_NOSUPPORT: | |
47 | ✗ | return -EOPNOTSUPP; | |
48 | ✗ | case cvmfs::STATUS_FORBIDDEN: | |
49 | ✗ | return -EPERM; | |
50 | ✗ | case cvmfs::STATUS_NOSPACE: | |
51 | ✗ | return -ENOSPC; | |
52 | 23 | case cvmfs::STATUS_NOENTRY: | |
53 | 23 | return -ENOENT; | |
54 | 30 | case cvmfs::STATUS_MALFORMED: | |
55 | 30 | return -EINVAL; | |
56 | ✗ | case cvmfs::STATUS_IOERR: | |
57 | ✗ | return -EIO; | |
58 | ✗ | case cvmfs::STATUS_CORRUPTED: | |
59 | ✗ | return -EIO; | |
60 | ✗ | case cvmfs::STATUS_TIMEOUT: | |
61 | ✗ | return -EIO; | |
62 | ✗ | case cvmfs::STATUS_BADCOUNT: | |
63 | ✗ | return -EINVAL; | |
64 | 19 | case cvmfs::STATUS_OUTOFBOUNDS: | |
65 | 19 | return -EINVAL; | |
66 | ✗ | default: | |
67 | ✗ | return -EIO; | |
68 | } | ||
69 | } | ||
70 | |||
71 | } // anonymous namespace | ||
72 | |||
73 | const shash::Any ExternalCacheManager::kInvalidHandle; | ||
74 | |||
75 | |||
76 | ✗ | int ExternalCacheManager::AbortTxn(void *txn) { | |
77 | ✗ | const int result = Reset(txn); | |
78 | #ifdef __APPLE__ | ||
79 | free(reinterpret_cast<Transaction *>(txn)->buffer); | ||
80 | #endif | ||
81 | ✗ | return result; | |
82 | } | ||
83 | |||
84 | |||
85 | 294 | bool ExternalCacheManager::AcquireQuotaManager(QuotaManager *quota_mgr) { | |
86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 294 times.
|
294 | assert(quota_mgr != NULL); |
87 | 294 | quota_mgr_ = quota_mgr; | |
88 | 270 | LogCvmfs(kLogCache, kLogDebug, "set quota manager"); | |
89 | 294 | return true; | |
90 | } | ||
91 | |||
92 | |||
93 | 56925 | void ExternalCacheManager::CallRemotely(ExternalCacheManager::RpcJob *rpc_job) { | |
94 |
2/2✓ Branch 0 taken 26550 times.
✓ Branch 1 taken 30375 times.
|
56925 | if (!spawned_) { |
95 | 26550 | transport_.SendFrame(rpc_job->frame_send()); | |
96 | 26550 | const uint32_t save_att_size = rpc_job->frame_recv()->att_size(); | |
97 | bool again; | ||
98 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 26550 times.
|
26565 | do { |
99 | 26565 | again = false; | |
100 | 26565 | const bool retval = transport_.RecvFrame(rpc_job->frame_recv()); | |
101 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26565 times.
|
26565 | assert(retval); |
102 |
2/2✓ Branch 2 taken 15 times.
✓ Branch 3 taken 26550 times.
|
26565 | if (rpc_job->frame_recv()->IsMsgOutOfBand()) { |
103 | google::protobuf::MessageLite *msg_typed = rpc_job->frame_recv() | ||
104 | 15 | ->GetMsgTyped(); | |
105 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
|
15 | assert(msg_typed->GetTypeName() == "cvmfs.MsgDetach"); |
106 |
2/4✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
|
15 | quota_mgr_->BroadcastBackchannels("R"); // release pinned catalogs |
107 | 15 | rpc_job->frame_recv()->Reset(save_att_size); | |
108 | 15 | again = true; | |
109 | } | ||
110 | } while (again); | ||
111 | } else { | ||
112 |
1/2✓ Branch 1 taken 30375 times.
✗ Branch 2 not taken.
|
30375 | Signal signal; |
113 | { | ||
114 | 30375 | const MutexLockGuard guard(lock_inflight_rpcs_); | |
115 |
1/2✓ Branch 2 taken 30420 times.
✗ Branch 3 not taken.
|
30420 | inflight_rpcs_.push_back(RpcInFlight(rpc_job, &signal)); |
116 | 30420 | } | |
117 | { | ||
118 | 30420 | const MutexLockGuard guard(lock_send_fd_); | |
119 |
1/2✓ Branch 2 taken 30420 times.
✗ Branch 3 not taken.
|
30420 | transport_.SendFrame(rpc_job->frame_send()); |
120 | 30420 | } | |
121 |
1/2✓ Branch 1 taken 30405 times.
✗ Branch 2 not taken.
|
30420 | signal.Wait(); |
122 | 30405 | } | |
123 | 56970 | } | |
124 | |||
125 | |||
126 | 10964 | int ExternalCacheManager::ChangeRefcount(const shash::Any &id, int change_by) { | |
127 |
1/2✓ Branch 1 taken 10964 times.
✗ Branch 2 not taken.
|
10964 | cvmfs::MsgHash object_id; |
128 |
1/2✓ Branch 1 taken 10964 times.
✗ Branch 2 not taken.
|
10964 | transport_.FillMsgHash(id, &object_id); |
129 |
1/2✓ Branch 1 taken 10964 times.
✗ Branch 2 not taken.
|
10964 | cvmfs::MsgRefcountReq msg_refcount; |
130 | 10964 | msg_refcount.set_session_id(session_id_); | |
131 | 10964 | msg_refcount.set_req_id(NextRequestId()); | |
132 | 10964 | msg_refcount.set_allocated_object_id(&object_id); | |
133 | 10964 | msg_refcount.set_change_by(change_by); | |
134 |
1/2✓ Branch 1 taken 10964 times.
✗ Branch 2 not taken.
|
10964 | RpcJob rpc_job(&msg_refcount); |
135 |
1/2✓ Branch 1 taken 10964 times.
✗ Branch 2 not taken.
|
10964 | CallRemotely(&rpc_job); |
136 | 10964 | msg_refcount.release_object_id(); | |
137 | |||
138 |
1/2✓ Branch 1 taken 10949 times.
✗ Branch 2 not taken.
|
10964 | cvmfs::MsgRefcountReply *msg_reply = rpc_job.msg_refcount_reply(); |
139 | 21898 | return Ack2Errno(msg_reply->status()); | |
140 | 10949 | } | |
141 | |||
142 | |||
143 | 4419 | int ExternalCacheManager::Close(int fd) { | |
144 | 4419 | ReadOnlyHandle handle; | |
145 | { | ||
146 | 4419 | const WriteLockGuard guard(rwlock_fd_table_); | |
147 |
1/2✓ Branch 1 taken 4419 times.
✗ Branch 2 not taken.
|
4419 | handle = fd_table_.GetHandle(fd); |
148 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 4404 times.
|
4419 | if (handle.id == kInvalidHandle) |
149 | 15 | return -EBADF; | |
150 |
1/2✓ Branch 1 taken 4404 times.
✗ Branch 2 not taken.
|
4404 | const int retval = fd_table_.CloseFd(fd); |
151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4404 times.
|
4404 | assert(retval == 0); |
152 |
2/2✓ Branch 1 taken 4404 times.
✓ Branch 2 taken 15 times.
|
4419 | } |
153 | |||
154 |
1/2✓ Branch 1 taken 4389 times.
✗ Branch 2 not taken.
|
4404 | return ChangeRefcount(handle.id, -1); |
155 | } | ||
156 | |||
157 | |||
158 | 2122 | int ExternalCacheManager::CommitTxn(void *txn) { | |
159 | 2122 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
160 |
1/2✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
|
90 | LogCvmfs(kLogCache, kLogDebug, "committing %s", |
161 | 180 | std::string(transaction->id.ToString()).c_str()); | |
162 | 2122 | const int retval = Flush(true, transaction); | |
163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2122 times.
|
2122 | if (retval != 0) |
164 | ✗ | return retval; | |
165 | |||
166 | 2122 | const int refcount = transaction->open_fds - 1; | |
167 |
2/2✓ Branch 0 taken 2120 times.
✓ Branch 1 taken 2 times.
|
2122 | if (refcount != 0) |
168 | 2120 | return ChangeRefcount(transaction->id, refcount); | |
169 | #ifdef __APPLE__ | ||
170 | free(transaction->buffer); | ||
171 | #endif | ||
172 | 2 | return 0; | |
173 | } | ||
174 | |||
175 | |||
176 | ✗ | int ExternalCacheManager::ConnectLocator(const std::string &locator, | |
177 | bool print_error) { | ||
178 | ✗ | vector<string> tokens = SplitString(locator, '='); | |
179 | ✗ | int result = -1; | |
180 | ✗ | if (tokens[0] == "unix") { | |
181 | ✗ | result = ConnectSocket(tokens[1]); | |
182 | ✗ | } else if (tokens[0] == "tcp") { | |
183 | ✗ | vector<string> tcp_address = SplitString(tokens[1], ':'); | |
184 | ✗ | if (tcp_address.size() != 2) | |
185 | ✗ | return -EINVAL; | |
186 | ✗ | result = ConnectTcpEndpoint(tcp_address[0], String2Uint64(tcp_address[1])); | |
187 | ✗ | } else { | |
188 | ✗ | return -EINVAL; | |
189 | } | ||
190 | ✗ | if (result < 0) { | |
191 | ✗ | if (print_error) { | |
192 | ✗ | if (errno) { | |
193 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogStderr, | |
194 | ✗ | "Failed to connect to socket: %s", strerror(errno)); | |
195 | } else { | ||
196 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogStderr, | |
197 | "Failed to connect to socket (unknown error)"); | ||
198 | } | ||
199 | } | ||
200 | ✗ | return -EIO; | |
201 | } | ||
202 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslog, "connected to cache plugin at %s", | |
203 | locator.c_str()); | ||
204 | ✗ | return result; | |
205 | } | ||
206 | |||
207 | |||
208 | 296 | ExternalCacheManager *ExternalCacheManager::Create(int fd_connection, | |
209 | unsigned max_open_fds, | ||
210 | const string &ident) { | ||
211 | UniquePtr<ExternalCacheManager> cache_mgr( | ||
212 |
3/6✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 296 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 296 times.
✗ Branch 8 not taken.
|
296 | new ExternalCacheManager(fd_connection, max_open_fds)); |
213 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 296 times.
|
296 | assert(cache_mgr.IsValid()); |
214 | |||
215 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | cvmfs::MsgHandshake msg_handshake; |
216 | 296 | msg_handshake.set_protocol_version(kPbProtocolVersion); | |
217 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | msg_handshake.set_name(ident); |
218 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | CacheTransport::Frame frame_send(&msg_handshake); |
219 |
1/2✓ Branch 2 taken 296 times.
✗ Branch 3 not taken.
|
296 | cache_mgr->transport_.SendFrame(&frame_send); |
220 | |||
221 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | CacheTransport::Frame frame_recv; |
222 |
1/2✓ Branch 2 taken 296 times.
✗ Branch 3 not taken.
|
296 | const bool retval = cache_mgr->transport_.RecvFrame(&frame_recv); |
223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
|
296 | if (!retval) |
224 | ✗ | return NULL; | |
225 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | google::protobuf::MessageLite *msg_typed = frame_recv.GetMsgTyped(); |
226 |
2/4✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 296 times.
|
296 | if (msg_typed->GetTypeName() != "cvmfs.MsgHandshakeAck") |
227 | ✗ | return NULL; | |
228 | 296 | cvmfs::MsgHandshakeAck *msg_ack = reinterpret_cast<cvmfs::MsgHandshakeAck *>( | |
229 | msg_typed); | ||
230 | 296 | cache_mgr->session_id_ = msg_ack->session_id(); | |
231 | 296 | cache_mgr->capabilities_ = msg_ack->capabilities(); | |
232 | 296 | cache_mgr->max_object_size_ = msg_ack->max_object_size(); | |
233 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 296 times.
|
296 | assert(cache_mgr->max_object_size_ > 0); |
234 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 296 times.
|
296 | if (cache_mgr->max_object_size_ > kMaxSupportedObjectSize) { |
235 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslogErr, | |
236 | "external cache manager object size too large (%u)", | ||
237 | ✗ | cache_mgr->max_object_size_); | |
238 | ✗ | return NULL; | |
239 | } | ||
240 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 296 times.
|
296 | if (cache_mgr->max_object_size_ < kMinSupportedObjectSize) { |
241 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslogErr, | |
242 | "external cache manager object size too small (%u)", | ||
243 | ✗ | cache_mgr->max_object_size_); | |
244 | ✗ | return NULL; | |
245 | } | ||
246 |
2/2✓ Branch 1 taken 270 times.
✓ Branch 2 taken 26 times.
|
296 | if (msg_ack->has_pid()) |
247 | 270 | cache_mgr->pid_plugin_ = msg_ack->pid(); | |
248 | 296 | return cache_mgr.Release(); | |
249 | 296 | } | |
250 | |||
251 | |||
252 | /** | ||
253 | * Tries to connect to the plugin at locator, or, if it doesn't exist, spawns | ||
254 | * a new plugin using cmdline. Two processes could try to spawn the plugin at | ||
255 | * the same time. In this case, the plugin should indicate to the client to | ||
256 | * retry connecting. | ||
257 | */ | ||
258 | ✗ | ExternalCacheManager::PluginHandle *ExternalCacheManager::CreatePlugin( | |
259 | const std::string &locator, const std::vector<std::string> &cmd_line) { | ||
260 | ✗ | UniquePtr<PluginHandle> plugin_handle(new PluginHandle()); | |
261 | ✗ | unsigned num_attempts = 0; | |
262 | ✗ | bool try_again = false; | |
263 | ✗ | do { | |
264 | ✗ | num_attempts++; | |
265 | ✗ | if (num_attempts > 2) { | |
266 | // Prevent violate busy loops | ||
267 | ✗ | SafeSleepMs(1000); | |
268 | } | ||
269 | ✗ | plugin_handle->fd_connection_ = ConnectLocator(locator, num_attempts > 1); | |
270 | ✗ | if (plugin_handle->IsValid()) { | |
271 | ✗ | break; | |
272 | ✗ | } else if (plugin_handle->fd_connection_ == -EINVAL) { | |
273 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslog, "Invalid locator: %s", | |
274 | locator.c_str()); | ||
275 | ✗ | plugin_handle->error_msg_ = "Invalid locator: " + locator; | |
276 | ✗ | break; | |
277 | } else { | ||
278 | ✗ | if (num_attempts > 1) { | |
279 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogStderr, | |
280 | "Failed to connect to external cache manager: %d", | ||
281 | ✗ | plugin_handle->fd_connection_); | |
282 | } | ||
283 | ✗ | plugin_handle->error_msg_ = "Failed to connect to external cache manager"; | |
284 | } | ||
285 | |||
286 | ✗ | try_again = SpawnPlugin(cmd_line); | |
287 | } while (try_again); | ||
288 | |||
289 | ✗ | return plugin_handle.Release(); | |
290 | } | ||
291 | |||
292 | |||
293 | 2097 | void ExternalCacheManager::CtrlTxn(const Label &label, | |
294 | const int flags, | ||
295 | void *txn) { | ||
296 | 2097 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
297 | 2097 | transaction->label = label; | |
298 | 2097 | transaction->label_modified = true; | |
299 | 2097 | } | |
300 | |||
301 | |||
302 | ✗ | string ExternalCacheManager::Describe() { return "External cache manager\n"; } | |
303 | |||
304 | |||
305 | 30 | bool ExternalCacheManager::DoFreeState(void *data) { | |
306 | FdTable<ReadOnlyHandle> | ||
307 | 30 | *fd_table = reinterpret_cast<FdTable<ReadOnlyHandle> *>(data); | |
308 |
1/2✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
|
30 | delete fd_table; |
309 | 30 | return true; | |
310 | } | ||
311 | |||
312 | |||
313 | 4470 | int ExternalCacheManager::DoOpen(const shash::Any &id) { | |
314 | 4470 | int fd = -1; | |
315 | { | ||
316 | 4470 | const WriteLockGuard guard(rwlock_fd_table_); | |
317 |
1/2✓ Branch 2 taken 4470 times.
✗ Branch 3 not taken.
|
4470 | fd = fd_table_.OpenFd(ReadOnlyHandle(id)); |
318 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 4440 times.
|
4470 | if (fd < 0) { |
319 |
1/2✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
|
30 | LogCvmfs(kLogCache, kLogDebug, "error while creating new fd: %s", |
320 | strerror(-fd)); | ||
321 | 30 | return fd; | |
322 | } | ||
323 |
2/2✓ Branch 1 taken 4440 times.
✓ Branch 2 taken 30 times.
|
4470 | } |
324 | |||
325 |
1/2✓ Branch 1 taken 4440 times.
✗ Branch 2 not taken.
|
4440 | const int status_refcnt = ChangeRefcount(id, 1); |
326 |
2/2✓ Branch 0 taken 4402 times.
✓ Branch 1 taken 38 times.
|
4440 | if (status_refcnt == 0) |
327 | 4402 | return fd; | |
328 | |||
329 | 38 | const WriteLockGuard guard(rwlock_fd_table_); | |
330 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | const int retval = fd_table_.CloseFd(fd); |
331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | assert(retval == 0); |
332 | 38 | return status_refcnt; | |
333 | 38 | } | |
334 | |||
335 | |||
336 | 30 | int ExternalCacheManager::DoRestoreState(void *data) { | |
337 | // When DoRestoreState is called, we have fd 0 assigned to the root file | ||
338 | // catalog unless this is a lower layer cache in a tiered setup | ||
339 |
2/2✓ Branch 1 taken 3810 times.
✓ Branch 2 taken 30 times.
|
3840 | for (unsigned i = 1; i < fd_table_.GetMaxFds(); ++i) { |
340 |
3/6✓ Branch 2 taken 3810 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3810 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3810 times.
|
3810 | assert(fd_table_.GetHandle(i) == ReadOnlyHandle()); |
341 | } | ||
342 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | const ReadOnlyHandle handle_root = fd_table_.GetHandle(0); |
343 | |||
344 | 30 | FdTable<ReadOnlyHandle> *other = reinterpret_cast<FdTable<ReadOnlyHandle> *>( | |
345 | data); | ||
346 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | fd_table_.AssignFrom(*other); |
347 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | cvmfs::MsgIoctl msg_ioctl; |
348 | 30 | msg_ioctl.set_session_id(session_id_); | |
349 | 30 | msg_ioctl.set_conncnt_change_by(-1); | |
350 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | CacheTransport::Frame frame(&msg_ioctl); |
351 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | transport_.SendFrame(&frame); |
352 | |||
353 | 30 | int new_root_fd = -1; | |
354 |
2/4✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
|
30 | if (handle_root != ReadOnlyHandle()) { |
355 | ✗ | new_root_fd = fd_table_.OpenFd(handle_root); | |
356 | // There must be a free file descriptor because the root file catalog gets | ||
357 | // closed before a reload | ||
358 | ✗ | assert(new_root_fd >= 0); | |
359 | } | ||
360 | 30 | return new_root_fd; | |
361 | 30 | } | |
362 | |||
363 | |||
364 | 30 | void *ExternalCacheManager::DoSaveState() { | |
365 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | cvmfs::MsgIoctl msg_ioctl; |
366 | 30 | msg_ioctl.set_session_id(session_id_); | |
367 | 30 | msg_ioctl.set_conncnt_change_by(1); | |
368 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | CacheTransport::Frame frame(&msg_ioctl); |
369 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | transport_.SendFrame(&frame); |
370 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
60 | return fd_table_.Clone(); |
371 | 30 | } | |
372 | |||
373 | |||
374 | 1935 | int ExternalCacheManager::Dup(int fd) { | |
375 |
1/2✓ Branch 1 taken 1935 times.
✗ Branch 2 not taken.
|
1935 | const shash::Any id = GetHandle(fd); |
376 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 1920 times.
|
1935 | if (id == kInvalidHandle) |
377 | 15 | return -EBADF; | |
378 |
1/2✓ Branch 1 taken 1920 times.
✗ Branch 2 not taken.
|
1920 | return DoOpen(id); |
379 | } | ||
380 | |||
381 | |||
382 | 296 | ExternalCacheManager::ExternalCacheManager(int fd_connection, | |
383 | 296 | unsigned max_open_fds) | |
384 | 296 | : pid_plugin_(0) | |
385 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | , fd_table_(max_open_fds, ReadOnlyHandle()) |
386 |
1/2✓ Branch 1 taken 296 times.
✗ Branch 2 not taken.
|
296 | , transport_(fd_connection) |
387 | 296 | , session_id_(-1) | |
388 | 296 | , max_object_size_(0) | |
389 | 296 | , spawned_(false) | |
390 | 296 | , terminated_(false) | |
391 | 592 | , capabilities_(cvmfs::CAP_NONE) { | |
392 | 296 | int retval = pthread_rwlock_init(&rwlock_fd_table_, NULL); | |
393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
|
296 | assert(retval == 0); |
394 | 296 | retval = pthread_mutex_init(&lock_send_fd_, NULL); | |
395 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
|
296 | assert(retval == 0); |
396 | 296 | retval = pthread_mutex_init(&lock_inflight_rpcs_, NULL); | |
397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
|
296 | assert(retval == 0); |
398 | 296 | memset(&thread_read_, 0, sizeof(thread_read_)); | |
399 | 296 | atomic_init64(&next_request_id_); | |
400 | 296 | } | |
401 | |||
402 | |||
403 | 1176 | ExternalCacheManager::~ExternalCacheManager() { | |
404 | 588 | terminated_ = true; | |
405 | 588 | MemoryFence(); | |
406 |
1/2✓ Branch 0 taken 294 times.
✗ Branch 1 not taken.
|
588 | if (session_id_ >= 0) { |
407 | 588 | cvmfs::MsgQuit msg_quit; | |
408 | 588 | msg_quit.set_session_id(session_id_); | |
409 | 588 | CacheTransport::Frame frame(&msg_quit); | |
410 | 588 | transport_.SendFrame(&frame); | |
411 | } | ||
412 | 588 | shutdown(transport_.fd_connection(), SHUT_RDWR); | |
413 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 279 times.
|
588 | if (spawned_) |
414 | 30 | pthread_join(thread_read_, NULL); | |
415 | 588 | close(transport_.fd_connection()); | |
416 | 588 | pthread_rwlock_destroy(&rwlock_fd_table_); | |
417 | 588 | pthread_mutex_destroy(&lock_send_fd_); | |
418 | 588 | pthread_mutex_destroy(&lock_inflight_rpcs_); | |
419 | 1176 | } | |
420 | |||
421 | |||
422 | 11536 | int ExternalCacheManager::Flush(bool do_commit, Transaction *transaction) { | |
423 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11534 times.
|
11536 | if (transaction->committed) |
424 | 2 | return 0; | |
425 |
1/2✓ Branch 2 taken 9120 times.
✗ Branch 3 not taken.
|
9120 | LogCvmfs(kLogCache, kLogDebug, "flushing %u bytes for %s", |
426 | transaction->buf_pos, | ||
427 |
1/2✓ Branch 1 taken 9120 times.
✗ Branch 2 not taken.
|
18240 | std::string(transaction->id.ToString()).c_str()); |
428 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | cvmfs::MsgHash object_id; |
429 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | transport_.FillMsgHash(transaction->id, &object_id); |
430 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | cvmfs::MsgStoreReq msg_store; |
431 | 11534 | msg_store.set_session_id(session_id_); | |
432 | 11534 | msg_store.set_req_id(transaction->transaction_id); | |
433 | 11534 | msg_store.set_allocated_object_id(&object_id); | |
434 | 11534 | msg_store.set_part_nr((transaction->size / max_object_size_) + 1); | |
435 | 11534 | msg_store.set_expected_size(transaction->expected_size); | |
436 | 11534 | msg_store.set_last_part(do_commit); | |
437 | |||
438 |
2/2✓ Branch 0 taken 11526 times.
✓ Branch 1 taken 8 times.
|
11534 | if (transaction->label_modified) { |
439 | cvmfs::EnumObjectType object_type; | ||
440 |
1/2✓ Branch 1 taken 11526 times.
✗ Branch 2 not taken.
|
11526 | transport_.FillObjectType(transaction->label.flags, &object_type); |
441 |
1/2✓ Branch 1 taken 11526 times.
✗ Branch 2 not taken.
|
11526 | msg_store.set_object_type(object_type); |
442 |
2/4✓ Branch 1 taken 11526 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11526 times.
✗ Branch 5 not taken.
|
11526 | msg_store.set_description(transaction->label.GetDescription()); |
443 | } | ||
444 | |||
445 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | RpcJob rpc_job(&msg_store); |
446 | 11534 | rpc_job.set_attachment_send(transaction->buffer, transaction->buf_pos); | |
447 | // TODO(jblomer): allow for out of order chunk upload | ||
448 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | CallRemotely(&rpc_job); |
449 | 11534 | msg_store.release_object_id(); | |
450 | |||
451 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | cvmfs::MsgStoreReply *msg_reply = rpc_job.msg_store_reply(); |
452 |
1/2✓ Branch 1 taken 11534 times.
✗ Branch 2 not taken.
|
11534 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
453 | 11534 | transaction->flushed = true; | |
454 |
2/2✓ Branch 0 taken 2122 times.
✓ Branch 1 taken 9412 times.
|
11534 | if (do_commit) |
455 | 2122 | transaction->committed = true; | |
456 | } | ||
457 | 11534 | return Ack2Errno(msg_reply->status()); | |
458 | 11534 | } | |
459 | |||
460 | |||
461 | 2757 | shash::Any ExternalCacheManager::GetHandle(int fd) { | |
462 | 2757 | const ReadLockGuard guard(rwlock_fd_table_); | |
463 |
1/2✓ Branch 1 taken 2757 times.
✗ Branch 2 not taken.
|
2742 | const ReadOnlyHandle handle = fd_table_.GetHandle(fd); |
464 | 2757 | return handle.id; | |
465 | 2757 | } | |
466 | |||
467 | |||
468 | 279 | int64_t ExternalCacheManager::GetSize(int fd) { | |
469 |
1/2✓ Branch 1 taken 279 times.
✗ Branch 2 not taken.
|
279 | const shash::Any id = GetHandle(fd); |
470 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 264 times.
|
279 | if (id == kInvalidHandle) |
471 | 15 | return -EBADF; | |
472 | |||
473 |
1/2✓ Branch 1 taken 249 times.
✗ Branch 2 not taken.
|
264 | cvmfs::MsgHash object_id; |
474 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
249 | transport_.FillMsgHash(id, &object_id); |
475 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
264 | cvmfs::MsgObjectInfoReq msg_info; |
476 | 264 | msg_info.set_session_id(session_id_); | |
477 | 264 | msg_info.set_req_id(NextRequestId()); | |
478 | 264 | msg_info.set_allocated_object_id(&object_id); | |
479 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
264 | RpcJob rpc_job(&msg_info); |
480 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
264 | CallRemotely(&rpc_job); |
481 | 264 | msg_info.release_object_id(); | |
482 | |||
483 |
1/2✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
|
264 | cvmfs::MsgObjectInfoReply *msg_reply = rpc_job.msg_object_info_reply(); |
484 |
2/2✓ Branch 1 taken 249 times.
✓ Branch 2 taken 15 times.
|
264 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
485 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 249 times.
|
249 | assert(msg_reply->has_size()); |
486 | 249 | return msg_reply->size(); | |
487 | } | ||
488 | 15 | return Ack2Errno(msg_reply->status()); | |
489 | 264 | } | |
490 | |||
491 | |||
492 | 15 | void *ExternalCacheManager::MainRead(void *data) { | |
493 | 15 | ExternalCacheManager *cache_mgr = reinterpret_cast<ExternalCacheManager *>( | |
494 | data); | ||
495 | 15 | LogCvmfs(kLogCache, kLogDebug, "starting external cache reader thread"); | |
496 | |||
497 | 15 | unsigned char buffer[cache_mgr->max_object_size_]; | |
498 | while (true) { | ||
499 |
1/2✓ Branch 1 taken 45435 times.
✗ Branch 2 not taken.
|
45435 | CacheTransport::Frame frame_recv; |
500 | 45435 | frame_recv.set_attachment(buffer, cache_mgr->max_object_size_); | |
501 |
1/2✓ Branch 1 taken 45435 times.
✗ Branch 2 not taken.
|
45435 | const bool retval = cache_mgr->transport_.RecvFrame(&frame_recv); |
502 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 45420 times.
|
45435 | if (!retval) |
503 | 15 | break; | |
504 | |||
505 | uint64_t req_id; | ||
506 | 45420 | uint64_t part_nr = 0; | |
507 |
1/2✓ Branch 1 taken 45420 times.
✗ Branch 2 not taken.
|
45420 | google::protobuf::MessageLite *msg = frame_recv.GetMsgTyped(); |
508 |
3/4✓ Branch 1 taken 45420 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 285 times.
✓ Branch 6 taken 45135 times.
|
45420 | if (msg->GetTypeName() == "cvmfs.MsgRefcountReply") { |
509 | 285 | req_id = reinterpret_cast<cvmfs::MsgRefcountReply *>(msg)->req_id(); | |
510 |
3/4✓ Branch 1 taken 45135 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 135 times.
✓ Branch 6 taken 45000 times.
|
45135 | } else if (msg->GetTypeName() == "cvmfs.MsgObjectInfoReply") { |
511 | 135 | req_id = reinterpret_cast<cvmfs::MsgObjectInfoReply *>(msg)->req_id(); | |
512 |
3/4✓ Branch 1 taken 45000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 27000 times.
✓ Branch 6 taken 18000 times.
|
45000 | } else if (msg->GetTypeName() == "cvmfs.MsgReadReply") { |
513 | 27000 | req_id = reinterpret_cast<cvmfs::MsgReadReply *>(msg)->req_id(); | |
514 |
3/4✓ Branch 1 taken 18000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 3000 times.
✓ Branch 6 taken 15000 times.
|
18000 | } else if (msg->GetTypeName() == "cvmfs.MsgStoreReply") { |
515 | 3000 | req_id = reinterpret_cast<cvmfs::MsgStoreReply *>(msg)->req_id(); | |
516 | 3000 | part_nr = reinterpret_cast<cvmfs::MsgStoreReply *>(msg)->part_nr(); | |
517 |
2/4✓ Branch 1 taken 15000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15000 times.
|
15000 | } else if (msg->GetTypeName() == "cvmfs.MsgInfoReply") { |
518 | ✗ | req_id = reinterpret_cast<cvmfs::MsgInfoReply *>(msg)->req_id(); | |
519 |
2/4✓ Branch 1 taken 15000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15000 times.
|
15000 | } else if (msg->GetTypeName() == "cvmfs.MsgShrinkReply") { |
520 | ✗ | req_id = reinterpret_cast<cvmfs::MsgShrinkReply *>(msg)->req_id(); | |
521 |
2/4✓ Branch 1 taken 15000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15000 times.
|
15000 | } else if (msg->GetTypeName() == "cvmfs.MsgListReply") { |
522 | ✗ | req_id = reinterpret_cast<cvmfs::MsgListReply *>(msg)->req_id(); | |
523 |
2/4✓ Branch 1 taken 15000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15000 times.
|
15000 | } else if (msg->GetTypeName() == "cvmfs.MsgBreadcrumbReply") { |
524 | ✗ | req_id = reinterpret_cast<cvmfs::MsgBreadcrumbReply *>(msg)->req_id(); | |
525 |
2/4✓ Branch 1 taken 15000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 15000 times.
✗ Branch 6 not taken.
|
15000 | } else if (msg->GetTypeName() == "cvmfs.MsgDetach") { |
526 | // Release pinned catalogs | ||
527 |
2/4✓ Branch 2 taken 15000 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 15000 times.
✗ Branch 6 not taken.
|
15000 | cache_mgr->quota_mgr_->BroadcastBackchannels("R"); |
528 | 15000 | continue; | |
529 | } else { | ||
530 | ✗ | PANIC(kLogSyslogErr | kLogDebug, "unexpected message %s", | |
531 | std::string(msg->GetTypeName()).c_str()); | ||
532 | } | ||
533 | |||
534 | 30420 | RpcInFlight rpc_inflight; | |
535 | { | ||
536 | 30420 | const MutexLockGuard guard(cache_mgr->lock_inflight_rpcs_); | |
537 |
1/2✓ Branch 1 taken 30480 times.
✗ Branch 2 not taken.
|
30480 | for (unsigned i = 0; i < cache_mgr->inflight_rpcs_.size(); ++i) { |
538 | 30480 | RpcJob *rpc_job = cache_mgr->inflight_rpcs_[i].rpc_job; | |
539 |
5/6✓ Branch 1 taken 30420 times.
✓ Branch 2 taken 60 times.
✓ Branch 4 taken 30420 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 30420 times.
✓ Branch 7 taken 60 times.
|
30480 | if ((rpc_job->req_id() == req_id) && (rpc_job->part_nr() == part_nr)) { |
540 | 30420 | rpc_inflight = cache_mgr->inflight_rpcs_[i]; | |
541 |
1/2✓ Branch 2 taken 30420 times.
✗ Branch 3 not taken.
|
30420 | cache_mgr->inflight_rpcs_.erase(cache_mgr->inflight_rpcs_.begin() |
542 | 30420 | + i); | |
543 | 30420 | break; | |
544 | } | ||
545 | } | ||
546 | 30420 | } | |
547 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30420 times.
|
30420 | if (rpc_inflight.rpc_job == NULL) { |
548 | ✗ | LogCvmfs(kLogCache, kLogSyslogWarn | kLogDebug, | |
549 | "got unmatched rpc reply"); | ||
550 | ✗ | continue; | |
551 | } | ||
552 |
1/2✓ Branch 2 taken 30420 times.
✗ Branch 3 not taken.
|
30420 | rpc_inflight.rpc_job->frame_recv()->MergeFrom(frame_recv); |
553 |
1/2✓ Branch 1 taken 30420 times.
✗ Branch 2 not taken.
|
30420 | rpc_inflight.signal->Wakeup(); |
554 |
3/3✓ Branch 1 taken 30420 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15000 times.
|
90855 | } |
555 | |||
556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!cache_mgr->terminated_) { |
557 | ✗ | PANIC(kLogSyslogErr | kLogDebug, | |
558 | "connection to external cache manager broken (%d)", errno); | ||
559 | } | ||
560 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | LogCvmfs(kLogCache, kLogDebug, "stopping external cache reader thread"); |
561 | 15 | return NULL; | |
562 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | } |
563 | |||
564 | |||
565 | 2550 | int ExternalCacheManager::Open(const LabeledObject &object) { | |
566 | 2550 | return DoOpen(object.id); | |
567 | } | ||
568 | |||
569 | |||
570 | 2 | int ExternalCacheManager::OpenFromTxn(void *txn) { | |
571 | 2 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
572 | ✗ | LogCvmfs(kLogCache, kLogDebug, "open fd for transaction %s", | |
573 | ✗ | std::string(transaction->id.ToString()).c_str()); | |
574 | 2 | const int retval = Flush(true, transaction); | |
575 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (retval != 0) |
576 | ✗ | return retval; | |
577 | |||
578 | 2 | int fd = -1; | |
579 | { | ||
580 | 2 | const WriteLockGuard guard(rwlock_fd_table_); | |
581 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | fd = fd_table_.OpenFd(ReadOnlyHandle(transaction->id)); |
582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (fd < 0) { |
583 | ✗ | LogCvmfs(kLogCache, kLogDebug, "error while creating new fd: %s", | |
584 | strerror(-fd)); | ||
585 | ✗ | return fd; | |
586 | } | ||
587 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | } |
588 | 2 | transaction->open_fds++; | |
589 | 2 | return fd; | |
590 | } | ||
591 | |||
592 | |||
593 | 513 | int64_t ExternalCacheManager::Pread(int fd, | |
594 | void *buf, | ||
595 | uint64_t size, | ||
596 | uint64_t offset) { | ||
597 |
1/2✓ Branch 1 taken 513 times.
✗ Branch 2 not taken.
|
513 | const shash::Any id = GetHandle(fd); |
598 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 498 times.
|
513 | if (id == kInvalidHandle) |
599 | 15 | return -EBADF; | |
600 | |||
601 |
1/2✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
|
498 | cvmfs::MsgHash object_id; |
602 |
1/2✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
|
498 | transport_.FillMsgHash(id, &object_id); |
603 | 498 | uint64_t nbytes = 0; | |
604 |
2/2✓ Branch 0 taken 33832 times.
✓ Branch 1 taken 428 times.
|
34260 | while (nbytes < size) { |
605 | const uint64_t batch_size = | ||
606 | 33832 | std::min(size - nbytes, static_cast<uint64_t>(max_object_size_)); | |
607 |
1/2✓ Branch 1 taken 33817 times.
✗ Branch 2 not taken.
|
33832 | cvmfs::MsgReadReq msg_read; |
608 | 33817 | msg_read.set_session_id(session_id_); | |
609 | 33802 | msg_read.set_req_id(NextRequestId()); | |
610 | 33787 | msg_read.set_allocated_object_id(&object_id); | |
611 | 33787 | msg_read.set_offset(offset + nbytes); | |
612 | 33787 | msg_read.set_size(batch_size); | |
613 |
1/2✓ Branch 1 taken 33832 times.
✗ Branch 2 not taken.
|
33817 | RpcJob rpc_job(&msg_read); |
614 | 33832 | rpc_job.set_attachment_recv(reinterpret_cast<char *>(buf) + nbytes, | |
615 | batch_size); | ||
616 |
1/2✓ Branch 1 taken 33862 times.
✗ Branch 2 not taken.
|
33832 | CallRemotely(&rpc_job); |
617 | 33862 | msg_read.release_object_id(); | |
618 | |||
619 |
1/2✓ Branch 1 taken 33787 times.
✗ Branch 2 not taken.
|
33862 | cvmfs::MsgReadReply *msg_reply = rpc_job.msg_read_reply(); |
620 |
2/2✓ Branch 1 taken 33783 times.
✓ Branch 2 taken 19 times.
|
33787 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
621 | 33783 | nbytes += rpc_job.frame_recv()->att_size(); | |
622 | // Fuse sends in rounded up buffers, so short reads are expected | ||
623 |
2/2✓ Branch 2 taken 51 times.
✓ Branch 3 taken 33717 times.
|
33768 | if (rpc_job.frame_recv()->att_size() < batch_size) |
624 | 51 | return nbytes; | |
625 | } else { | ||
626 | 19 | return Ack2Errno(msg_reply->status()); | |
627 | } | ||
628 |
4/4✓ Branch 1 taken 33762 times.
✓ Branch 2 taken 70 times.
✓ Branch 4 taken 33762 times.
✓ Branch 5 taken 70 times.
|
33857 | } |
629 | 428 | return size; | |
630 | 498 | } | |
631 | |||
632 | |||
633 | 30 | int ExternalCacheManager::Readahead(int fd) { | |
634 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | const shash::Any id = GetHandle(fd); |
635 |
2/2✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
|
30 | if (id == kInvalidHandle) |
636 | 15 | return -EBADF; | |
637 | // No-op | ||
638 | 15 | return 0; | |
639 | } | ||
640 | |||
641 | |||
642 | 49 | int ExternalCacheManager::Reset(void *txn) { | |
643 | 49 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
644 | 49 | transaction->buf_pos = 0; | |
645 | 49 | transaction->size = 0; | |
646 | 49 | transaction->open_fds = 0; | |
647 | 49 | transaction->committed = false; | |
648 | 49 | transaction->label_modified = true; | |
649 | |||
650 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 15 times.
|
49 | if (!transaction->flushed) |
651 | 34 | return 0; | |
652 | |||
653 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | cvmfs::MsgHash object_id; |
654 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | transport_.FillMsgHash(transaction->id, &object_id); |
655 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | cvmfs::MsgStoreAbortReq msg_abort; |
656 | 15 | msg_abort.set_session_id(session_id_); | |
657 | 15 | msg_abort.set_req_id(transaction->transaction_id); | |
658 | 15 | msg_abort.set_allocated_object_id(&object_id); | |
659 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | RpcJob rpc_job(&msg_abort); |
660 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | CallRemotely(&rpc_job); |
661 | 15 | msg_abort.release_object_id(); | |
662 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | cvmfs::MsgStoreReply *msg_reply = rpc_job.msg_store_reply(); |
663 | 15 | transaction->transaction_id = NextRequestId(); | |
664 | 15 | transaction->flushed = false; | |
665 | 15 | return Ack2Errno(msg_reply->status()); | |
666 | 15 | } | |
667 | |||
668 | |||
669 | 34 | manifest::Breadcrumb ExternalCacheManager::LoadBreadcrumb( | |
670 | const std::string &fqrn) { | ||
671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (!(capabilities_ & cvmfs::CAP_BREADCRUMB)) |
672 | ✗ | return manifest::Breadcrumb(); | |
673 | |||
674 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | cvmfs::MsgBreadcrumbLoadReq msg_breadcrumb_load; |
675 | 34 | msg_breadcrumb_load.set_session_id(session_id_); | |
676 | 34 | msg_breadcrumb_load.set_req_id(NextRequestId()); | |
677 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | msg_breadcrumb_load.set_fqrn(fqrn); |
678 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | RpcJob rpc_job(&msg_breadcrumb_load); |
679 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | CallRemotely(&rpc_job); |
680 | |||
681 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | manifest::Breadcrumb breadcrumb; |
682 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | cvmfs::MsgBreadcrumbReply *msg_reply = rpc_job.msg_breadcrumb_reply(); |
683 |
2/2✓ Branch 1 taken 17 times.
✓ Branch 2 taken 17 times.
|
34 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
684 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
|
17 | assert(msg_reply->has_breadcrumb()); |
685 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
|
17 | assert(msg_reply->breadcrumb().fqrn() == fqrn); |
686 |
1/2✓ Branch 3 taken 17 times.
✗ Branch 4 not taken.
|
17 | const bool rv = transport_.ParseMsgHash(msg_reply->breadcrumb().hash(), |
687 | &breadcrumb.catalog_hash); | ||
688 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | assert(rv); |
689 | 17 | breadcrumb.catalog_hash.suffix = shash::kSuffixCatalog; | |
690 | 17 | breadcrumb.timestamp = msg_reply->breadcrumb().timestamp(); | |
691 |
1/2✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | if (msg_reply->breadcrumb().has_revision()) { |
692 | 17 | breadcrumb.revision = msg_reply->breadcrumb().revision(); | |
693 | } else { | ||
694 | ✗ | breadcrumb.revision = 0; | |
695 | } | ||
696 | } | ||
697 | 34 | return breadcrumb; | |
698 | 34 | } | |
699 | |||
700 | |||
701 | 17 | bool ExternalCacheManager::StoreBreadcrumb(const manifest::Manifest &manifest) { | |
702 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!(capabilities_ & cvmfs::CAP_BREADCRUMB)) |
703 | ✗ | return false; | |
704 | |||
705 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | cvmfs::MsgHash hash; |
706 |
1/2✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | transport_.FillMsgHash(manifest.catalog_hash(), &hash); |
707 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | cvmfs::MsgBreadcrumb breadcrumb; |
708 |
2/4✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 17 times.
✗ Branch 5 not taken.
|
17 | breadcrumb.set_fqrn(manifest.repository_name()); |
709 | 17 | breadcrumb.set_allocated_hash(&hash); | |
710 | 17 | breadcrumb.set_timestamp(manifest.publish_timestamp()); | |
711 | 17 | breadcrumb.set_revision(manifest.revision()); | |
712 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | cvmfs::MsgBreadcrumbStoreReq msg_breadcrumb_store; |
713 | 17 | msg_breadcrumb_store.set_session_id(session_id_); | |
714 | 17 | msg_breadcrumb_store.set_req_id(NextRequestId()); | |
715 | 17 | msg_breadcrumb_store.set_allocated_breadcrumb(&breadcrumb); | |
716 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | RpcJob rpc_job(&msg_breadcrumb_store); |
717 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | CallRemotely(&rpc_job); |
718 | 17 | msg_breadcrumb_store.release_breadcrumb(); | |
719 | 17 | breadcrumb.release_hash(); | |
720 | |||
721 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | cvmfs::MsgBreadcrumbReply *msg_reply = rpc_job.msg_breadcrumb_reply(); |
722 | 17 | return msg_reply->status() == cvmfs::STATUS_OK; | |
723 | 17 | } | |
724 | |||
725 | |||
726 | 15 | void ExternalCacheManager::Spawn() { | |
727 | 15 | const int retval = pthread_create(&thread_read_, NULL, MainRead, this); | |
728 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | assert(retval == 0); |
729 | 15 | spawned_ = true; | |
730 | 15 | } | |
731 | |||
732 | |||
733 | /** | ||
734 | * Returns true if the plugin could be spawned or was spawned by another | ||
735 | * process. | ||
736 | */ | ||
737 | ✗ | bool ExternalCacheManager::SpawnPlugin(const vector<string> &cmd_line) { | |
738 | ✗ | if (cmd_line.empty()) | |
739 | ✗ | return false; | |
740 | |||
741 | int pipe_ready[2]; | ||
742 | ✗ | MakePipe(pipe_ready); | |
743 | ✗ | set<int> preserve_filedes; | |
744 | ✗ | preserve_filedes.insert(pipe_ready[1]); | |
745 | |||
746 | ✗ | const int fd_null_read = open("/dev/null", O_RDONLY); | |
747 | ✗ | const int fd_null_write = open("/dev/null", O_WRONLY); | |
748 | ✗ | assert((fd_null_read >= 0) && (fd_null_write >= 0)); | |
749 | ✗ | map<int, int> map_fildes; | |
750 | ✗ | map_fildes[fd_null_read] = 0; | |
751 | ✗ | map_fildes[fd_null_write] = 1; | |
752 | ✗ | map_fildes[fd_null_write] = 2; | |
753 | |||
754 | pid_t child_pid; | ||
755 | ✗ | int retval = setenv(CacheTransport::kEnvReadyNotifyFd, | |
756 | ✗ | StringifyInt(pipe_ready[1]).c_str(), 1); | |
757 | ✗ | assert(retval == 0); | |
758 | ✗ | retval = ManagedExec(cmd_line, | |
759 | preserve_filedes, | ||
760 | map_fildes, | ||
761 | false, // drop_credentials | ||
762 | false, // clear_env | ||
763 | true, // double fork | ||
764 | &child_pid); | ||
765 | ✗ | unsetenv(CacheTransport::kEnvReadyNotifyFd); | |
766 | ✗ | close(fd_null_read); | |
767 | ✗ | close(fd_null_write); | |
768 | ✗ | if (!retval) { | |
769 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslogErr, | |
770 | "failed to start cache plugin '%s'", | ||
771 | ✗ | JoinStrings(cmd_line, " ").c_str()); | |
772 | ✗ | ClosePipe(pipe_ready); | |
773 | ✗ | return false; | |
774 | } | ||
775 | |||
776 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslog, | |
777 | "started cache plugin '%s' (pid %d), waiting for it to become ready", | ||
778 | ✗ | JoinStrings(cmd_line, " ").c_str(), child_pid); | |
779 | ✗ | close(pipe_ready[1]); | |
780 | char buf; | ||
781 | ✗ | if (read(pipe_ready[0], &buf, 1) != 1) { | |
782 | ✗ | close(pipe_ready[0]); | |
783 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslogErr, | |
784 | "cache plugin did not start properly"); | ||
785 | ✗ | return false; | |
786 | } | ||
787 | ✗ | close(pipe_ready[0]); | |
788 | |||
789 | ✗ | if (buf == CacheTransport::kReadyNotification) | |
790 | ✗ | return true; | |
791 | ✗ | LogCvmfs(kLogCache, kLogDebug | kLogSyslogErr, | |
792 | "cache plugin failed to create an endpoint"); | ||
793 | ✗ | return false; | |
794 | } | ||
795 | |||
796 | |||
797 | 2152 | int ExternalCacheManager::StartTxn(const shash::Any &id, | |
798 | uint64_t size, | ||
799 | void *txn) { | ||
800 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 2122 times.
|
2152 | if (!(capabilities_ & cvmfs::CAP_WRITE)) |
801 | 30 | return -EROFS; | |
802 | |||
803 | 2122 | Transaction *transaction = new (txn) Transaction(id); | |
804 | 2122 | transaction->expected_size = size; | |
805 | 2122 | transaction->transaction_id = NextRequestId(); | |
806 | #ifdef __APPLE__ | ||
807 | transaction->buffer = reinterpret_cast<unsigned char *>( | ||
808 | smalloc(max_object_size_)); | ||
809 | #endif | ||
810 | 2122 | return 0; | |
811 | } | ||
812 | |||
813 | |||
814 | 2154 | int64_t ExternalCacheManager::Write(const void *buf, uint64_t size, void *txn) { | |
815 | 2154 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
816 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2154 times.
|
2154 | assert(!transaction->committed); |
817 |
1/2✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
|
120 | LogCvmfs(kLogCache, kLogDebug, "writing %" PRIu64 " bytes for %s", size, |
818 | 240 | transaction->id.ToString().c_str()); | |
819 | |||
820 |
1/2✓ Branch 0 taken 2154 times.
✗ Branch 1 not taken.
|
2154 | if (transaction->expected_size != kSizeUnknown) { |
821 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2154 times.
|
2154 | if (transaction->size + size > transaction->expected_size) { |
822 | ✗ | LogCvmfs(kLogCache, kLogDebug, | |
823 | "Transaction size (%" PRIu64 ") > expected size (%" PRIu64 ")", | ||
824 | ✗ | transaction->size + size, transaction->expected_size); | |
825 | ✗ | return -EFBIG; | |
826 | } | ||
827 | } | ||
828 | |||
829 | 2154 | uint64_t written = 0; | |
830 | 2154 | const unsigned char *read_pos = reinterpret_cast<const unsigned char *>(buf); | |
831 |
2/2✓ Branch 0 taken 11549 times.
✓ Branch 1 taken 2154 times.
|
13703 | while (written < size) { |
832 |
2/2✓ Branch 0 taken 9412 times.
✓ Branch 1 taken 2137 times.
|
11549 | if (transaction->buf_pos == max_object_size_) { |
833 | 9412 | bool do_commit = false; | |
834 |
1/2✓ Branch 0 taken 9412 times.
✗ Branch 1 not taken.
|
9412 | if (transaction->expected_size != kSizeUnknown) |
835 | 9412 | do_commit = (transaction->size + written) == transaction->expected_size; | |
836 |
1/2✓ Branch 1 taken 9412 times.
✗ Branch 2 not taken.
|
9412 | const int retval = Flush(do_commit, transaction); |
837 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9412 times.
|
9412 | if (retval != 0) { |
838 | ✗ | transaction->size += written; | |
839 | ✗ | return retval; | |
840 | } | ||
841 | 9412 | transaction->size += transaction->buf_pos; | |
842 | 9412 | transaction->buf_pos = 0; | |
843 | } | ||
844 | 11549 | const uint64_t remaining = size - written; | |
845 | 11549 | const uint64_t space_in_buffer = max_object_size_ - transaction->buf_pos; | |
846 | 11549 | const uint64_t batch_size = std::min(remaining, space_in_buffer); | |
847 | 11549 | memcpy(transaction->buffer + transaction->buf_pos, read_pos, batch_size); | |
848 | 11549 | transaction->buf_pos += batch_size; | |
849 | 11549 | written += batch_size; | |
850 | 11549 | read_pos += batch_size; | |
851 | } | ||
852 | 2154 | return written; | |
853 | } | ||
854 | |||
855 | |||
856 | //------------------------------------------------------------------------------ | ||
857 | |||
858 | |||
859 | 98 | bool ExternalQuotaManager::DoListing(cvmfs::EnumObjectType type, | |
860 | vector<cvmfs::MsgListRecord> *result) { | ||
861 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
|
98 | if (!(cache_mgr_->capabilities_ & cvmfs::CAP_LIST)) |
862 | ✗ | return false; | |
863 | |||
864 | 98 | uint64_t listing_id = 0; | |
865 | 98 | bool more_data = false; | |
866 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 98 times.
|
158 | do { |
867 |
1/2✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
|
158 | cvmfs::MsgListReq msg_list; |
868 | 158 | msg_list.set_session_id(cache_mgr_->session_id_); | |
869 | 158 | msg_list.set_req_id(cache_mgr_->NextRequestId()); | |
870 | 158 | msg_list.set_listing_id(listing_id); | |
871 |
1/2✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
|
158 | msg_list.set_object_type(type); |
872 |
1/2✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
|
158 | ExternalCacheManager::RpcJob rpc_job(&msg_list); |
873 |
1/2✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
|
158 | cache_mgr_->CallRemotely(&rpc_job); |
874 | |||
875 |
1/2✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
|
158 | cvmfs::MsgListReply *msg_reply = rpc_job.msg_list_reply(); |
876 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 158 times.
|
158 | if (msg_reply->status() != cvmfs::STATUS_OK) |
877 | ✗ | return false; | |
878 | 158 | more_data = !msg_reply->is_last_part(); | |
879 | 158 | listing_id = msg_reply->listing_id(); | |
880 |
3/4✓ Branch 1 taken 3004162 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3004004 times.
✓ Branch 4 taken 158 times.
|
3004162 | for (int i = 0; i < msg_reply->list_record_size(); ++i) { |
881 |
2/4✓ Branch 1 taken 3004004 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3004004 times.
✗ Branch 5 not taken.
|
3004004 | result->push_back(msg_reply->list_record(i)); |
882 | } | ||
883 |
2/4✓ Branch 1 taken 158 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 158 times.
✗ Branch 5 not taken.
|
158 | } while (more_data); |
884 | |||
885 | 98 | return true; | |
886 | } | ||
887 | |||
888 | |||
889 | 38 | bool ExternalQuotaManager::Cleanup(const uint64_t leave_size) { | |
890 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if (!(cache_mgr_->capabilities_ & cvmfs::CAP_SHRINK)) |
891 | ✗ | return false; | |
892 | |||
893 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | cvmfs::MsgShrinkReq msg_shrink; |
894 | 38 | msg_shrink.set_session_id(cache_mgr_->session_id_); | |
895 | 38 | msg_shrink.set_req_id(cache_mgr_->NextRequestId()); | |
896 | 38 | msg_shrink.set_shrink_to(leave_size); | |
897 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | ExternalCacheManager::RpcJob rpc_job(&msg_shrink); |
898 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | cache_mgr_->CallRemotely(&rpc_job); |
899 | |||
900 |
1/2✓ Branch 1 taken 38 times.
✗ Branch 2 not taken.
|
38 | cvmfs::MsgShrinkReply *msg_reply = rpc_job.msg_shrink_reply(); |
901 | 38 | return msg_reply->status() == cvmfs::STATUS_OK; | |
902 | 38 | } | |
903 | |||
904 | |||
905 | 294 | ExternalQuotaManager *ExternalQuotaManager::Create( | |
906 | ExternalCacheManager *cache_mgr) { | ||
907 | UniquePtr<ExternalQuotaManager> quota_mgr( | ||
908 |
3/6✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 294 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 294 times.
✗ Branch 8 not taken.
|
294 | new ExternalQuotaManager(cache_mgr)); |
909 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 294 times.
|
294 | assert(quota_mgr.IsValid()); |
910 | |||
911 | 588 | return quota_mgr.Release(); | |
912 | 294 | } | |
913 | |||
914 | |||
915 | 84 | int ExternalQuotaManager::GetInfo(QuotaInfo *quota_info) { | |
916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
|
84 | if (!(cache_mgr_->capabilities_ & cvmfs::CAP_INFO)) |
917 | ✗ | return Ack2Errno(cvmfs::STATUS_NOSUPPORT); | |
918 | |||
919 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | cvmfs::MsgInfoReq msg_info; |
920 | 84 | msg_info.set_session_id(cache_mgr_->session_id_); | |
921 | 84 | msg_info.set_req_id(cache_mgr_->NextRequestId()); | |
922 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | ExternalCacheManager::RpcJob rpc_job(&msg_info); |
923 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | cache_mgr_->CallRemotely(&rpc_job); |
924 | |||
925 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | cvmfs::MsgInfoReply *msg_reply = rpc_job.msg_info_reply(); |
926 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
927 | 84 | quota_info->size = msg_reply->size_bytes(); | |
928 | 84 | quota_info->used = msg_reply->used_bytes(); | |
929 | 84 | quota_info->pinned = msg_reply->pinned_bytes(); | |
930 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | if (msg_reply->no_shrink() >= 0) |
931 | 84 | quota_info->no_shrink = msg_reply->no_shrink(); | |
932 | } | ||
933 | 84 | return Ack2Errno(msg_reply->status()); | |
934 | 84 | } | |
935 | |||
936 | |||
937 | 19 | uint64_t ExternalQuotaManager::GetCapacity() { | |
938 | 19 | QuotaInfo info; | |
939 |
1/2✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
|
19 | const int retval = GetInfo(&info); |
940 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | if (retval != 0) |
941 | ✗ | return uint64_t(-1); | |
942 | 19 | return info.size; | |
943 | } | ||
944 | |||
945 | |||
946 | ✗ | uint64_t ExternalQuotaManager::GetCleanupRate(uint64_t period_s) { | |
947 | ✗ | QuotaInfo info; | |
948 | ✗ | const int retval = GetInfo(&info); | |
949 | ✗ | if (retval != 0) | |
950 | ✗ | return 0; | |
951 | ✗ | return info.no_shrink; | |
952 | } | ||
953 | |||
954 | |||
955 | 29 | uint64_t ExternalQuotaManager::GetSize() { | |
956 | 29 | QuotaInfo info; | |
957 |
1/2✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
|
29 | const int retval = GetInfo(&info); |
958 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
|
29 | if (retval != 0) |
959 | ✗ | return 0; | |
960 | 29 | return info.used; | |
961 | } | ||
962 | |||
963 | |||
964 | 36 | uint64_t ExternalQuotaManager::GetSizePinned() { | |
965 | 36 | QuotaInfo info; | |
966 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | const int retval = GetInfo(&info); |
967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if (retval != 0) |
968 | ✗ | return 0; | |
969 | 36 | return info.pinned; | |
970 | } | ||
971 | |||
972 | |||
973 | ✗ | bool ExternalQuotaManager::HasCapability(Capabilities capability) { | |
974 | ✗ | switch (capability) { | |
975 | ✗ | case kCapIntrospectSize: | |
976 | ✗ | return cache_mgr_->capabilities_ & cvmfs::CAP_INFO; | |
977 | ✗ | case kCapIntrospectCleanupRate: | |
978 | ✗ | return cache_mgr_->capabilities_ & cvmfs::CAP_SHRINK_RATE; | |
979 | ✗ | case kCapList: | |
980 | ✗ | return cache_mgr_->capabilities_ & cvmfs::CAP_LIST; | |
981 | ✗ | case kCapShrink: | |
982 | ✗ | return cache_mgr_->capabilities_ & cvmfs::CAP_SHRINK; | |
983 | ✗ | case kCapListeners: | |
984 | ✗ | return true; | |
985 | ✗ | default: | |
986 | ✗ | return false; | |
987 | } | ||
988 | } | ||
989 | |||
990 | |||
991 | 17 | vector<string> ExternalQuotaManager::List() { | |
992 | 17 | vector<string> result; | |
993 | 17 | vector<cvmfs::MsgListRecord> raw_list; | |
994 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | const bool retval = DoListing(cvmfs::OBJECT_REGULAR, &raw_list); |
995 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!retval) |
996 | ✗ | return result; | |
997 |
2/2✓ Branch 1 taken 1502002 times.
✓ Branch 2 taken 17 times.
|
1502019 | for (unsigned i = 0; i < raw_list.size(); ++i) |
998 |
1/2✓ Branch 3 taken 1502002 times.
✗ Branch 4 not taken.
|
1502002 | result.push_back(raw_list[i].description()); |
999 | 17 | return result; | |
1000 | 17 | } | |
1001 | |||
1002 | |||
1003 | 15 | vector<string> ExternalQuotaManager::ListCatalogs() { | |
1004 | 15 | vector<string> result; | |
1005 | 15 | vector<cvmfs::MsgListRecord> raw_list; | |
1006 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | const bool retval = DoListing(cvmfs::OBJECT_CATALOG, &raw_list); |
1007 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!retval) |
1008 | ✗ | return result; | |
1009 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | for (unsigned i = 0; i < raw_list.size(); ++i) |
1010 | ✗ | result.push_back(raw_list[i].description()); | |
1011 | 15 | return result; | |
1012 | 15 | } | |
1013 | |||
1014 | |||
1015 | 17 | vector<string> ExternalQuotaManager::ListPinned() { | |
1016 | 17 | vector<string> result; | |
1017 |
2/2✓ Branch 1 taken 51 times.
✓ Branch 2 taken 17 times.
|
136 | vector<cvmfs::MsgListRecord> raw_lists[3]; |
1018 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | bool retval = DoListing(cvmfs::OBJECT_REGULAR, &raw_lists[0]); |
1019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!retval) |
1020 | ✗ | return result; | |
1021 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | retval = DoListing(cvmfs::OBJECT_CATALOG, &raw_lists[1]); |
1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!retval) |
1023 | ✗ | return result; | |
1024 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | retval = DoListing(cvmfs::OBJECT_VOLATILE, &raw_lists[2]); |
1025 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!retval) |
1026 | ✗ | return result; | |
1027 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 17 times.
|
68 | for (unsigned i = 0; i < sizeof(raw_lists) / sizeof(raw_lists[0]); ++i) { |
1028 |
2/2✓ Branch 1 taken 1502002 times.
✓ Branch 2 taken 51 times.
|
1502053 | for (unsigned j = 0; j < raw_lists[i].size(); ++j) { |
1029 |
2/2✓ Branch 2 taken 200 times.
✓ Branch 3 taken 1501802 times.
|
1502002 | if (raw_lists[i][j].pinned()) |
1030 |
1/2✓ Branch 3 taken 200 times.
✗ Branch 4 not taken.
|
200 | result.push_back(raw_lists[i][j].description()); |
1031 | } | ||
1032 | } | ||
1033 | 17 | return result; | |
1034 |
2/4✓ Branch 0 taken 51 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
68 | } |
1035 | |||
1036 | |||
1037 | 15 | vector<string> ExternalQuotaManager::ListVolatile() { | |
1038 | 15 | vector<string> result; | |
1039 | 15 | vector<cvmfs::MsgListRecord> raw_list; | |
1040 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | const bool retval = DoListing(cvmfs::OBJECT_VOLATILE, &raw_list); |
1041 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | if (!retval) |
1042 | ✗ | return result; | |
1043 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | for (unsigned i = 0; i < raw_list.size(); ++i) |
1044 | ✗ | result.push_back(raw_list[i].description()); | |
1045 | 15 | return result; | |
1046 | 15 | } | |
1047 | |||
1048 | |||
1049 | 15 | void ExternalQuotaManager::RegisterBackChannel(int back_channel[2], | |
1050 | const string &channel_id) { | ||
1051 |
1/2✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | const shash::Md5 hash_id = shash::Md5(shash::AsciiPtr(channel_id)); |
1052 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | MakePipe(back_channel); |
1053 | 15 | LockBackChannels(); | |
1054 |
2/4✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
|
15 | assert(back_channels_.find(hash_id) == back_channels_.end()); |
1055 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | back_channels_[hash_id] = back_channel[1]; |
1056 | 15 | UnlockBackChannels(); | |
1057 | 15 | } | |
1058 | |||
1059 | |||
1060 | 15 | void ExternalQuotaManager::UnregisterBackChannel(int back_channel[2], | |
1061 | const string &channel_id) { | ||
1062 |
1/2✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | const shash::Md5 hash_id = shash::Md5(shash::AsciiPtr(channel_id)); |
1063 | 15 | LockBackChannels(); | |
1064 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | back_channels_.erase(hash_id); |
1065 | 15 | UnlockBackChannels(); | |
1066 |
1/2✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
|
15 | ClosePipe(back_channel); |
1067 | 15 | } | |
1068 |