| 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 |