Directory: | cvmfs/ |
---|---|
File: | cvmfs/cache_extern.cc |
Date: | 2025-06-29 02:35:41 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 554 | 720 | 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 | 21424 | int Ack2Errno(cvmfs::EnumStatus status_code) { | |
43 |
4/12✓ Branch 0 taken 21356 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 28 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
|
21424 | switch (status_code) { |
44 | 21356 | case cvmfs::STATUS_OK: | |
45 | 21356 | 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 | 22 | case cvmfs::STATUS_NOENTRY: | |
53 | 22 | return -ENOENT; | |
54 | 28 | case cvmfs::STATUS_MALFORMED: | |
55 | 28 | 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 | 18 | case cvmfs::STATUS_OUTOFBOUNDS: | |
65 | 18 | 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 | 276 | bool ExternalCacheManager::AcquireQuotaManager(QuotaManager *quota_mgr) { | |
86 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
|
276 | assert(quota_mgr != NULL); |
87 | 276 | quota_mgr_ = quota_mgr; | |
88 | 252 | LogCvmfs(kLogCache, kLogDebug, "set quota manager"); | |
89 | 276 | return true; | |
90 | } | ||
91 | |||
92 | |||
93 | 53551 | void ExternalCacheManager::CallRemotely(ExternalCacheManager::RpcJob *rpc_job) { | |
94 |
2/2✓ Branch 0 taken 25159 times.
✓ Branch 1 taken 28392 times.
|
53551 | if (!spawned_) { |
95 | 25159 | transport_.SendFrame(rpc_job->frame_send()); | |
96 | 25159 | const uint32_t save_att_size = rpc_job->frame_recv()->att_size(); | |
97 | bool again; | ||
98 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 25159 times.
|
25173 | do { |
99 | 25173 | again = false; | |
100 | 25173 | const bool retval = transport_.RecvFrame(rpc_job->frame_recv()); | |
101 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 25173 times.
|
25173 | assert(retval); |
102 |
2/2✓ Branch 2 taken 14 times.
✓ Branch 3 taken 25159 times.
|
25173 | if (rpc_job->frame_recv()->IsMsgOutOfBand()) { |
103 | google::protobuf::MessageLite *msg_typed = rpc_job->frame_recv() | ||
104 | 14 | ->GetMsgTyped(); | |
105 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
|
14 | assert(msg_typed->GetTypeName() == "cvmfs.MsgDetach"); |
106 |
2/4✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
|
14 | quota_mgr_->BroadcastBackchannels("R"); // release pinned catalogs |
107 | 14 | rpc_job->frame_recv()->Reset(save_att_size); | |
108 | 14 | again = true; | |
109 | } | ||
110 | } while (again); | ||
111 | } else { | ||
112 |
1/2✓ Branch 1 taken 28378 times.
✗ Branch 2 not taken.
|
28392 | Signal signal; |
113 | { | ||
114 | 28378 | const MutexLockGuard guard(lock_inflight_rpcs_); | |
115 |
1/2✓ Branch 2 taken 28392 times.
✗ Branch 3 not taken.
|
28392 | inflight_rpcs_.push_back(RpcInFlight(rpc_job, &signal)); |
116 | 28392 | } | |
117 | { | ||
118 | 28392 | const MutexLockGuard guard(lock_send_fd_); | |
119 |
1/2✓ Branch 2 taken 28392 times.
✗ Branch 3 not taken.
|
28392 | transport_.SendFrame(rpc_job->frame_send()); |
120 | 28392 | } | |
121 |
1/2✓ Branch 1 taken 28378 times.
✗ Branch 2 not taken.
|
28392 | signal.Wait(); |
122 | 28378 | } | |
123 | 53509 | } | |
124 | |||
125 | |||
126 | 10400 | int ExternalCacheManager::ChangeRefcount(const shash::Any &id, int change_by) { | |
127 |
1/2✓ Branch 1 taken 10400 times.
✗ Branch 2 not taken.
|
10400 | cvmfs::MsgHash object_id; |
128 |
1/2✓ Branch 1 taken 10400 times.
✗ Branch 2 not taken.
|
10400 | transport_.FillMsgHash(id, &object_id); |
129 |
1/2✓ Branch 1 taken 10400 times.
✗ Branch 2 not taken.
|
10400 | cvmfs::MsgRefcountReq msg_refcount; |
130 | 10400 | msg_refcount.set_session_id(session_id_); | |
131 | 10400 | msg_refcount.set_req_id(NextRequestId()); | |
132 | 10400 | msg_refcount.set_allocated_object_id(&object_id); | |
133 | 10400 | msg_refcount.set_change_by(change_by); | |
134 |
1/2✓ Branch 1 taken 10400 times.
✗ Branch 2 not taken.
|
10400 | RpcJob rpc_job(&msg_refcount); |
135 |
1/2✓ Branch 1 taken 10372 times.
✗ Branch 2 not taken.
|
10400 | CallRemotely(&rpc_job); |
136 | 10372 | msg_refcount.release_object_id(); | |
137 | |||
138 |
1/2✓ Branch 1 taken 10372 times.
✗ Branch 2 not taken.
|
10372 | cvmfs::MsgRefcountReply *msg_reply = rpc_job.msg_refcount_reply(); |
139 | 20772 | return Ack2Errno(msg_reply->status()); | |
140 | 10372 | } | |
141 | |||
142 | |||
143 | 4140 | int ExternalCacheManager::Close(int fd) { | |
144 | 4140 | ReadOnlyHandle handle; | |
145 | { | ||
146 | 4140 | const WriteLockGuard guard(rwlock_fd_table_); | |
147 |
1/2✓ Branch 1 taken 4140 times.
✗ Branch 2 not taken.
|
4140 | handle = fd_table_.GetHandle(fd); |
148 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 4126 times.
|
4140 | if (handle.id == kInvalidHandle) |
149 | 14 | return -EBADF; | |
150 |
1/2✓ Branch 1 taken 4126 times.
✗ Branch 2 not taken.
|
4126 | const int retval = fd_table_.CloseFd(fd); |
151 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4126 times.
|
4126 | assert(retval == 0); |
152 |
2/2✓ Branch 1 taken 4126 times.
✓ Branch 2 taken 14 times.
|
4140 | } |
153 | |||
154 |
1/2✓ Branch 1 taken 4126 times.
✗ Branch 2 not taken.
|
4126 | return ChangeRefcount(handle.id, -1); |
155 | } | ||
156 | |||
157 | |||
158 | 2116 | int ExternalCacheManager::CommitTxn(void *txn) { | |
159 | 2116 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
160 |
1/2✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
|
84 | LogCvmfs(kLogCache, kLogDebug, "committing %s", |
161 | 168 | std::string(transaction->id.ToString()).c_str()); | |
162 | 2116 | const int retval = Flush(true, transaction); | |
163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2116 times.
|
2116 | if (retval != 0) |
164 | ✗ | return retval; | |
165 | |||
166 | 2116 | const int refcount = transaction->open_fds - 1; | |
167 |
2/2✓ Branch 0 taken 2114 times.
✓ Branch 1 taken 2 times.
|
2116 | if (refcount != 0) |
168 | 2114 | 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 | 278 | 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 278 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 278 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 278 times.
✗ Branch 8 not taken.
|
278 | new ExternalCacheManager(fd_connection, max_open_fds)); |
213 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 278 times.
|
278 | assert(cache_mgr.IsValid()); |
214 | |||
215 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | cvmfs::MsgHandshake msg_handshake; |
216 | 278 | msg_handshake.set_protocol_version(kPbProtocolVersion); | |
217 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | msg_handshake.set_name(ident); |
218 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | CacheTransport::Frame frame_send(&msg_handshake); |
219 |
1/2✓ Branch 2 taken 278 times.
✗ Branch 3 not taken.
|
278 | cache_mgr->transport_.SendFrame(&frame_send); |
220 | |||
221 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | CacheTransport::Frame frame_recv; |
222 |
1/2✓ Branch 2 taken 278 times.
✗ Branch 3 not taken.
|
278 | const bool retval = cache_mgr->transport_.RecvFrame(&frame_recv); |
223 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
|
278 | if (!retval) |
224 | ✗ | return NULL; | |
225 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | google::protobuf::MessageLite *msg_typed = frame_recv.GetMsgTyped(); |
226 |
2/4✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 278 times.
|
278 | if (msg_typed->GetTypeName() != "cvmfs.MsgHandshakeAck") |
227 | ✗ | return NULL; | |
228 | 278 | cvmfs::MsgHandshakeAck *msg_ack = reinterpret_cast<cvmfs::MsgHandshakeAck *>( | |
229 | msg_typed); | ||
230 | 278 | cache_mgr->session_id_ = msg_ack->session_id(); | |
231 | 278 | cache_mgr->capabilities_ = msg_ack->capabilities(); | |
232 | 278 | cache_mgr->max_object_size_ = msg_ack->max_object_size(); | |
233 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 278 times.
|
278 | assert(cache_mgr->max_object_size_ > 0); |
234 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 278 times.
|
278 | 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 278 times.
|
278 | 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 252 times.
✓ Branch 2 taken 26 times.
|
278 | if (msg_ack->has_pid()) |
247 | 252 | cache_mgr->pid_plugin_ = msg_ack->pid(); | |
248 | 278 | return cache_mgr.Release(); | |
249 | 278 | } | |
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 | 2092 | void ExternalCacheManager::CtrlTxn(const Label &label, | |
294 | const int flags, | ||
295 | void *txn) { | ||
296 | 2092 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
297 | 2092 | transaction->label = label; | |
298 | 2092 | transaction->label_modified = true; | |
299 | 2092 | } | |
300 | |||
301 | |||
302 | ✗ | string ExternalCacheManager::Describe() { return "External cache manager\n"; } | |
303 | |||
304 | |||
305 | 28 | bool ExternalCacheManager::DoFreeState(void *data) { | |
306 | FdTable<ReadOnlyHandle> | ||
307 | 28 | *fd_table = reinterpret_cast<FdTable<ReadOnlyHandle> *>(data); | |
308 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | delete fd_table; |
309 | 28 | return true; | |
310 | } | ||
311 | |||
312 | |||
313 | 4188 | int ExternalCacheManager::DoOpen(const shash::Any &id) { | |
314 | 4188 | int fd = -1; | |
315 | { | ||
316 | 4188 | const WriteLockGuard guard(rwlock_fd_table_); | |
317 |
1/2✓ Branch 2 taken 4188 times.
✗ Branch 3 not taken.
|
4188 | fd = fd_table_.OpenFd(ReadOnlyHandle(id)); |
318 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 4160 times.
|
4188 | if (fd < 0) { |
319 |
1/2✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | LogCvmfs(kLogCache, kLogDebug, "error while creating new fd: %s", |
320 | strerror(-fd)); | ||
321 | 28 | return fd; | |
322 | } | ||
323 |
2/2✓ Branch 1 taken 4160 times.
✓ Branch 2 taken 28 times.
|
4188 | } |
324 | |||
325 |
1/2✓ Branch 1 taken 4160 times.
✗ Branch 2 not taken.
|
4160 | const int status_refcnt = ChangeRefcount(id, 1); |
326 |
2/2✓ Branch 0 taken 4124 times.
✓ Branch 1 taken 36 times.
|
4160 | if (status_refcnt == 0) |
327 | 4124 | return fd; | |
328 | |||
329 | 36 | const WriteLockGuard guard(rwlock_fd_table_); | |
330 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | const int retval = fd_table_.CloseFd(fd); |
331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | assert(retval == 0); |
332 | 36 | return status_refcnt; | |
333 | 36 | } | |
334 | |||
335 | |||
336 | 28 | 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 3556 times.
✓ Branch 2 taken 28 times.
|
3584 | for (unsigned i = 1; i < fd_table_.GetMaxFds(); ++i) { |
340 |
3/6✓ Branch 2 taken 3556 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 3556 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3556 times.
|
3556 | assert(fd_table_.GetHandle(i) == ReadOnlyHandle()); |
341 | } | ||
342 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const ReadOnlyHandle handle_root = fd_table_.GetHandle(0); |
343 | |||
344 | 28 | FdTable<ReadOnlyHandle> *other = reinterpret_cast<FdTable<ReadOnlyHandle> *>( | |
345 | data); | ||
346 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | fd_table_.AssignFrom(*other); |
347 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | cvmfs::MsgIoctl msg_ioctl; |
348 | 28 | msg_ioctl.set_session_id(session_id_); | |
349 | 28 | msg_ioctl.set_conncnt_change_by(-1); | |
350 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | CacheTransport::Frame frame(&msg_ioctl); |
351 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | transport_.SendFrame(&frame); |
352 | |||
353 | 28 | int new_root_fd = -1; | |
354 |
2/4✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 28 times.
|
28 | 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 | 28 | return new_root_fd; | |
361 | 28 | } | |
362 | |||
363 | |||
364 | 28 | void *ExternalCacheManager::DoSaveState() { | |
365 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | cvmfs::MsgIoctl msg_ioctl; |
366 | 28 | msg_ioctl.set_session_id(session_id_); | |
367 | 28 | msg_ioctl.set_conncnt_change_by(1); | |
368 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | CacheTransport::Frame frame(&msg_ioctl); |
369 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | transport_.SendFrame(&frame); |
370 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
56 | return fd_table_.Clone(); |
371 | 28 | } | |
372 | |||
373 | |||
374 | 1806 | int ExternalCacheManager::Dup(int fd) { | |
375 |
1/2✓ Branch 1 taken 1806 times.
✗ Branch 2 not taken.
|
1806 | const shash::Any id = GetHandle(fd); |
376 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1792 times.
|
1806 | if (id == kInvalidHandle) |
377 | 14 | return -EBADF; | |
378 |
1/2✓ Branch 1 taken 1792 times.
✗ Branch 2 not taken.
|
1792 | return DoOpen(id); |
379 | } | ||
380 | |||
381 | |||
382 | 278 | ExternalCacheManager::ExternalCacheManager(int fd_connection, | |
383 | 278 | unsigned max_open_fds) | |
384 | 278 | : pid_plugin_(0) | |
385 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | , fd_table_(max_open_fds, ReadOnlyHandle()) |
386 |
1/2✓ Branch 1 taken 278 times.
✗ Branch 2 not taken.
|
278 | , transport_(fd_connection) |
387 | 278 | , session_id_(-1) | |
388 | 278 | , max_object_size_(0) | |
389 | 278 | , spawned_(false) | |
390 | 278 | , terminated_(false) | |
391 | 556 | , capabilities_(cvmfs::CAP_NONE) { | |
392 | 278 | int retval = pthread_rwlock_init(&rwlock_fd_table_, NULL); | |
393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
|
278 | assert(retval == 0); |
394 | 278 | retval = pthread_mutex_init(&lock_send_fd_, NULL); | |
395 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
|
278 | assert(retval == 0); |
396 | 278 | retval = pthread_mutex_init(&lock_inflight_rpcs_, NULL); | |
397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 278 times.
|
278 | assert(retval == 0); |
398 | 278 | memset(&thread_read_, 0, sizeof(thread_read_)); | |
399 | 278 | atomic_init64(&next_request_id_); | |
400 | 278 | } | |
401 | |||
402 | |||
403 | 1104 | ExternalCacheManager::~ExternalCacheManager() { | |
404 | 552 | terminated_ = true; | |
405 | 552 | MemoryFence(); | |
406 |
1/2✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
|
552 | if (session_id_ >= 0) { |
407 | 552 | cvmfs::MsgQuit msg_quit; | |
408 | 552 | msg_quit.set_session_id(session_id_); | |
409 | 552 | CacheTransport::Frame frame(&msg_quit); | |
410 | 552 | transport_.SendFrame(&frame); | |
411 | } | ||
412 | 552 | shutdown(transport_.fd_connection(), SHUT_RDWR); | |
413 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 262 times.
|
552 | if (spawned_) |
414 | 28 | pthread_join(thread_read_, NULL); | |
415 | 552 | close(transport_.fd_connection()); | |
416 | 552 | pthread_rwlock_destroy(&rwlock_fd_table_); | |
417 | 552 | pthread_mutex_destroy(&lock_send_fd_); | |
418 | 552 | pthread_mutex_destroy(&lock_inflight_rpcs_); | |
419 | 1104 | } | |
420 | |||
421 | |||
422 | 10928 | int ExternalCacheManager::Flush(bool do_commit, Transaction *transaction) { | |
423 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10926 times.
|
10928 | if (transaction->committed) |
424 | 2 | return 0; | |
425 |
1/2✓ Branch 2 taken 8512 times.
✗ Branch 3 not taken.
|
8512 | LogCvmfs(kLogCache, kLogDebug, "flushing %u bytes for %s", |
426 | transaction->buf_pos, | ||
427 |
1/2✓ Branch 1 taken 8512 times.
✗ Branch 2 not taken.
|
17024 | std::string(transaction->id.ToString()).c_str()); |
428 |
1/2✓ Branch 1 taken 10926 times.
✗ Branch 2 not taken.
|
10926 | cvmfs::MsgHash object_id; |
429 |
1/2✓ Branch 1 taken 10926 times.
✗ Branch 2 not taken.
|
10926 | transport_.FillMsgHash(transaction->id, &object_id); |
430 |
1/2✓ Branch 1 taken 10926 times.
✗ Branch 2 not taken.
|
10926 | cvmfs::MsgStoreReq msg_store; |
431 | 10926 | msg_store.set_session_id(session_id_); | |
432 | 10926 | msg_store.set_req_id(transaction->transaction_id); | |
433 | 10926 | msg_store.set_allocated_object_id(&object_id); | |
434 | 10926 | msg_store.set_part_nr((transaction->size / max_object_size_) + 1); | |
435 | 10926 | msg_store.set_expected_size(transaction->expected_size); | |
436 | 10926 | msg_store.set_last_part(do_commit); | |
437 | |||
438 |
2/2✓ Branch 0 taken 10918 times.
✓ Branch 1 taken 8 times.
|
10926 | if (transaction->label_modified) { |
439 | cvmfs::EnumObjectType object_type; | ||
440 |
1/2✓ Branch 1 taken 10918 times.
✗ Branch 2 not taken.
|
10918 | transport_.FillObjectType(transaction->label.flags, &object_type); |
441 |
1/2✓ Branch 1 taken 10918 times.
✗ Branch 2 not taken.
|
10918 | msg_store.set_object_type(object_type); |
442 |
2/4✓ Branch 1 taken 10918 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 10918 times.
✗ Branch 5 not taken.
|
10918 | msg_store.set_description(transaction->label.GetDescription()); |
443 | } | ||
444 | |||
445 |
1/2✓ Branch 1 taken 10926 times.
✗ Branch 2 not taken.
|
10926 | RpcJob rpc_job(&msg_store); |
446 | 10926 | 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 10926 times.
✗ Branch 2 not taken.
|
10926 | CallRemotely(&rpc_job); |
449 | 10926 | msg_store.release_object_id(); | |
450 | |||
451 |
1/2✓ Branch 1 taken 10926 times.
✗ Branch 2 not taken.
|
10926 | cvmfs::MsgStoreReply *msg_reply = rpc_job.msg_store_reply(); |
452 |
1/2✓ Branch 1 taken 10926 times.
✗ Branch 2 not taken.
|
10926 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
453 | 10926 | transaction->flushed = true; | |
454 |
2/2✓ Branch 0 taken 2116 times.
✓ Branch 1 taken 8810 times.
|
10926 | if (do_commit) |
455 | 2116 | transaction->committed = true; | |
456 | } | ||
457 | 10926 | return Ack2Errno(msg_reply->status()); | |
458 | 10926 | } | |
459 | |||
460 | |||
461 | 2582 | shash::Any ExternalCacheManager::GetHandle(int fd) { | |
462 | 2582 | const ReadLockGuard guard(rwlock_fd_table_); | |
463 |
1/2✓ Branch 1 taken 2582 times.
✗ Branch 2 not taken.
|
2582 | const ReadOnlyHandle handle = fd_table_.GetHandle(fd); |
464 | 2582 | return handle.id; | |
465 | 2582 | } | |
466 | |||
467 | |||
468 | 262 | int64_t ExternalCacheManager::GetSize(int fd) { | |
469 |
1/2✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
|
262 | const shash::Any id = GetHandle(fd); |
470 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 248 times.
|
262 | if (id == kInvalidHandle) |
471 | 14 | return -EBADF; | |
472 | |||
473 |
1/2✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
|
248 | cvmfs::MsgHash object_id; |
474 |
1/2✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
|
248 | transport_.FillMsgHash(id, &object_id); |
475 |
1/2✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
|
234 | cvmfs::MsgObjectInfoReq msg_info; |
476 | 234 | msg_info.set_session_id(session_id_); | |
477 | 234 | msg_info.set_req_id(NextRequestId()); | |
478 | 248 | msg_info.set_allocated_object_id(&object_id); | |
479 |
1/2✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
|
234 | RpcJob rpc_job(&msg_info); |
480 |
1/2✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
|
248 | CallRemotely(&rpc_job); |
481 | 248 | msg_info.release_object_id(); | |
482 | |||
483 |
1/2✓ Branch 1 taken 248 times.
✗ Branch 2 not taken.
|
248 | cvmfs::MsgObjectInfoReply *msg_reply = rpc_job.msg_object_info_reply(); |
484 |
2/2✓ Branch 1 taken 234 times.
✓ Branch 2 taken 14 times.
|
248 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
485 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 234 times.
|
234 | assert(msg_reply->has_size()); |
486 | 234 | return msg_reply->size(); | |
487 | } | ||
488 | 14 | return Ack2Errno(msg_reply->status()); | |
489 | 248 | } | |
490 | |||
491 | |||
492 | 14 | void *ExternalCacheManager::MainRead(void *data) { | |
493 | 14 | ExternalCacheManager *cache_mgr = reinterpret_cast<ExternalCacheManager *>( | |
494 | data); | ||
495 | 14 | LogCvmfs(kLogCache, kLogDebug, "starting external cache reader thread"); | |
496 | |||
497 | 14 | unsigned char buffer[cache_mgr->max_object_size_]; | |
498 | while (true) { | ||
499 |
1/2✓ Branch 1 taken 42406 times.
✗ Branch 2 not taken.
|
42406 | CacheTransport::Frame frame_recv; |
500 | 42406 | frame_recv.set_attachment(buffer, cache_mgr->max_object_size_); | |
501 |
1/2✓ Branch 1 taken 42406 times.
✗ Branch 2 not taken.
|
42406 | const bool retval = cache_mgr->transport_.RecvFrame(&frame_recv); |
502 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 42392 times.
|
42406 | if (!retval) |
503 | 14 | break; | |
504 | |||
505 | uint64_t req_id; | ||
506 | 42392 | uint64_t part_nr = 0; | |
507 |
1/2✓ Branch 1 taken 42392 times.
✗ Branch 2 not taken.
|
42392 | google::protobuf::MessageLite *msg = frame_recv.GetMsgTyped(); |
508 |
3/4✓ Branch 1 taken 42392 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 266 times.
✓ Branch 6 taken 42126 times.
|
42392 | if (msg->GetTypeName() == "cvmfs.MsgRefcountReply") { |
509 | 266 | req_id = reinterpret_cast<cvmfs::MsgRefcountReply *>(msg)->req_id(); | |
510 |
3/4✓ Branch 1 taken 42126 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 126 times.
✓ Branch 6 taken 42000 times.
|
42126 | } else if (msg->GetTypeName() == "cvmfs.MsgObjectInfoReply") { |
511 | 126 | req_id = reinterpret_cast<cvmfs::MsgObjectInfoReply *>(msg)->req_id(); | |
512 |
3/4✓ Branch 1 taken 42000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 25200 times.
✓ Branch 6 taken 16800 times.
|
42000 | } else if (msg->GetTypeName() == "cvmfs.MsgReadReply") { |
513 | 25200 | req_id = reinterpret_cast<cvmfs::MsgReadReply *>(msg)->req_id(); | |
514 |
3/4✓ Branch 1 taken 16800 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2800 times.
✓ Branch 6 taken 14000 times.
|
16800 | } else if (msg->GetTypeName() == "cvmfs.MsgStoreReply") { |
515 | 2800 | req_id = reinterpret_cast<cvmfs::MsgStoreReply *>(msg)->req_id(); | |
516 | 2800 | part_nr = reinterpret_cast<cvmfs::MsgStoreReply *>(msg)->part_nr(); | |
517 |
2/4✓ Branch 1 taken 14000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14000 times.
|
14000 | } else if (msg->GetTypeName() == "cvmfs.MsgInfoReply") { |
518 | ✗ | req_id = reinterpret_cast<cvmfs::MsgInfoReply *>(msg)->req_id(); | |
519 |
2/4✓ Branch 1 taken 14000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14000 times.
|
14000 | } else if (msg->GetTypeName() == "cvmfs.MsgShrinkReply") { |
520 | ✗ | req_id = reinterpret_cast<cvmfs::MsgShrinkReply *>(msg)->req_id(); | |
521 |
2/4✓ Branch 1 taken 14000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14000 times.
|
14000 | } else if (msg->GetTypeName() == "cvmfs.MsgListReply") { |
522 | ✗ | req_id = reinterpret_cast<cvmfs::MsgListReply *>(msg)->req_id(); | |
523 |
2/4✓ Branch 1 taken 14000 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14000 times.
|
14000 | } else if (msg->GetTypeName() == "cvmfs.MsgBreadcrumbReply") { |
524 | ✗ | req_id = reinterpret_cast<cvmfs::MsgBreadcrumbReply *>(msg)->req_id(); | |
525 |
2/4✓ Branch 1 taken 14000 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 14000 times.
✗ Branch 6 not taken.
|
14000 | } else if (msg->GetTypeName() == "cvmfs.MsgDetach") { |
526 | // Release pinned catalogs | ||
527 |
2/4✓ Branch 2 taken 14000 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 14000 times.
✗ Branch 6 not taken.
|
14000 | cache_mgr->quota_mgr_->BroadcastBackchannels("R"); |
528 | 14000 | continue; | |
529 | } else { | ||
530 | ✗ | PANIC(kLogSyslogErr | kLogDebug, "unexpected message %s", | |
531 | std::string(msg->GetTypeName()).c_str()); | ||
532 | } | ||
533 | |||
534 | 28392 | RpcInFlight rpc_inflight; | |
535 | { | ||
536 | 28392 | const MutexLockGuard guard(cache_mgr->lock_inflight_rpcs_); | |
537 |
1/2✓ Branch 1 taken 28588 times.
✗ Branch 2 not taken.
|
28588 | for (unsigned i = 0; i < cache_mgr->inflight_rpcs_.size(); ++i) { |
538 | 28588 | RpcJob *rpc_job = cache_mgr->inflight_rpcs_[i].rpc_job; | |
539 |
5/6✓ Branch 1 taken 28392 times.
✓ Branch 2 taken 196 times.
✓ Branch 4 taken 28392 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28392 times.
✓ Branch 7 taken 196 times.
|
28588 | if ((rpc_job->req_id() == req_id) && (rpc_job->part_nr() == part_nr)) { |
540 | 28392 | rpc_inflight = cache_mgr->inflight_rpcs_[i]; | |
541 |
1/2✓ Branch 2 taken 28392 times.
✗ Branch 3 not taken.
|
28392 | cache_mgr->inflight_rpcs_.erase(cache_mgr->inflight_rpcs_.begin() |
542 | 28392 | + i); | |
543 | 28392 | break; | |
544 | } | ||
545 | } | ||
546 | 28392 | } | |
547 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28392 times.
|
28392 | 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 28392 times.
✗ Branch 3 not taken.
|
28392 | rpc_inflight.rpc_job->frame_recv()->MergeFrom(frame_recv); |
553 |
1/2✓ Branch 1 taken 28392 times.
✗ Branch 2 not taken.
|
28392 | rpc_inflight.signal->Wakeup(); |
554 |
3/3✓ Branch 1 taken 28392 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14000 times.
|
84798 | } |
555 | |||
556 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!cache_mgr->terminated_) { |
557 | ✗ | PANIC(kLogSyslogErr | kLogDebug, | |
558 | "connection to external cache manager broken (%d)", errno); | ||
559 | } | ||
560 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | LogCvmfs(kLogCache, kLogDebug, "stopping external cache reader thread"); |
561 | 14 | return NULL; | |
562 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | } |
563 | |||
564 | |||
565 | 2396 | int ExternalCacheManager::Open(const LabeledObject &object) { | |
566 | 2396 | 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 | 486 | int64_t ExternalCacheManager::Pread(int fd, | |
594 | void *buf, | ||
595 | uint64_t size, | ||
596 | uint64_t offset) { | ||
597 |
1/2✓ Branch 1 taken 486 times.
✗ Branch 2 not taken.
|
486 | const shash::Any id = GetHandle(fd); |
598 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 472 times.
|
486 | if (id == kInvalidHandle) |
599 | 14 | return -EBADF; | |
600 | |||
601 |
1/2✓ Branch 1 taken 472 times.
✗ Branch 2 not taken.
|
472 | cvmfs::MsgHash object_id; |
602 |
1/2✓ Branch 1 taken 472 times.
✗ Branch 2 not taken.
|
472 | transport_.FillMsgHash(id, &object_id); |
603 | 472 | uint64_t nbytes = 0; | |
604 |
2/2✓ Branch 0 taken 31651 times.
✓ Branch 1 taken 406 times.
|
32057 | while (nbytes < size) { |
605 | 31651 | const uint64_t batch_size = std::min( | |
606 | 31651 | size - nbytes, static_cast<uint64_t>(max_object_size_)); | |
607 |
1/2✓ Branch 1 taken 31651 times.
✗ Branch 2 not taken.
|
31651 | cvmfs::MsgReadReq msg_read; |
608 | 31651 | msg_read.set_session_id(session_id_); | |
609 | 31651 | msg_read.set_req_id(NextRequestId()); | |
610 | 31651 | msg_read.set_allocated_object_id(&object_id); | |
611 | 31651 | msg_read.set_offset(offset + nbytes); | |
612 | 31651 | msg_read.set_size(batch_size); | |
613 |
1/2✓ Branch 1 taken 31651 times.
✗ Branch 2 not taken.
|
31651 | RpcJob rpc_job(&msg_read); |
614 | 31651 | rpc_job.set_attachment_recv(reinterpret_cast<char *>(buf) + nbytes, | |
615 | batch_size); | ||
616 |
1/2✓ Branch 1 taken 31651 times.
✗ Branch 2 not taken.
|
31651 | CallRemotely(&rpc_job); |
617 | 31651 | msg_read.release_object_id(); | |
618 | |||
619 |
1/2✓ Branch 1 taken 31651 times.
✗ Branch 2 not taken.
|
31651 | cvmfs::MsgReadReply *msg_reply = rpc_job.msg_read_reply(); |
620 |
2/2✓ Branch 1 taken 31633 times.
✓ Branch 2 taken 18 times.
|
31651 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
621 | 31633 | 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 48 times.
✓ Branch 3 taken 31585 times.
|
31633 | if (rpc_job.frame_recv()->att_size() < batch_size) |
624 | 48 | return nbytes; | |
625 | } else { | ||
626 | 18 | return Ack2Errno(msg_reply->status()); | |
627 | } | ||
628 |
4/4✓ Branch 1 taken 31585 times.
✓ Branch 2 taken 66 times.
✓ Branch 4 taken 31585 times.
✓ Branch 5 taken 66 times.
|
31717 | } |
629 | 406 | return size; | |
630 | 472 | } | |
631 | |||
632 | |||
633 | 28 | int ExternalCacheManager::Readahead(int fd) { | |
634 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const shash::Any id = GetHandle(fd); |
635 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 14 times.
|
28 | if (id == kInvalidHandle) |
636 | 14 | return -EBADF; | |
637 | // No-op | ||
638 | 14 | return 0; | |
639 | } | ||
640 | |||
641 | |||
642 | 46 | int ExternalCacheManager::Reset(void *txn) { | |
643 | 46 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
644 | 46 | transaction->buf_pos = 0; | |
645 | 46 | transaction->size = 0; | |
646 | 46 | transaction->open_fds = 0; | |
647 | 46 | transaction->committed = false; | |
648 | 46 | transaction->label_modified = true; | |
649 | |||
650 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
|
46 | if (!transaction->flushed) |
651 | 32 | return 0; | |
652 | |||
653 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | cvmfs::MsgHash object_id; |
654 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | transport_.FillMsgHash(transaction->id, &object_id); |
655 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | cvmfs::MsgStoreAbortReq msg_abort; |
656 | 14 | msg_abort.set_session_id(session_id_); | |
657 | 14 | msg_abort.set_req_id(transaction->transaction_id); | |
658 | 14 | msg_abort.set_allocated_object_id(&object_id); | |
659 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | RpcJob rpc_job(&msg_abort); |
660 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | CallRemotely(&rpc_job); |
661 | 14 | msg_abort.release_object_id(); | |
662 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | cvmfs::MsgStoreReply *msg_reply = rpc_job.msg_store_reply(); |
663 | 14 | transaction->transaction_id = NextRequestId(); | |
664 | 14 | transaction->flushed = false; | |
665 | 14 | return Ack2Errno(msg_reply->status()); | |
666 | 14 | } | |
667 | |||
668 | |||
669 | 32 | manifest::Breadcrumb ExternalCacheManager::LoadBreadcrumb( | |
670 | const std::string &fqrn) { | ||
671 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | if (!(capabilities_ & cvmfs::CAP_BREADCRUMB)) |
672 | ✗ | return manifest::Breadcrumb(); | |
673 | |||
674 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | cvmfs::MsgBreadcrumbLoadReq msg_breadcrumb_load; |
675 | 32 | msg_breadcrumb_load.set_session_id(session_id_); | |
676 | 32 | msg_breadcrumb_load.set_req_id(NextRequestId()); | |
677 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | msg_breadcrumb_load.set_fqrn(fqrn); |
678 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | RpcJob rpc_job(&msg_breadcrumb_load); |
679 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | CallRemotely(&rpc_job); |
680 | |||
681 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | manifest::Breadcrumb breadcrumb; |
682 |
1/2✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
|
32 | cvmfs::MsgBreadcrumbReply *msg_reply = rpc_job.msg_breadcrumb_reply(); |
683 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
|
32 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
684 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | assert(msg_reply->has_breadcrumb()); |
685 |
1/2✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
|
16 | assert(msg_reply->breadcrumb().fqrn() == fqrn); |
686 |
1/2✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
|
16 | const bool rv = transport_.ParseMsgHash(msg_reply->breadcrumb().hash(), |
687 | &breadcrumb.catalog_hash); | ||
688 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | assert(rv); |
689 | 16 | breadcrumb.catalog_hash.suffix = shash::kSuffixCatalog; | |
690 | 16 | breadcrumb.timestamp = msg_reply->breadcrumb().timestamp(); | |
691 |
1/2✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | if (msg_reply->breadcrumb().has_revision()) { |
692 | 16 | breadcrumb.revision = msg_reply->breadcrumb().revision(); | |
693 | } else { | ||
694 | ✗ | breadcrumb.revision = 0; | |
695 | } | ||
696 | } | ||
697 | 32 | return breadcrumb; | |
698 | 32 | } | |
699 | |||
700 | |||
701 | 16 | bool ExternalCacheManager::StoreBreadcrumb(const manifest::Manifest &manifest) { | |
702 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (!(capabilities_ & cvmfs::CAP_BREADCRUMB)) |
703 | ✗ | return false; | |
704 | |||
705 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | cvmfs::MsgHash hash; |
706 |
1/2✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | transport_.FillMsgHash(manifest.catalog_hash(), &hash); |
707 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | cvmfs::MsgBreadcrumb breadcrumb; |
708 |
2/4✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
|
16 | breadcrumb.set_fqrn(manifest.repository_name()); |
709 | 16 | breadcrumb.set_allocated_hash(&hash); | |
710 | 16 | breadcrumb.set_timestamp(manifest.publish_timestamp()); | |
711 | 16 | breadcrumb.set_revision(manifest.revision()); | |
712 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | cvmfs::MsgBreadcrumbStoreReq msg_breadcrumb_store; |
713 | 16 | msg_breadcrumb_store.set_session_id(session_id_); | |
714 | 16 | msg_breadcrumb_store.set_req_id(NextRequestId()); | |
715 | 16 | msg_breadcrumb_store.set_allocated_breadcrumb(&breadcrumb); | |
716 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | RpcJob rpc_job(&msg_breadcrumb_store); |
717 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | CallRemotely(&rpc_job); |
718 | 16 | msg_breadcrumb_store.release_breadcrumb(); | |
719 | 16 | breadcrumb.release_hash(); | |
720 | |||
721 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | cvmfs::MsgBreadcrumbReply *msg_reply = rpc_job.msg_breadcrumb_reply(); |
722 | 16 | return msg_reply->status() == cvmfs::STATUS_OK; | |
723 | 16 | } | |
724 | |||
725 | |||
726 | 14 | void ExternalCacheManager::Spawn() { | |
727 | 14 | const int retval = pthread_create(&thread_read_, NULL, MainRead, this); | |
728 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | assert(retval == 0); |
729 | 14 | spawned_ = true; | |
730 | 14 | } | |
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 | 2144 | int ExternalCacheManager::StartTxn(const shash::Any &id, | |
798 | uint64_t size, | ||
799 | void *txn) { | ||
800 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 2116 times.
|
2144 | if (!(capabilities_ & cvmfs::CAP_WRITE)) |
801 | 28 | return -EROFS; | |
802 | |||
803 | 2116 | Transaction *transaction = new (txn) Transaction(id); | |
804 | 2116 | transaction->expected_size = size; | |
805 | 2116 | transaction->transaction_id = NextRequestId(); | |
806 | #ifdef __APPLE__ | ||
807 | transaction->buffer = reinterpret_cast<unsigned char *>( | ||
808 | smalloc(max_object_size_)); | ||
809 | #endif | ||
810 | 2116 | return 0; | |
811 | } | ||
812 | |||
813 | |||
814 | 2146 | int64_t ExternalCacheManager::Write(const void *buf, uint64_t size, void *txn) { | |
815 | 2146 | Transaction *transaction = reinterpret_cast<Transaction *>(txn); | |
816 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2146 times.
|
2146 | assert(!transaction->committed); |
817 |
1/2✓ Branch 2 taken 112 times.
✗ Branch 3 not taken.
|
112 | LogCvmfs(kLogCache, kLogDebug, "writing %" PRIu64 " bytes for %s", size, |
818 | 224 | transaction->id.ToString().c_str()); | |
819 | |||
820 |
1/2✓ Branch 0 taken 2146 times.
✗ Branch 1 not taken.
|
2146 | if (transaction->expected_size != kSizeUnknown) { |
821 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2146 times.
|
2146 | 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 | 2146 | uint64_t written = 0; | |
830 | 2146 | const unsigned char *read_pos = reinterpret_cast<const unsigned char *>(buf); | |
831 |
2/2✓ Branch 0 taken 10940 times.
✓ Branch 1 taken 2146 times.
|
13086 | while (written < size) { |
832 |
2/2✓ Branch 0 taken 8810 times.
✓ Branch 1 taken 2130 times.
|
10940 | if (transaction->buf_pos == max_object_size_) { |
833 | 8810 | bool do_commit = false; | |
834 |
1/2✓ Branch 0 taken 8810 times.
✗ Branch 1 not taken.
|
8810 | if (transaction->expected_size != kSizeUnknown) |
835 | 8810 | do_commit = (transaction->size + written) == transaction->expected_size; | |
836 |
1/2✓ Branch 1 taken 8810 times.
✗ Branch 2 not taken.
|
8810 | const int retval = Flush(do_commit, transaction); |
837 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8810 times.
|
8810 | if (retval != 0) { |
838 | ✗ | transaction->size += written; | |
839 | ✗ | return retval; | |
840 | } | ||
841 | 8810 | transaction->size += transaction->buf_pos; | |
842 | 8810 | transaction->buf_pos = 0; | |
843 | } | ||
844 | 10940 | const uint64_t remaining = size - written; | |
845 | 10940 | const uint64_t space_in_buffer = max_object_size_ - transaction->buf_pos; | |
846 | 10940 | const uint64_t batch_size = std::min(remaining, space_in_buffer); | |
847 | 10940 | memcpy(transaction->buffer + transaction->buf_pos, read_pos, batch_size); | |
848 | 10940 | transaction->buf_pos += batch_size; | |
849 | 10940 | written += batch_size; | |
850 | 10940 | read_pos += batch_size; | |
851 | } | ||
852 | 2146 | return written; | |
853 | } | ||
854 | |||
855 | |||
856 | //------------------------------------------------------------------------------ | ||
857 | |||
858 | |||
859 | 92 | bool ExternalQuotaManager::DoListing(cvmfs::EnumObjectType type, | |
860 | vector<cvmfs::MsgListRecord> *result) { | ||
861 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 92 times.
|
92 | if (!(cache_mgr_->capabilities_ & cvmfs::CAP_LIST)) |
862 | ✗ | return false; | |
863 | |||
864 | 92 | uint64_t listing_id = 0; | |
865 | 92 | bool more_data = false; | |
866 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 92 times.
|
148 | do { |
867 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | cvmfs::MsgListReq msg_list; |
868 | 148 | msg_list.set_session_id(cache_mgr_->session_id_); | |
869 | 148 | msg_list.set_req_id(cache_mgr_->NextRequestId()); | |
870 | 148 | msg_list.set_listing_id(listing_id); | |
871 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | msg_list.set_object_type(type); |
872 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | ExternalCacheManager::RpcJob rpc_job(&msg_list); |
873 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | cache_mgr_->CallRemotely(&rpc_job); |
874 | |||
875 |
1/2✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
|
148 | cvmfs::MsgListReply *msg_reply = rpc_job.msg_list_reply(); |
876 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
|
148 | if (msg_reply->status() != cvmfs::STATUS_OK) |
877 | ✗ | return false; | |
878 | 148 | more_data = !msg_reply->is_last_part(); | |
879 | 148 | listing_id = msg_reply->listing_id(); | |
880 |
3/4✓ Branch 1 taken 2804152 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2804004 times.
✓ Branch 4 taken 148 times.
|
2804152 | for (int i = 0; i < msg_reply->list_record_size(); ++i) { |
881 |
2/4✓ Branch 1 taken 2804004 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2804004 times.
✗ Branch 5 not taken.
|
2804004 | result->push_back(msg_reply->list_record(i)); |
882 | } | ||
883 |
2/4✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 148 times.
✗ Branch 5 not taken.
|
148 | } while (more_data); |
884 | |||
885 | 92 | return true; | |
886 | } | ||
887 | |||
888 | |||
889 | 36 | bool ExternalQuotaManager::Cleanup(const uint64_t leave_size) { | |
890 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if (!(cache_mgr_->capabilities_ & cvmfs::CAP_SHRINK)) |
891 | ✗ | return false; | |
892 | |||
893 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | cvmfs::MsgShrinkReq msg_shrink; |
894 | 36 | msg_shrink.set_session_id(cache_mgr_->session_id_); | |
895 | 36 | msg_shrink.set_req_id(cache_mgr_->NextRequestId()); | |
896 | 36 | msg_shrink.set_shrink_to(leave_size); | |
897 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | ExternalCacheManager::RpcJob rpc_job(&msg_shrink); |
898 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | cache_mgr_->CallRemotely(&rpc_job); |
899 | |||
900 |
1/2✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
36 | cvmfs::MsgShrinkReply *msg_reply = rpc_job.msg_shrink_reply(); |
901 | 36 | return msg_reply->status() == cvmfs::STATUS_OK; | |
902 | 36 | } | |
903 | |||
904 | |||
905 | 276 | ExternalQuotaManager *ExternalQuotaManager::Create( | |
906 | ExternalCacheManager *cache_mgr) { | ||
907 | UniquePtr<ExternalQuotaManager> quota_mgr( | ||
908 |
3/6✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 276 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 276 times.
✗ Branch 8 not taken.
|
276 | new ExternalQuotaManager(cache_mgr)); |
909 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 276 times.
|
276 | assert(quota_mgr.IsValid()); |
910 | |||
911 | 552 | return quota_mgr.Release(); | |
912 | 276 | } | |
913 | |||
914 | |||
915 | 80 | int ExternalQuotaManager::GetInfo(QuotaInfo *quota_info) { | |
916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 80 times.
|
80 | if (!(cache_mgr_->capabilities_ & cvmfs::CAP_INFO)) |
917 | ✗ | return Ack2Errno(cvmfs::STATUS_NOSUPPORT); | |
918 | |||
919 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | cvmfs::MsgInfoReq msg_info; |
920 | 80 | msg_info.set_session_id(cache_mgr_->session_id_); | |
921 | 80 | msg_info.set_req_id(cache_mgr_->NextRequestId()); | |
922 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | ExternalCacheManager::RpcJob rpc_job(&msg_info); |
923 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | cache_mgr_->CallRemotely(&rpc_job); |
924 | |||
925 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | cvmfs::MsgInfoReply *msg_reply = rpc_job.msg_info_reply(); |
926 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | if (msg_reply->status() == cvmfs::STATUS_OK) { |
927 | 80 | quota_info->size = msg_reply->size_bytes(); | |
928 | 80 | quota_info->used = msg_reply->used_bytes(); | |
929 | 80 | quota_info->pinned = msg_reply->pinned_bytes(); | |
930 |
1/2✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
|
80 | if (msg_reply->no_shrink() >= 0) |
931 | 80 | quota_info->no_shrink = msg_reply->no_shrink(); | |
932 | } | ||
933 | 80 | return Ack2Errno(msg_reply->status()); | |
934 | 80 | } | |
935 | |||
936 | |||
937 | 18 | uint64_t ExternalQuotaManager::GetCapacity() { | |
938 | 18 | QuotaInfo info; | |
939 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | const int retval = GetInfo(&info); |
940 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (retval != 0) |
941 | ✗ | return uint64_t(-1); | |
942 | 18 | 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 | 28 | uint64_t ExternalQuotaManager::GetSize() { | |
956 | 28 | QuotaInfo info; | |
957 |
1/2✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
|
28 | const int retval = GetInfo(&info); |
958 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (retval != 0) |
959 | ✗ | return 0; | |
960 | 28 | return info.used; | |
961 | } | ||
962 | |||
963 | |||
964 | 34 | uint64_t ExternalQuotaManager::GetSizePinned() { | |
965 | 34 | QuotaInfo info; | |
966 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
34 | const int retval = GetInfo(&info); |
967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (retval != 0) |
968 | ✗ | return 0; | |
969 | 34 | 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 | 16 | vector<string> ExternalQuotaManager::List() { | |
992 | 16 | vector<string> result; | |
993 | 16 | vector<cvmfs::MsgListRecord> raw_list; | |
994 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | const bool retval = DoListing(cvmfs::OBJECT_REGULAR, &raw_list); |
995 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (!retval) |
996 | ✗ | return result; | |
997 |
2/2✓ Branch 1 taken 1402002 times.
✓ Branch 2 taken 16 times.
|
1402018 | for (unsigned i = 0; i < raw_list.size(); ++i) |
998 |
1/2✓ Branch 3 taken 1402002 times.
✗ Branch 4 not taken.
|
1402002 | result.push_back(raw_list[i].description()); |
999 | 16 | return result; | |
1000 | 16 | } | |
1001 | |||
1002 | |||
1003 | 14 | vector<string> ExternalQuotaManager::ListCatalogs() { | |
1004 | 14 | vector<string> result; | |
1005 | 14 | vector<cvmfs::MsgListRecord> raw_list; | |
1006 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | const bool retval = DoListing(cvmfs::OBJECT_CATALOG, &raw_list); |
1007 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!retval) |
1008 | ✗ | return result; | |
1009 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
14 | for (unsigned i = 0; i < raw_list.size(); ++i) |
1010 | ✗ | result.push_back(raw_list[i].description()); | |
1011 | 14 | return result; | |
1012 | 14 | } | |
1013 | |||
1014 | |||
1015 | 16 | vector<string> ExternalQuotaManager::ListPinned() { | |
1016 | 16 | vector<string> result; | |
1017 |
2/2✓ Branch 1 taken 48 times.
✓ Branch 2 taken 16 times.
|
128 | vector<cvmfs::MsgListRecord> raw_lists[3]; |
1018 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | bool retval = DoListing(cvmfs::OBJECT_REGULAR, &raw_lists[0]); |
1019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (!retval) |
1020 | ✗ | return result; | |
1021 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | retval = DoListing(cvmfs::OBJECT_CATALOG, &raw_lists[1]); |
1022 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (!retval) |
1023 | ✗ | return result; | |
1024 |
1/2✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
|
16 | retval = DoListing(cvmfs::OBJECT_VOLATILE, &raw_lists[2]); |
1025 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (!retval) |
1026 | ✗ | return result; | |
1027 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
|
64 | for (unsigned i = 0; i < sizeof(raw_lists) / sizeof(raw_lists[0]); ++i) { |
1028 |
2/2✓ Branch 1 taken 1402002 times.
✓ Branch 2 taken 48 times.
|
1402050 | for (unsigned j = 0; j < raw_lists[i].size(); ++j) { |
1029 |
2/2✓ Branch 2 taken 200 times.
✓ Branch 3 taken 1401802 times.
|
1402002 | 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 | 16 | return result; | |
1034 |
2/4✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
64 | } |
1035 | |||
1036 | |||
1037 | 14 | vector<string> ExternalQuotaManager::ListVolatile() { | |
1038 | 14 | vector<string> result; | |
1039 | 14 | vector<cvmfs::MsgListRecord> raw_list; | |
1040 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | const bool retval = DoListing(cvmfs::OBJECT_VOLATILE, &raw_list); |
1041 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!retval) |
1042 | ✗ | return result; | |
1043 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
|
14 | for (unsigned i = 0; i < raw_list.size(); ++i) |
1044 | ✗ | result.push_back(raw_list[i].description()); | |
1045 | 14 | return result; | |
1046 | 14 | } | |
1047 | |||
1048 | |||
1049 | 14 | void ExternalQuotaManager::RegisterBackChannel(int back_channel[2], | |
1050 | const string &channel_id) { | ||
1051 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | const shash::Md5 hash_id = shash::Md5(shash::AsciiPtr(channel_id)); |
1052 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | MakePipe(back_channel); |
1053 | 14 | LockBackChannels(); | |
1054 |
2/4✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
|
14 | assert(back_channels_.find(hash_id) == back_channels_.end()); |
1055 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | back_channels_[hash_id] = back_channel[1]; |
1056 | 14 | UnlockBackChannels(); | |
1057 | 14 | } | |
1058 | |||
1059 | |||
1060 | 14 | void ExternalQuotaManager::UnregisterBackChannel(int back_channel[2], | |
1061 | const string &channel_id) { | ||
1062 |
1/2✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | const shash::Md5 hash_id = shash::Md5(shash::AsciiPtr(channel_id)); |
1063 | 14 | LockBackChannels(); | |
1064 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | back_channels_.erase(hash_id); |
1065 | 14 | UnlockBackChannels(); | |
1066 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | ClosePipe(back_channel); |
1067 | 14 | } | |
1068 |