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