GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/cache_plugin/channel.cc
Date: 2026-10-25 02:40:14
Exec Total Coverage
Lines: 484 597 81.1%
Branches: 383 887 43.2%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "channel.h"
6
7 #include <errno.h>
8 #include <poll.h>
9 #include <signal.h>
10 #include <sys/socket.h>
11 #include <sys/un.h>
12 #include <unistd.h>
13
14 #include <cassert>
15 #include <cstring>
16 #include <memory>
17 #include <vector>
18
19 #include "util/concurrency.h"
20 #include "util/exception.h"
21 #include "util/logging.h"
22 #include "util/platform.h"
23 #include "util/posix.h"
24 #include "util/smalloc.h"
25 #include "util/string.h"
26
27 using namespace std; // NOLINT
28
29
30 SessionCtx *SessionCtx::instance_ = NULL;
31
32 ✗ void SessionCtx::CleanupInstance() {
33 ✗ delete instance_;
34 ✗ instance_ = NULL;
35 }
36
37
38 33 SessionCtx::SessionCtx() {
39 33 lock_tls_blocks_ = reinterpret_cast<pthread_mutex_t *>(
40 33 smalloc(sizeof(pthread_mutex_t)));
41 33 const int retval = pthread_mutex_init(lock_tls_blocks_, NULL);
42
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 assert(retval == 0);
43 33 }
44
45
46 ✗ SessionCtx::~SessionCtx() {
47 ✗ pthread_mutex_destroy(lock_tls_blocks_);
48 ✗ free(lock_tls_blocks_);
49
50 ✗ for (unsigned i = 0; i < tls_blocks_.size(); ++i) {
51 ✗ delete tls_blocks_[i];
52 }
53
54 ✗ const int retval = pthread_key_delete(thread_local_storage_);
55 ✗ assert(retval == 0);
56 }
57
58
59 317262 SessionCtx *SessionCtx::GetInstance() {
60
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 317229 times.
317262 if (instance_ == NULL) {
61 33 instance_ = new SessionCtx();
62 33 const int retval = pthread_key_create(&instance_->thread_local_storage_,
63 TlsDestructor);
64
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 assert(retval == 0);
65 }
66
67 317262 return instance_;
68 }
69
70
71 91608 void SessionCtx::Get(uint64_t *id, char **reponame, char **client_instance) {
72 ThreadLocalStorage *tls = static_cast<ThreadLocalStorage *>(
73 91608 pthread_getspecific(thread_local_storage_));
74
3/4
✓ Branch 0 taken 91575 times.
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91575 times.
91608 if ((tls == NULL) || !tls->is_set) {
75 33 *id = 0;
76 33 *reponame = NULL;
77 33 *client_instance = NULL;
78 } else {
79 91575 *id = tls->id;
80 91575 *reponame = tls->reponame;
81 91575 *client_instance = tls->client_instance;
82 }
83 91608 }
84
85
86 ✗ bool SessionCtx::IsSet() {
87 ThreadLocalStorage *tls = static_cast<ThreadLocalStorage *>(
88 ✗ pthread_getspecific(thread_local_storage_));
89 ✗ if (tls == NULL)
90 ✗ return false;
91
92 ✗ return tls->is_set;
93 }
94
95
96 112827 void SessionCtx::Set(uint64_t id, char *reponame, char *client_instance) {
97 ThreadLocalStorage *tls = static_cast<ThreadLocalStorage *>(
98 112827 pthread_getspecific(thread_local_storage_));
99
100
2/2
✓ Branch 0 taken 495 times.
✓ Branch 1 taken 112332 times.
112827 if (tls == NULL) {
101
1/2
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
495 tls = new ThreadLocalStorage(id, reponame, client_instance);
102 495 const int retval = pthread_setspecific(thread_local_storage_, tls);
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 495 times.
495 assert(retval == 0);
104 495 const MutexLockGuard lock_guard(lock_tls_blocks_);
105
1/2
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
495 tls_blocks_.push_back(tls);
106 495 } else {
107 112332 tls->id = id;
108 112332 tls->reponame = reponame;
109 112332 tls->client_instance = client_instance;
110 112332 tls->is_set = true;
111 }
112 112827 }
113
114
115 495 void SessionCtx::TlsDestructor(void *data) {
116 495 ThreadLocalStorage *tls = static_cast<SessionCtx::ThreadLocalStorage *>(data);
117
1/2
✓ Branch 0 taken 495 times.
✗ Branch 1 not taken.
495 delete tls;
118
119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 495 times.
495 assert(instance_);
120 495 const MutexLockGuard lock_guard(instance_->lock_tls_blocks_);
121 495 for (vector<ThreadLocalStorage *>::iterator
122 495 i = instance_->tls_blocks_.begin(),
123 495 iEnd = instance_->tls_blocks_.end();
124
1/2
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
495 i != iEnd;
125 ✗ ++i) {
126
1/2
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
495 if ((*i) == tls) {
127
1/2
✓ Branch 2 taken 495 times.
✗ Branch 3 not taken.
495 instance_->tls_blocks_.erase(i);
128 495 break;
129 }
130 }
131 495 }
132
133
134 112827 void SessionCtx::Unset() {
135 ThreadLocalStorage *tls = static_cast<ThreadLocalStorage *>(
136 112827 pthread_getspecific(thread_local_storage_));
137
1/2
✓ Branch 0 taken 112827 times.
✗ Branch 1 not taken.
112827 if (tls != NULL) {
138 112827 tls->is_set = false;
139 112827 tls->id = 0;
140 112827 tls->reponame = NULL;
141 112827 tls->client_instance = NULL;
142 }
143 112827 }
144
145
146 //------------------------------------------------------------------------------
147
148
149 594 CachePlugin::SessionInfo::SessionInfo(uint64_t id, const std::string &name)
150 594 : id(id), name(name) {
151
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 vector<string> tokens = SplitString(name, ':');
152 594 reponame = strdup(tokens[0].c_str());
153
2/2
✓ Branch 1 taken 528 times.
✓ Branch 2 taken 66 times.
594 if (tokens.size() > 1)
154 528 client_instance = strdup(tokens[1].c_str());
155 else
156 66 client_instance = NULL;
157 594 }
158
159 const uint64_t CachePlugin::kSizeUnknown = uint64_t(-1);
160
161
162 33066 void CachePlugin::AskToDetach() {
163 33066 char detach = kSignalDetach;
164
1/2
✓ Branch 1 taken 33066 times.
✗ Branch 2 not taken.
33066 WritePipe(pipe_ctrl_[1], &detach, 1);
165 33066 }
166
167
168 561 CachePlugin::CachePlugin(uint64_t capabilities)
169 561 : is_local_(false)
170 561 , capabilities_(capabilities)
171 561 , fd_socket_(-1)
172 561 , fd_socket_lock_(-1)
173 561 , running_(0)
174 561 , num_workers_(0)
175 561 , max_object_size_(kDefaultMaxObjectSize)
176
1/2
✓ Branch 3 taken 561 times.
✗ Branch 4 not taken.
561 , num_inlimbo_clients_(0) {
177 561 next_session_id_.store(0);
178 561 next_txn_id_.store(0);
179 561 next_lst_id_.store(0);
180 // Don't use listing id zero
181 561 next_lst_id_.fetch_add(1);
182
1/2
✓ Branch 2 taken 561 times.
✗ Branch 3 not taken.
561 txn_ids_.Init(128, UniqueRequest(), HashUniqueRequest);
183 561 memset(&thread_io_, 0, sizeof(thread_io_));
184
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 MakePipe(pipe_ctrl_);
185 561 }
186
187
188 1122 CachePlugin::~CachePlugin() {
189 1122 Terminate();
190 1122 ClosePipe(pipe_ctrl_);
191
1/2
✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
1122 if (fd_socket_ >= 0)
192 1122 close(fd_socket_);
193
1/2
✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
1122 if (fd_socket_lock_ >= 0)
194 1122 UnlockFile(fd_socket_lock_);
195 }
196
197
198 33 void CachePlugin::HandleBreadcrumbStore(cvmfs::MsgBreadcrumbStoreReq *msg_req,
199 CacheTransport *transport) {
200
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 const SessionCtxGuard session_guard(msg_req->session_id(), this);
201
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 cvmfs::MsgBreadcrumbReply msg_reply;
202
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 CacheTransport::Frame frame_send(&msg_reply);
203
204
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 msg_reply.set_req_id(msg_req->req_id());
205
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 manifest::Breadcrumb breadcrumb;
206
1/2
✓ Branch 3 taken 33 times.
✗ Branch 4 not taken.
33 const bool retval = transport->ParseMsgHash(msg_req->breadcrumb().hash(),
207 &breadcrumb.catalog_hash);
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!retval) {
209 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
210 "malformed hash received from client");
211 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
212 } else {
213 33 breadcrumb.timestamp = msg_req->breadcrumb().timestamp();
214
2/4
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
33 if (msg_req->breadcrumb().has_revision()) {
215 33 breadcrumb.revision = msg_req->breadcrumb().revision();
216 } else {
217 ✗ breadcrumb.revision = 0;
218 }
219
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
33 const cvmfs::EnumStatus status = StoreBreadcrumb(
220 33 msg_req->breadcrumb().fqrn(), breadcrumb);
221
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_reply.set_status(status);
222 }
223
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 transport->SendFrame(&frame_send);
224 33 }
225
226
227 66 void CachePlugin::HandleBreadcrumbLoad(cvmfs::MsgBreadcrumbLoadReq *msg_req,
228 CacheTransport *transport) {
229
1/2
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 const SessionCtxGuard session_guard(msg_req->session_id(), this);
230
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 cvmfs::MsgBreadcrumbReply msg_reply;
231
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 CacheTransport::Frame frame_send(&msg_reply);
232
233
1/2
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 msg_reply.set_req_id(msg_req->req_id());
234
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 manifest::Breadcrumb breadcrumb;
235
2/4
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
66 const cvmfs::EnumStatus status = LoadBreadcrumb(msg_req->fqrn(), &breadcrumb);
236
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 msg_reply.set_status(status);
237
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 33 times.
66 if (status == cvmfs::STATUS_OK) {
238
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
33 assert(breadcrumb.IsValid());
239
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
33 cvmfs::MsgHash *msg_hash = new cvmfs::MsgHash();
240
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 transport->FillMsgHash(breadcrumb.catalog_hash, msg_hash);
241
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
33 cvmfs::MsgBreadcrumb *msg_breadcrumb = new cvmfs::MsgBreadcrumb();
242
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_breadcrumb->set_fqrn(msg_req->fqrn());
243
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_breadcrumb->set_allocated_hash(msg_hash);
244
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_breadcrumb->set_timestamp(breadcrumb.timestamp);
245
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_breadcrumb->set_revision(breadcrumb.revision);
246
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_reply.set_allocated_breadcrumb(msg_breadcrumb);
247 }
248
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 transport->SendFrame(&frame_send);
249 66 }
250
251
252 594 void CachePlugin::HandleHandshake(cvmfs::MsgHandshake *msg_req,
253 CacheTransport *transport) {
254 594 const uint64_t session_id = NextSessionId();
255
2/4
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 594 times.
✗ Branch 4 not taken.
594 if (msg_req->has_name()) {
256
3/6
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 594 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 594 times.
✗ Branch 8 not taken.
594 sessions_[session_id] = SessionInfo(session_id, msg_req->name());
257 } else {
258 ✗ sessions_[session_id] = SessionInfo(
259 ✗ session_id, "anonymous client (" + StringifyInt(session_id) + ")");
260 }
261
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 cvmfs::MsgHandshakeAck msg_ack;
262
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 CacheTransport::Frame frame_send(&msg_ack);
263
264
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 msg_ack.set_status(cvmfs::STATUS_OK);
265 594 msg_ack.set_name(name_);
266
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 msg_ack.set_protocol_version(kPbProtocolVersion);
267
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 msg_ack.set_max_object_size(max_object_size_);
268
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 msg_ack.set_session_id(session_id);
269
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 msg_ack.set_capabilities(capabilities_);
270
1/2
✓ Branch 0 taken 594 times.
✗ Branch 1 not taken.
594 if (is_local_)
271
1/2
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
594 msg_ack.set_pid(getpid());
272
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 transport->SendFrame(&frame_send);
273 594 }
274
275
276 132 void CachePlugin::HandleInfo(cvmfs::MsgInfoReq *msg_req,
277 CacheTransport *transport) {
278
1/2
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
132 const SessionCtxGuard session_guard(msg_req->session_id(), this);
279
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 cvmfs::MsgInfoReply msg_reply;
280
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 CacheTransport::Frame frame_send(&msg_reply);
281
282
1/2
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
132 msg_reply.set_req_id(msg_req->req_id());
283 132 Info info;
284
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 const cvmfs::EnumStatus status = GetInfo(&info);
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 if (status != cvmfs::STATUS_OK) {
286 ✗ LogSessionError(msg_req->session_id(), status,
287 "failed to query cache status");
288 }
289
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 msg_reply.set_size_bytes(info.size_bytes);
290
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 msg_reply.set_used_bytes(info.used_bytes);
291
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 msg_reply.set_pinned_bytes(info.pinned_bytes);
292
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 msg_reply.set_no_shrink(info.no_shrink);
293
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 msg_reply.set_status(status);
294
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 transport->SendFrame(&frame_send);
295 132 }
296
297
298 132 void CachePlugin::HandleIoctl(cvmfs::MsgIoctl *msg_req) {
299
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 132 times.
132 if (!msg_req->has_conncnt_change_by())
300 ✗ return;
301 132 const int32_t conncnt_change_by = msg_req->conncnt_change_by();
302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 132 times.
132 if ((static_cast<int32_t>(num_inlimbo_clients_) + conncnt_change_by) < 0) {
303 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
304 "invalid request to drop connection counter below zero");
305 ✗ return;
306 }
307
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 66 times.
132 if (conncnt_change_by > 0) {
308
2/4
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 66 times.
✗ Branch 7 not taken.
66 LogSessionInfo(msg_req->session_id(), "lock session beyond lifetime");
309 } else {
310
2/4
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 66 times.
✗ Branch 7 not taken.
66 LogSessionInfo(msg_req->session_id(), "release session lock");
311 }
312 132 num_inlimbo_clients_ += conncnt_change_by;
313 }
314
315
316 330 void CachePlugin::HandleList(cvmfs::MsgListReq *msg_req,
317 CacheTransport *transport) {
318
1/2
✓ Branch 2 taken 330 times.
✗ Branch 3 not taken.
330 const SessionCtxGuard session_guard(msg_req->session_id(), this);
319
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 cvmfs::MsgListReply msg_reply;
320
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 CacheTransport::Frame frame_send(&msg_reply);
321
322
1/2
✓ Branch 2 taken 330 times.
✗ Branch 3 not taken.
330 msg_reply.set_req_id(msg_req->req_id());
323 330 int64_t listing_id = msg_req->listing_id();
324
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 msg_reply.set_listing_id(listing_id);
325
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 msg_reply.set_is_last_part(true);
326
327 cvmfs::EnumStatus status;
328
2/2
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 132 times.
330 if (msg_req->listing_id() == 0) {
329 198 listing_id = NextLstId();
330
1/2
✓ Branch 2 taken 198 times.
✗ Branch 3 not taken.
198 status = ListingBegin(listing_id, msg_req->object_type());
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (status != cvmfs::STATUS_OK) {
332 ✗ LogSessionError(msg_req->session_id(), status,
333 "failed to start enumeration of objects");
334 ✗ msg_reply.set_status(status);
335 ✗ transport->SendFrame(&frame_send);
336 ✗ return;
337 }
338
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 msg_reply.set_listing_id(listing_id);
339 }
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
330 assert(listing_id != 0);
341
342
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 ObjectInfo item;
343 330 unsigned total_size = 0;
344
3/4
✓ Branch 1 taken 6600198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6600000 times.
✓ Branch 4 taken 198 times.
6600198 while ((status = ListingNext(listing_id, &item)) == cvmfs::STATUS_OK) {
345
1/2
✓ Branch 1 taken 6600000 times.
✗ Branch 2 not taken.
6600000 cvmfs::MsgListRecord *msg_list_record = msg_reply.add_list_record();
346
2/4
✓ Branch 1 taken 6600000 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6600000 times.
✗ Branch 5 not taken.
6600000 cvmfs::MsgHash *msg_hash = new cvmfs::MsgHash();
347
1/2
✓ Branch 1 taken 6600000 times.
✗ Branch 2 not taken.
6600000 transport->FillMsgHash(item.id, msg_hash);
348
1/2
✓ Branch 1 taken 6600000 times.
✗ Branch 2 not taken.
6600000 msg_list_record->set_allocated_hash(msg_hash);
349
1/2
✓ Branch 1 taken 6600000 times.
✗ Branch 2 not taken.
6600000 msg_list_record->set_pinned(item.pinned);
350 msg_list_record->set_description(item.description);
351 // Approximation of the message size
352 6600000 total_size += sizeof(item) + item.description.length();
353
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 6599868 times.
6600000 if (total_size > kListingSize)
354 132 break;
355 }
356
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 132 times.
330 if (status == cvmfs::STATUS_OUTOFBOUNDS) {
357
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 ListingEnd(listing_id);
358 198 status = cvmfs::STATUS_OK;
359 } else {
360
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 msg_reply.set_is_last_part(false);
361 }
362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
330 if (status != cvmfs::STATUS_OK) {
363 ✗ LogSessionError(msg_req->session_id(), status, "failed enumerate objects");
364 }
365
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 msg_reply.set_status(status);
366
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 transport->SendFrame(&frame_send);
367
3/6
✓ Branch 2 taken 330 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 330 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 330 times.
✗ Branch 9 not taken.
330 }
368
369
370 528 void CachePlugin::HandleObjectInfo(cvmfs::MsgObjectInfoReq *msg_req,
371 CacheTransport *transport) {
372
1/2
✓ Branch 2 taken 528 times.
✗ Branch 3 not taken.
528 const SessionCtxGuard session_guard(msg_req->session_id(), this);
373
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 cvmfs::MsgObjectInfoReply msg_reply;
374
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 CacheTransport::Frame frame_send(&msg_reply);
375
376
1/2
✓ Branch 2 taken 528 times.
✗ Branch 3 not taken.
528 msg_reply.set_req_id(msg_req->req_id());
377
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 shash::Any object_id;
378
1/2
✓ Branch 2 taken 528 times.
✗ Branch 3 not taken.
528 const bool retval = transport->ParseMsgHash(msg_req->object_id(), &object_id);
379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 528 times.
528 if (!retval) {
380 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
381 "malformed hash received from client");
382 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
383 } else {
384
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 ObjectInfo info;
385
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 const cvmfs::EnumStatus status = GetObjectInfo(object_id, &info);
386
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 msg_reply.set_status(status);
387
2/2
✓ Branch 0 taken 495 times.
✓ Branch 1 taken 33 times.
528 if (status == cvmfs::STATUS_OK) {
388
1/2
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
495 msg_reply.set_object_type(info.object_type);
389
1/2
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
495 msg_reply.set_size(info.size);
390
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 } else if (status != cvmfs::STATUS_NOENTRY) {
391
2/4
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
33 LogSessionError(msg_req->session_id(), status,
392 "failed retrieving object details");
393 }
394 528 }
395
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 transport->SendFrame(&frame_send);
396 528 }
397
398
399 72963 void CachePlugin::HandleRead(cvmfs::MsgReadReq *msg_req,
400 CacheTransport *transport) {
401
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 const SessionCtxGuard session_guard(msg_req->session_id(), this);
402
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 cvmfs::MsgReadReply msg_reply;
403
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 CacheTransport::Frame frame_send(&msg_reply);
404
405
1/2
✓ Branch 2 taken 72963 times.
✗ Branch 3 not taken.
72963 msg_reply.set_req_id(msg_req->req_id());
406
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 shash::Any object_id;
407
1/2
✓ Branch 2 taken 72963 times.
✗ Branch 3 not taken.
72963 const bool retval = transport->ParseMsgHash(msg_req->object_id(), &object_id);
408
3/6
✓ Branch 0 taken 72963 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 72963 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 72963 times.
72963 if (!retval || (msg_req->size() > max_object_size_)) {
409 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
410 "malformed hash received from client");
411 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
412 ✗ transport->SendFrame(&frame_send);
413 ✗ return;
414 }
415 72963 unsigned size = msg_req->size();
416 #ifdef __APPLE__
417 unsigned char *buffer = reinterpret_cast<unsigned char *>(smalloc(size));
418 #else
419 72963 unsigned char buffer[size];
420 #endif
421
1/2
✓ Branch 2 taken 72963 times.
✗ Branch 3 not taken.
72963 const cvmfs::EnumStatus status = Pread(object_id, msg_req->offset(), &size,
422 buffer);
423
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 msg_reply.set_status(status);
424
2/2
✓ Branch 0 taken 72930 times.
✓ Branch 1 taken 33 times.
72963 if (status == cvmfs::STATUS_OK) {
425 72930 frame_send.set_attachment(buffer, size);
426 } else {
427
2/4
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
33 LogSessionError(msg_req->session_id(), status,
428 "failed to read from object");
429 }
430
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 transport->SendFrame(&frame_send);
431 #ifdef __APPLE__
432 free(buffer);
433 #endif
434
3/6
✓ Branch 2 taken 72963 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 72963 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 72963 times.
✗ Branch 9 not taken.
145926 }
435
436
437 18612 void CachePlugin::HandleRefcount(cvmfs::MsgRefcountReq *msg_req,
438 CacheTransport *transport) {
439
1/2
✓ Branch 2 taken 18612 times.
✗ Branch 3 not taken.
18612 const SessionCtxGuard session_guard(msg_req->session_id(), this);
440
1/2
✓ Branch 1 taken 18612 times.
✗ Branch 2 not taken.
18612 cvmfs::MsgRefcountReply msg_reply;
441
1/2
✓ Branch 1 taken 18612 times.
✗ Branch 2 not taken.
18612 CacheTransport::Frame frame_send(&msg_reply);
442
443
1/2
✓ Branch 2 taken 18612 times.
✗ Branch 3 not taken.
18612 msg_reply.set_req_id(msg_req->req_id());
444
1/2
✓ Branch 1 taken 18612 times.
✗ Branch 2 not taken.
18612 shash::Any object_id;
445
1/2
✓ Branch 2 taken 18612 times.
✗ Branch 3 not taken.
18612 const bool retval = transport->ParseMsgHash(msg_req->object_id(), &object_id);
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18612 times.
18612 if (!retval) {
447 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
448 "malformed hash received from client");
449 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
450 } else {
451
1/2
✓ Branch 2 taken 18612 times.
✗ Branch 3 not taken.
18612 const cvmfs::EnumStatus status = ChangeRefcount(object_id,
452 msg_req->change_by());
453
1/2
✓ Branch 1 taken 18612 times.
✗ Branch 2 not taken.
18612 msg_reply.set_status(status);
454
4/4
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 18546 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 33 times.
18612 if ((status != cvmfs::STATUS_OK) && (status != cvmfs::STATUS_NOENTRY)) {
455
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 LogSessionError(msg_req->session_id(), status,
456
2/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
66 "failed to open/close object " + object_id.ToString());
457 }
458 }
459
1/2
✓ Branch 1 taken 18612 times.
✗ Branch 2 not taken.
18612 transport->SendFrame(&frame_send);
460 18612 }
461
462
463 114147 bool CachePlugin::HandleRequest(int fd_con) {
464 114147 CacheTransport transport(fd_con, CacheTransport::kFlagSendIgnoreFailure);
465 114147 char buffer[max_object_size_];
466
1/2
✓ Branch 1 taken 114147 times.
✗ Branch 2 not taken.
114147 CacheTransport::Frame frame_recv;
467 114147 frame_recv.set_attachment(buffer, max_object_size_);
468
1/2
✓ Branch 1 taken 114147 times.
✗ Branch 2 not taken.
114147 const bool retval = transport.RecvFrame(&frame_recv);
469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114147 times.
114147 if (!retval) {
470 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogDebug,
471 ✗ "failed to receive request from connection (%d)", errno);
472 ✗ return false;
473 }
474
475
1/2
✓ Branch 1 taken 114147 times.
✗ Branch 2 not taken.
114147 google::protobuf::MessageLite *msg_typed = frame_recv.GetMsgTyped();
476
477
3/4
✓ Branch 1 taken 114147 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 594 times.
✓ Branch 6 taken 113553 times.
114147 if (msg_typed->GetTypeName() == "cvmfs.MsgHandshake") {
478 594 cvmfs::MsgHandshake *msg_req = reinterpret_cast<cvmfs::MsgHandshake *>(
479 msg_typed);
480
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 HandleHandshake(msg_req, &transport);
481
3/4
✓ Branch 1 taken 113553 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 594 times.
✓ Branch 6 taken 112959 times.
113553 } else if (msg_typed->GetTypeName() == "cvmfs.MsgQuit") {
482 594 cvmfs::MsgQuit *msg_req = reinterpret_cast<cvmfs::MsgQuit *>(msg_typed);
483 1782 const map<uint64_t, SessionInfo>::const_iterator iter = sessions_.find(
484
1/2
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
594 msg_req->session_id());
485
1/2
✓ Branch 3 taken 594 times.
✗ Branch 4 not taken.
594 if (iter != sessions_.end()) {
486 594 free(iter->second.reponame);
487 594 free(iter->second.client_instance);
488 }
489
1/2
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
594 sessions_.erase(msg_req->session_id());
490 594 return false;
491
3/4
✓ Branch 1 taken 112959 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 132 times.
✓ Branch 6 taken 112827 times.
112959 } else if (msg_typed->GetTypeName() == "cvmfs.MsgIoctl") {
492
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 HandleIoctl(reinterpret_cast<cvmfs::MsgIoctl *>(msg_typed));
493
3/4
✓ Branch 1 taken 112827 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 18612 times.
✓ Branch 6 taken 94215 times.
112827 } else if (msg_typed->GetTypeName() == "cvmfs.MsgRefcountReq") {
494 18612 cvmfs::MsgRefcountReq *msg_req = reinterpret_cast<cvmfs::MsgRefcountReq *>(
495 msg_typed);
496
1/2
✓ Branch 1 taken 18612 times.
✗ Branch 2 not taken.
18612 HandleRefcount(msg_req, &transport);
497
3/4
✓ Branch 1 taken 94215 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 528 times.
✓ Branch 6 taken 93687 times.
94215 } else if (msg_typed->GetTypeName() == "cvmfs.MsgObjectInfoReq") {
498 cvmfs::MsgObjectInfoReq
499 528 *msg_req = reinterpret_cast<cvmfs::MsgObjectInfoReq *>(msg_typed);
500
1/2
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
528 HandleObjectInfo(msg_req, &transport);
501
3/4
✓ Branch 1 taken 93687 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 72963 times.
✓ Branch 6 taken 20724 times.
93687 } else if (msg_typed->GetTypeName() == "cvmfs.MsgReadReq") {
502 72963 cvmfs::MsgReadReq *msg_req = reinterpret_cast<cvmfs::MsgReadReq *>(
503 msg_typed);
504
1/2
✓ Branch 1 taken 72963 times.
✗ Branch 2 not taken.
72963 HandleRead(msg_req, &transport);
505
3/4
✓ Branch 1 taken 20724 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 20064 times.
✓ Branch 6 taken 660 times.
20724 } else if (msg_typed->GetTypeName() == "cvmfs.MsgStoreReq") {
506 20064 cvmfs::MsgStoreReq *msg_req = reinterpret_cast<cvmfs::MsgStoreReq *>(
507 msg_typed);
508
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 HandleStore(msg_req, &frame_recv, &transport);
509
3/4
✓ Branch 1 taken 660 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 33 times.
✓ Branch 6 taken 627 times.
660 } else if (msg_typed->GetTypeName() == "cvmfs.MsgStoreAbortReq") {
510 cvmfs::MsgStoreAbortReq
511 33 *msg_req = reinterpret_cast<cvmfs::MsgStoreAbortReq *>(msg_typed);
512
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 HandleStoreAbort(msg_req, &transport);
513
3/4
✓ Branch 1 taken 627 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 132 times.
✓ Branch 6 taken 495 times.
627 } else if (msg_typed->GetTypeName() == "cvmfs.MsgInfoReq") {
514 132 cvmfs::MsgInfoReq *msg_req = reinterpret_cast<cvmfs::MsgInfoReq *>(
515 msg_typed);
516
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 HandleInfo(msg_req, &transport);
517
3/4
✓ Branch 1 taken 495 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 66 times.
✓ Branch 6 taken 429 times.
495 } else if (msg_typed->GetTypeName() == "cvmfs.MsgShrinkReq") {
518 66 cvmfs::MsgShrinkReq *msg_req = reinterpret_cast<cvmfs::MsgShrinkReq *>(
519 msg_typed);
520
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 HandleShrink(msg_req, &transport);
521
3/4
✓ Branch 1 taken 429 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 330 times.
✓ Branch 6 taken 99 times.
429 } else if (msg_typed->GetTypeName() == "cvmfs.MsgListReq") {
522 330 cvmfs::MsgListReq *msg_req = reinterpret_cast<cvmfs::MsgListReq *>(
523 msg_typed);
524
1/2
✓ Branch 1 taken 330 times.
✗ Branch 2 not taken.
330 HandleList(msg_req, &transport);
525
3/4
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 33 times.
✓ Branch 6 taken 66 times.
99 } else if (msg_typed->GetTypeName() == "cvmfs.MsgBreadcrumbStoreReq") {
526 cvmfs::MsgBreadcrumbStoreReq
527 33 *msg_req = reinterpret_cast<cvmfs::MsgBreadcrumbStoreReq *>(msg_typed);
528
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 HandleBreadcrumbStore(msg_req, &transport);
529
2/4
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
66 } else if (msg_typed->GetTypeName() == "cvmfs.MsgBreadcrumbLoadReq") {
530 cvmfs::MsgBreadcrumbLoadReq
531 66 *msg_req = reinterpret_cast<cvmfs::MsgBreadcrumbLoadReq *>(msg_typed);
532
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 HandleBreadcrumbLoad(msg_req, &transport);
533 } else {
534 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogDebug,
535 "unexpected message from client: %s",
536 ✗ std::string(msg_typed->GetTypeName()).c_str());
537 ✗ return false;
538 }
539
540 113553 return true;
541
1/2
✓ Branch 1 taken 114147 times.
✗ Branch 2 not taken.
228294 }
542
543
544 66 void CachePlugin::HandleShrink(cvmfs::MsgShrinkReq *msg_req,
545 CacheTransport *transport) {
546
1/2
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 const SessionCtxGuard session_guard(msg_req->session_id(), this);
547
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 cvmfs::MsgShrinkReply msg_reply;
548
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 CacheTransport::Frame frame_send(&msg_reply);
549
550
1/2
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 msg_reply.set_req_id(msg_req->req_id());
551 66 uint64_t used_bytes = 0;
552
1/2
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
66 const cvmfs::EnumStatus status = Shrink(msg_req->shrink_to(), &used_bytes);
553
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 msg_reply.set_used_bytes(used_bytes);
554
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 msg_reply.set_status(status);
555
3/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
66 if ((status != cvmfs::STATUS_OK) && (status != cvmfs::STATUS_PARTIAL)) {
556 ✗ LogSessionError(msg_req->session_id(), status, "failed to cleanup cache");
557 }
558
1/2
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
66 transport->SendFrame(&frame_send);
559 66 }
560
561
562 33 void CachePlugin::HandleStoreAbort(cvmfs::MsgStoreAbortReq *msg_req,
563 CacheTransport *transport) {
564
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 const SessionCtxGuard session_guard(msg_req->session_id(), this);
565
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 cvmfs::MsgStoreReply msg_reply;
566
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 CacheTransport::Frame frame_send(&msg_reply);
567
1/2
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
33 msg_reply.set_req_id(msg_req->req_id());
568
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_reply.set_part_nr(0);
569 uint64_t txn_id;
570 33 const UniqueRequest uniq_req(msg_req->session_id(), msg_req->req_id());
571
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 const bool retval = txn_ids_.Lookup(uniq_req, &txn_id);
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!retval) {
573 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
574 "malformed transaction id received from client");
575 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
576 } else {
577
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 const cvmfs::EnumStatus status = AbortTxn(txn_id);
578
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 msg_reply.set_status(status);
579
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (status != cvmfs::STATUS_OK) {
580 ✗ LogSessionError(msg_req->session_id(), status,
581 "failed to abort transaction");
582 }
583
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 txn_ids_.Erase(uniq_req);
584 }
585
1/2
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
33 transport->SendFrame(&frame_send);
586 33 }
587
588
589 20064 void CachePlugin::HandleStore(cvmfs::MsgStoreReq *msg_req,
590 CacheTransport::Frame *frame,
591 CacheTransport *transport) {
592
1/2
✓ Branch 2 taken 20064 times.
✗ Branch 3 not taken.
20064 const SessionCtxGuard session_guard(msg_req->session_id(), this);
593
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 cvmfs::MsgStoreReply msg_reply;
594
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 CacheTransport::Frame frame_send(&msg_reply);
595
1/2
✓ Branch 2 taken 20064 times.
✗ Branch 3 not taken.
20064 msg_reply.set_req_id(msg_req->req_id());
596
1/2
✓ Branch 2 taken 20064 times.
✗ Branch 3 not taken.
20064 msg_reply.set_part_nr(msg_req->part_nr());
597
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 shash::Any object_id;
598
1/2
✓ Branch 2 taken 20064 times.
✗ Branch 3 not taken.
20064 bool retval = transport->ParseMsgHash(msg_req->object_id(), &object_id);
599
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 if (!retval || (frame->att_size() > max_object_size_)
600
5/8
✓ Branch 0 taken 20064 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 99 times.
✓ Branch 4 taken 19965 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 99 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 20064 times.
40128 || ((frame->att_size() < max_object_size_) && !msg_req->last_part())) {
601 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
602 "malformed hash or bad object size received from client");
603 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
604 ✗ transport->SendFrame(&frame_send);
605 ✗ return;
606 }
607
608 20064 const UniqueRequest uniq_req(msg_req->session_id(), msg_req->req_id());
609 uint64_t txn_id;
610 20064 cvmfs::EnumStatus status = cvmfs::STATUS_OK;
611
2/2
✓ Branch 1 taken 231 times.
✓ Branch 2 taken 19833 times.
20064 if (msg_req->part_nr() == 1) {
612
2/4
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 231 times.
231 if (txn_ids_.Contains(uniq_req)) {
613 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
614 "invalid attempt to restart running transaction");
615 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
616 ✗ transport->SendFrame(&frame_send);
617 ✗ return;
618 }
619 231 txn_id = NextTxnId();
620
1/2
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
231 ObjectInfo info;
621 231 info.id = object_id;
622
2/4
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 231 times.
✗ Branch 4 not taken.
231 if (msg_req->has_expected_size()) {
623 231 info.size = msg_req->expected_size();
624 }
625
2/4
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 231 times.
✗ Branch 4 not taken.
231 if (msg_req->has_object_type()) {
626 231 info.object_type = msg_req->object_type();
627 }
628
2/4
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 231 times.
✗ Branch 4 not taken.
231 if (msg_req->has_description()) {
629
2/4
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 231 times.
✗ Branch 5 not taken.
231 info.description = msg_req->description();
630 }
631
1/2
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
231 status = StartTxn(object_id, txn_id, info);
632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 231 times.
231 if (status != cvmfs::STATUS_OK) {
633 ✗ LogSessionError(msg_req->session_id(), status,
634 "failed to start transaction");
635 ✗ msg_reply.set_status(status);
636 ✗ transport->SendFrame(&frame_send);
637 ✗ return;
638 }
639
1/2
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
231 txn_ids_.Insert(uniq_req, txn_id);
640
1/2
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
231 } else {
641
1/2
✓ Branch 1 taken 19833 times.
✗ Branch 2 not taken.
19833 retval = txn_ids_.Lookup(uniq_req, &txn_id);
642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 19833 times.
19833 if (!retval) {
643 ✗ LogSessionError(msg_req->session_id(), cvmfs::STATUS_MALFORMED,
644 "invalid transaction received from client");
645 ✗ msg_reply.set_status(cvmfs::STATUS_MALFORMED);
646 ✗ transport->SendFrame(&frame_send);
647 ✗ return;
648 }
649 }
650
651 // TODO(jblomer): check part number and send objects up in order
652
2/2
✓ Branch 1 taken 20031 times.
✓ Branch 2 taken 33 times.
20064 if (frame->att_size() > 0) {
653
1/2
✓ Branch 2 taken 20031 times.
✗ Branch 3 not taken.
40062 status = WriteTxn(txn_id,
654 20031 reinterpret_cast<unsigned char *>(frame->attachment()),
655 frame->att_size());
656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20031 times.
20031 if (status != cvmfs::STATUS_OK) {
657 ✗ LogSessionError(msg_req->session_id(), status, "failure writing object");
658 ✗ msg_reply.set_status(status);
659 ✗ transport->SendFrame(&frame_send);
660 ✗ return;
661 }
662 }
663
664
2/2
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 19866 times.
20064 if (msg_req->last_part()) {
665
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 status = CommitTxn(txn_id);
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (status != cvmfs::STATUS_OK) {
667 ✗ LogSessionError(msg_req->session_id(), status,
668 "failure committing object");
669 }
670
1/2
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
198 txn_ids_.Erase(uniq_req);
671 }
672
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 msg_reply.set_status(status);
673
1/2
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
20064 transport->SendFrame(&frame_send);
674
3/6
✓ Branch 1 taken 20064 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 20064 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 20064 times.
✗ Branch 8 not taken.
20064 }
675
676
677 1122 bool CachePlugin::IsRunning() { return running_.load() != 0; }
678
679
680 561 bool CachePlugin::Listen(const string &locator) {
681
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 vector<string> tokens = SplitString(locator, '=');
682
1/2
✓ Branch 2 taken 561 times.
✗ Branch 3 not taken.
561 if (tokens[0] == "unix") {
683
1/2
✓ Branch 2 taken 561 times.
✗ Branch 3 not taken.
561 const string lock_path = tokens[1] + ".lock";
684
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 fd_socket_lock_ = TryLockFile(lock_path);
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 if (fd_socket_lock_ == -1) {
686 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogDebug,
687 ✗ "failed to acquire lock file %s (%d)", lock_path.c_str(), errno);
688 ✗ NotifySupervisor(CacheTransport::kFailureNotification);
689 ✗ return false;
690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 } else if (fd_socket_lock_ == -2) {
691 // Another plugin process probably started in the meantime
692 ✗ NotifySupervisor(CacheTransport::kReadyNotification);
693 ✗ if (getenv(CacheTransport::kEnvReadyNotifyFd) == NULL) {
694 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogStderr,
695 "failed to lock on %s, file is busy", lock_path.c_str());
696 }
697 ✗ return false;
698 }
699
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 assert(fd_socket_lock_ >= 0);
700
1/2
✓ Branch 2 taken 561 times.
✗ Branch 3 not taken.
561 fd_socket_ = MakeSocket(tokens[1], 0600);
701 561 is_local_ = true;
702
1/4
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
561 } else if (tokens[0] == "tcp") {
703 ✗ vector<string> tcp_address = SplitString(tokens[1], ':');
704 ✗ if (tcp_address.size() != 2) {
705 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogDebug, "invalid locator: %s",
706 locator.c_str());
707 ✗ NotifySupervisor(CacheTransport::kFailureNotification);
708 ✗ return false;
709 }
710 ✗ fd_socket_ = MakeTcpEndpoint(tcp_address[0], String2Uint64(tcp_address[1]));
711 ✗ } else {
712 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogDebug,
713 "unknown endpoint in locator: %s", locator.c_str());
714 ✗ NotifySupervisor(CacheTransport::kFailureNotification);
715 ✗ return false;
716 }
717
718
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 if (fd_socket_ < 0) {
719 ✗ if (errno == EADDRINUSE) {
720 // Another plugin process probably started in the meantime
721 ✗ NotifySupervisor(CacheTransport::kReadyNotification);
722 } else {
723 ✗ LogCvmfs(kLogCache, kLogSyslogErr | kLogDebug,
724 ✗ "failed to create endpoint %s (%d)", locator.c_str(), errno);
725 ✗ NotifySupervisor(CacheTransport::kFailureNotification);
726 }
727 ✗ is_local_ = false;
728 ✗ return false;
729 }
730 561 const int retval = listen(fd_socket_, 32);
731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 assert(retval == 0);
732
733 561 return true;
734 561 }
735
736
737 132 void CachePlugin::LogSessionInfo(uint64_t session_id, const string &msg) {
738
3/6
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 132 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 132 times.
✗ Branch 8 not taken.
264 string session_str("unidentified client (" + StringifyInt(session_id) + ")");
739
1/2
✓ Branch 1 taken 132 times.
✗ Branch 2 not taken.
132 const map<uint64_t, SessionInfo>::const_iterator iter = sessions_.find(
740 132 session_id);
741
1/2
✓ Branch 3 taken 132 times.
✗ Branch 4 not taken.
132 if (iter != sessions_.end()) {
742
1/2
✓ Branch 2 taken 132 times.
✗ Branch 3 not taken.
132 session_str = iter->second.name;
743 }
744
1/2
✓ Branch 3 taken 132 times.
✗ Branch 4 not taken.
132 LogCvmfs(kLogCache, kLogDebug | kLogSyslog, "session '%s': %s",
745 session_str.c_str(), msg.c_str());
746 132 }
747
748
749 99 void CachePlugin::LogSessionError(uint64_t session_id,
750 cvmfs::EnumStatus status,
751 const std::string &msg) {
752
3/6
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 99 times.
✗ Branch 8 not taken.
198 string session_str("unidentified client (" + StringifyInt(session_id) + ")");
753
1/2
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
99 const map<uint64_t, SessionInfo>::const_iterator iter = sessions_.find(
754 99 session_id);
755
1/2
✓ Branch 3 taken 99 times.
✗ Branch 4 not taken.
99 if (iter != sessions_.end()) {
756
1/2
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
99 session_str = iter->second.name;
757 }
758
1/2
✓ Branch 4 taken 99 times.
✗ Branch 5 not taken.
99 LogCvmfs(kLogCache, kLogDebug | kLogSyslogErr, "session '%s': %s (%d - %s)",
759 session_str.c_str(), msg.c_str(), status,
760 CacheTransportCode2Ascii(status));
761 99 }
762
763
764 561 void *CachePlugin::MainProcessRequests(void *data) {
765 561 CachePlugin *cache_plugin = reinterpret_cast<CachePlugin *>(data);
766
767 561 platform_sighandler_t save_sigpipe = signal(SIGPIPE, SIG_IGN);
768
769 561 vector<struct pollfd> watch_fds;
770 // Elements 0, 1: control pipe, socket fd
771 struct pollfd watch_ctrl;
772 561 watch_ctrl.fd = cache_plugin->pipe_ctrl_[0];
773 561 watch_ctrl.events = POLLIN | POLLPRI;
774
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 watch_fds.push_back(watch_ctrl);
775 struct pollfd watch_socket;
776 561 watch_socket.fd = cache_plugin->fd_socket_;
777 561 watch_socket.events = POLLIN | POLLPRI;
778
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 watch_fds.push_back(watch_socket);
779
780 561 bool terminated = false;
781
1/2
✓ Branch 0 taken 147774 times.
✗ Branch 1 not taken.
147774 while (!terminated) {
782
2/2
✓ Branch 1 taken 442167 times.
✓ Branch 2 taken 147774 times.
589941 for (unsigned i = 0; i < watch_fds.size(); ++i)
783 442167 watch_fds[i].revents = 0;
784
1/2
✓ Branch 3 taken 147774 times.
✗ Branch 4 not taken.
147774 const int retval = poll(&watch_fds[0], watch_fds.size(), -1);
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147774 times.
147774 if (retval < 0) {
786 ✗ if (errno == EINTR)
787 ✗ continue;
788 ✗ PANIC(kLogSyslogErr | kLogDebug, "cache plugin connection failure (%d)",
789 errno);
790 }
791
792 // Termination or detach
793
2/2
✓ Branch 1 taken 33627 times.
✓ Branch 2 taken 114147 times.
147774 if (watch_fds[0].revents) {
794 char signal;
795
1/2
✓ Branch 2 taken 33627 times.
✗ Branch 3 not taken.
33627 ReadPipe(watch_fds[0].fd, &signal, 1);
796
2/2
✓ Branch 0 taken 33066 times.
✓ Branch 1 taken 561 times.
33627 if (signal == kSignalDetach) {
797
1/2
✓ Branch 1 taken 33066 times.
✗ Branch 2 not taken.
33066 cache_plugin->SendDetachRequests();
798 33066 continue;
799 }
800
801 // termination
802
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 561 times.
561 if (watch_fds.size() > 2) {
803 ✗ LogCvmfs(kLogCache, kLogSyslogWarn | kLogDebug,
804 "terminating external cache manager with pending connections");
805 }
806 561 break;
807 }
808
809 // New connection
810
2/2
✓ Branch 1 taken 594 times.
✓ Branch 2 taken 113553 times.
114147 if (watch_fds[1].revents) {
811 struct sockaddr_un remote;
812 594 socklen_t socket_size = sizeof(remote);
813
1/2
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
594 const int fd_con = accept(watch_fds[1].fd, (struct sockaddr *)&remote,
814 594 &socket_size);
815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 594 times.
594 if (fd_con < 0) {
816 ✗ LogCvmfs(kLogCache, kLogSyslogWarn | kLogDebug,
817 ✗ "failed to establish connection (%d)", errno);
818 ✗ continue;
819 }
820 struct pollfd watch_con;
821 594 watch_con.fd = fd_con;
822 594 watch_con.events = POLLIN | POLLPRI;
823
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 watch_fds.push_back(watch_con);
824
1/2
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
594 cache_plugin->connections_.insert(fd_con);
825 }
826
827 // New request
828
2/2
✓ Branch 1 taken 114147 times.
✓ Branch 2 taken 114147 times.
228294 for (unsigned i = 2; i < watch_fds.size();) {
829
1/2
✓ Branch 1 taken 114147 times.
✗ Branch 2 not taken.
114147 if (watch_fds[i].revents) {
830
1/2
✓ Branch 2 taken 114147 times.
✗ Branch 3 not taken.
114147 const bool proceed = cache_plugin->HandleRequest(watch_fds[i].fd);
831
2/2
✓ Branch 0 taken 594 times.
✓ Branch 1 taken 113553 times.
114147 if (!proceed) {
832
1/2
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
594 close(watch_fds[i].fd);
833
1/2
✓ Branch 2 taken 594 times.
✗ Branch 3 not taken.
594 cache_plugin->connections_.erase(watch_fds[i].fd);
834
1/2
✓ Branch 4 taken 594 times.
✗ Branch 5 not taken.
594 watch_fds.erase(watch_fds.begin() + i);
835 594 if ((getenv(CacheTransport::kEnvReadyNotifyFd) != NULL)
836 ✗ && (cache_plugin->connections_.empty())
837
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 594 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 594 times.
594 && (cache_plugin->num_inlimbo_clients_ == 0)) {
838 ✗ LogCvmfs(kLogCache, kLogSyslog,
839 "stopping cache plugin, no more active clients");
840 ✗ terminated = true;
841 ✗ break;
842 }
843 } else {
844 113553 i++;
845 }
846 } else {
847 ✗ i++;
848 }
849 }
850 }
851
852 // 0, 1 being closed by destructor
853
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 561 times.
561 for (unsigned i = 2; i < watch_fds.size(); ++i)
854 ✗ close(watch_fds[i].fd);
855
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 cache_plugin->txn_ids_.Clear();
856
857 561 signal(SIGPIPE, save_sigpipe);
858 561 return NULL;
859 561 }
860
861
862 /**
863 * Used during startup to synchronize with the cvmfs client.
864 */
865 561 void CachePlugin::NotifySupervisor(char signal) {
866 561 char *pipe_ready = getenv(CacheTransport::kEnvReadyNotifyFd);
867
1/2
✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
561 if (pipe_ready == NULL)
868 561 return;
869 ✗ const int fd_pipe_ready = String2Int64(pipe_ready);
870 ✗ WritePipe(fd_pipe_ready, &signal, 1);
871 }
872
873
874 561 void CachePlugin::ProcessRequests(unsigned num_workers) {
875 561 num_workers_ = num_workers;
876 561 const int retval = pthread_create(&thread_io_, NULL, MainProcessRequests,
877 this);
878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 561 times.
561 assert(retval == 0);
879
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 NotifySupervisor(CacheTransport::kReadyNotification);
880 561 int32_t expected_val = 0;
881 561 running_.compare_exchange_strong(expected_val, 1);
882 561 }
883
884
885 33066 void CachePlugin::SendDetachRequests() {
886 33066 set<int>::const_iterator iter = connections_.begin();
887 33066 const set<int>::const_iterator iter_end = connections_.end();
888
2/2
✓ Branch 2 taken 33066 times.
✓ Branch 3 taken 33066 times.
66132 for (; iter != iter_end; ++iter) {
889 33066 CacheTransport transport(*iter,
890 CacheTransport::kFlagSendIgnoreFailure
891
1/2
✓ Branch 1 taken 33066 times.
✗ Branch 2 not taken.
33066 | CacheTransport::kFlagSendNonBlocking);
892
1/2
✓ Branch 1 taken 33066 times.
✗ Branch 2 not taken.
33066 cvmfs::MsgDetach msg_detach;
893
1/2
✓ Branch 1 taken 33066 times.
✗ Branch 2 not taken.
33066 CacheTransport::Frame frame_send(&msg_detach);
894
1/2
✓ Branch 1 taken 33066 times.
✗ Branch 2 not taken.
33066 transport.SendFrame(&frame_send);
895 33066 }
896 33066 }
897
898
899 561 void CachePlugin::Terminate() {
900
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 if (IsRunning()) {
901 561 char terminate = kSignalTerminate;
902
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 WritePipe(pipe_ctrl_[1], &terminate, 1);
903
1/2
✓ Branch 1 taken 561 times.
✗ Branch 2 not taken.
561 pthread_join(thread_io_, NULL);
904 561 int32_t expected_val = 1;
905 561 running_.compare_exchange_strong(expected_val, 0);
906 }
907 561 }
908
909
910 ✗ void CachePlugin::WaitFor() {
911 ✗ if (!IsRunning())
912 ✗ return;
913 ✗ pthread_join(thread_io_, NULL);
914 }
915