GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/bundle_mgr.h
Date: 2026-07-05 02:36:18
Exec Total Coverage
Lines: 28 29 96.6%
Branches: 10 20 50.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_BUNDLE_MGR_H_
6 #define CVMFS_BUNDLE_MGR_H_
7
8 #include <limits.h>
9 #include <pthread.h>
10
11 #include <cassert>
12 #include <cstddef>
13 #include <memory>
14 #include <type_traits>
15 #include <vector>
16
17 #include "duplex_testing.h"
18 #include "file_bundle.h"
19 #include "mountpoint.h"
20 #include "shortstring.h"
21 #include "util/posix.h"
22 #include "util/single_copy.h"
23
24 class MockFetcher;
25
26 class BundleMgr : SingleCopy {
27 friend class T_BundleMgr;
28 FRIEND_TEST(T_BundleMgr, ExchangeCT);
29 FRIEND_TEST(T_BundleMgr, ExchangePathString);
30 FRIEND_TEST(T_BundleMgr, Fetch);
31
32 public:
33 BundleMgr(MountPoint *mp, const PathString &path);
34 588 virtual ~BundleMgr() {
35 294 JoinFetcherPool();
36 294 pthread_mutex_destroy(&worker_read_mutex_);
37
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
294 delete bfm_;
38 588 }
39 void Fetch();
40 explicit operator bool() const { return is_valid_; }
41
42 private:
43 static void *MainBundleMgrFetcher(void *data);
44 void SpawnFetcherPool();
45 void JoinFetcherPool();
46 PathString ReceivePath(int fd) const;
47 bool TrySendPath(int fd, const PathString &path) const;
48
49 void FetchPath(const PathString &path);
50
51 // CT stands for contiguous type
52 template<typename CT,
53 typename = typename std::enable_if<
54 std::is_trivially_copyable<CT>::value>::type>
55 588 void BlockingSend(int fd, const CT &obj, size_t size = sizeof(CT)) const {
56 typedef typename std::remove_cv<CT>::type T;
57 static_assert(
58 std::is_trivially_copyable<T>::value,
59 "Can't directly send non trivially copyable types over a pipe");
60 static_assert(sizeof(T) == sizeof(CT), "CT illformed");
61 static_assert(
62 sizeof(T) <= PIPE_BUF,
63 "Type too big to be guaranteed atomic transmission over a pipe");
64
65 588 const T *ptr = reinterpret_cast<const T *>(&obj);
66 588 WritePipe(fd, ptr, size);
67 588 }
68
69 196 void BlockingSend(int fd, const PathString &path) const {
70 196 const size_t size = path.GetLength();
71
1/2
✓ Branch 1 taken 196 times.
✗ Branch 2 not taken.
196 BlockingSend(fd, size);
72
1/2
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
196 WritePipe(fd, path.GetChars(), size * sizeof(char));
73 196 }
74
75 49 void BlockingSend(int fd, const std::string &string) const {
76 49 const size_t size = string.size();
77
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
49 BlockingSend(fd, size);
78
1/2
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
49 WritePipe(fd, string.data(), size * sizeof(char));
79 49 }
80
81 template<typename CT,
82 typename = typename std::enable_if<
83 std::is_trivially_copyable<CT>::value>::type>
84 588 CT BlockingReceive(int fd) const {
85 typedef typename std::remove_cv<CT>::type T;
86 static_assert(
87 sizeof(T) <= PIPE_BUF,
88 "Type too big to be guaranteed atomic transmission over a pipe");
89 CT item;
90
1/2
✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
588 ReadPipe(fd, static_cast<void *>(&item), sizeof(CT));
91 588 return item;
92 }
93
94 245 std::string BlockingReceive(int fd) const {
95 245 const size_t size = BlockingReceive<size_t>(fd);
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 assert(size * sizeof(char) < PIPE_BUF);
97
1/2
✓ Branch 2 taken 245 times.
✗ Branch 3 not taken.
245 std::string result(size, '\t');
98
2/4
✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 245 times.
✗ Branch 5 not taken.
245 ReadPipe(fd, static_cast<void *>(&result[0]), size * sizeof(char));
99 245 return result;
100 }
101
102 MountPoint *mount_point_;
103 PathString path_;
104 NameString fname_;
105 PathString parent_path_;
106
107 // The file that contains the dependences
108 PathString bundle_file_path_;
109 BundleFileMgr *bfm_;
110
111 // Pool of fetcher threads. All workers share pipe_bm_[0] (read end)
112 // and serialize their reads via worker_read_mutex_ so cmd+payload
113 // pairs are received atomically.
114 std::vector<std::unique_ptr<pthread_t> > fetcher_threads_;
115 pthread_mutex_t worker_read_mutex_;
116 size_t pool_size_;
117 int back_channel_;
118
119 enum class Command {
120 kTerminate,
121 kFetch
122 };
123
124 /**
125 * Work queue (a pipe). Main thread writes Command + path payload to
126 * pipe_bm_[1]; workers read from pipe_bm_[0] under worker_read_mutex_.
127 */
128 int pipe_bm_[2];
129 bool is_valid_ = true;
130 };
131 #endif // CVMFS_BUNDLE_MGR_H_
132
133