GCC Code Coverage Report


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