GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/fd_table.h
Date: 2026-07-05 02:36:18
Exec Total Coverage
Lines: 62 63 98.4%
Branches: 40 59 67.8%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_FD_TABLE_H_
6 #define CVMFS_FD_TABLE_H_
7
8 #include <errno.h>
9 #include <inttypes.h>
10 #include <stdint.h>
11
12 #include <cassert>
13 #include <cstddef>
14 #include <vector>
15
16 #include "util/single_copy.h"
17
18 /**
19 * Maintains integers mapped to custom open file descriptors. File descriptors
20 * can be added, removed, and accessed. All operations take constant time. The
21 * maximum file descriptor number needs to be known upfront.
22 *
23 * Note that new file descriptors do not necessarily have the smallest available
24 * number but any number between 0..max_open_fds.
25 *
26 * This class is used by a couple of cache managers.
27 */
28 template<class HandleT>
29 class FdTable : SingleCopy {
30 public:
31 2170 FdTable(unsigned max_open_fds, const HandleT &invalid_handle)
32 2170 : invalid_handle_(invalid_handle)
33 2170 , fd_pivot_(0)
34
1/2
✓ Branch 2 taken 2170 times.
✗ Branch 3 not taken.
2170 , fd_index_(max_open_fds)
35
4/7
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 2166 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
4340 , open_fds_(max_open_fds, FdWrapper(invalid_handle_, 0)) {
36
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2170 times.
2170 assert(max_open_fds > 0);
37
2/2
✓ Branch 0 taken 3259754 times.
✓ Branch 1 taken 2170 times.
3261924 for (unsigned i = 0; i < max_open_fds; ++i) {
38 3259754 fd_index_[i] = i;
39 3259754 open_fds_[i].index = i;
40 }
41 2170 }
42
43 /**
44 * Used to restore the state.
45 */
46 78 void AssignFrom(const FdTable<HandleT> &other) {
47 78 invalid_handle_ = other.invalid_handle_;
48 78 fd_pivot_ = other.fd_pivot_;
49 78 fd_index_.resize(other.fd_index_.size());
50
1/5
✗ Branch 2 not taken.
✓ Branch 3 taken 78 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
78 open_fds_.resize(other.open_fds_.size(), FdWrapper(invalid_handle_, 0));
51
2/2
✓ Branch 1 taken 9984 times.
✓ Branch 2 taken 78 times.
10062 for (unsigned i = 0; i < fd_index_.size(); ++i) {
52 9984 fd_index_[i] = other.fd_index_[i];
53 9984 open_fds_[i] = other.open_fds_[i];
54 }
55 78 }
56
57 /**
58 * Used to save the state.
59 */
60 78 FdTable<HandleT> *Clone() {
61 78 FdTable<HandleT> *result = new FdTable<HandleT>(open_fds_.size(),
62
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 invalid_handle_);
63 78 result->fd_pivot_ = fd_pivot_;
64
2/2
✓ Branch 1 taken 9984 times.
✓ Branch 2 taken 78 times.
10062 for (unsigned i = 0; i < fd_index_.size(); ++i) {
65 9984 result->fd_index_[i] = fd_index_[i];
66 9984 result->open_fds_[i] = open_fds_[i];
67 }
68 78 return result;
69 }
70
71
72 /**
73 * Registers fd with a currently unused number. If the table is full,
74 * returns -ENFILE;
75 */
76 25026017 int OpenFd(const HandleT &handle) {
77
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 24473687 times.
✓ Branch 2 taken 552330 times.
25026017 if (handle == invalid_handle_)
78 return -EINVAL;
79
2/2
✓ Branch 1 taken 4047772 times.
✓ Branch 2 taken 20978245 times.
25026017 if (fd_pivot_ >= fd_index_.size())
80 4047772 return -ENFILE;
81
82 20978245 size_t const next_fd = fd_index_[fd_pivot_];
83
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20978245 times.
20978245 assert(next_fd < open_fds_.size());
84
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 20426042 times.
✓ Branch 3 taken 552203 times.
20978245 assert(open_fds_[next_fd].handle == invalid_handle_);
85
1/2
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
20978245 open_fds_[next_fd] = FdWrapper(handle, fd_pivot_);
86 20978245 ++fd_pivot_;
87 20978245 return next_fd;
88 }
89
90 /**
91 * For invalid and unused numbers, the invalid handle is returned.
92 */
93 25636273 HandleT GetHandle(int fd) {
94
2/2
✓ Branch 1 taken 21524755 times.
✓ Branch 2 taken 4111479 times.
25636273 return IsValid(fd) ? open_fds_[fd].handle : invalid_handle_;
95 }
96
97
98 /**
99 * Releases fd back to the set of available numbers. Gracefully handles
100 * invalid handles (-EBADFD)
101 */
102 25078859 int CloseFd(int fd) {
103
2/2
✓ Branch 1 taken 4101251 times.
✓ Branch 2 taken 20977608 times.
25078859 if (!IsValid(fd))
104 4101251 return -EBADF;
105
106 20977608 unsigned const index = open_fds_[fd].index;
107
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20977608 times.
20977608 assert(index < fd_index_.size());
108
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20977608 times.
20977608 assert(fd_pivot_ <= fd_index_.size());
109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20977608 times.
20977608 assert(fd_pivot_ > 0);
110 20977608 open_fds_[fd].handle = invalid_handle_;
111 20977608 --fd_pivot_;
112
2/2
✓ Branch 0 taken 11619533 times.
✓ Branch 1 taken 9358075 times.
20977608 if (index < fd_pivot_) {
113 11619533 unsigned const other = fd_index_[fd_pivot_];
114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 11619533 times.
11619533 assert(other < open_fds_.size());
115
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 11075176 times.
✓ Branch 3 taken 544357 times.
11619533 assert(open_fds_[other].handle != invalid_handle_);
116 11619533 open_fds_[other].index = index;
117 11619533 fd_index_[index] = other;
118 11619533 fd_index_[fd_pivot_] = fd;
119 }
120 20977608 return 0;
121 }
122
123 9984 unsigned GetMaxFds() const { return fd_index_.size(); }
124
125 private:
126 struct FdWrapper {
127 20980493 FdWrapper(HandleT h, unsigned i) : handle(h), index(i) { }
128
129 HandleT handle;
130 /**
131 * Back-pointer into fd_index_, which is needed when closing a file.
132 */
133 unsigned index;
134 };
135
136
137 50715132 inline bool IsValid(int fd) {
138
6/6
✓ Branch 0 taken 50715034 times.
✓ Branch 1 taken 98 times.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 50714936 times.
✓ Branch 5 taken 196 times.
✓ Branch 6 taken 50714936 times.
50715132 if ((fd < 0) || (static_cast<unsigned>(fd) >= open_fds_.size()))
139 196 return false;
140 50714936 return open_fds_[fd].handle != invalid_handle_;
141 }
142
143 /**
144 * An unused (available) file descriptor.
145 */
146 HandleT invalid_handle_;
147 /**
148 * The index of the first available file descriptor in fd_index_.
149 */
150 unsigned fd_pivot_;
151 /**
152 * Maps into open_fds_. Until fd_pivot_, file descriptors are used. As of
153 * fd_pivot_, points to free file descriptors. Used to acquire new file
154 * descriptors in constant time.
155 */
156 std::vector<unsigned> fd_index_;
157 /**
158 * The file descriptor number mapped to a user-defined file descriptor
159 * (struct). The fd integer passed to users of the file descriptor table
160 * points into this array.
161 */
162 std::vector<FdWrapper> open_fds_;
163 }; // class FdTable
164
165 #endif // CVMFS_FD_TABLE_H_
166