GCC Code Coverage Report


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