GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/fd_table.h
Date: 2026-03-01 02:36:14
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 <vector>
14
15 #include "util/single_copy.h"
16
17 /**
18 * Maintains integers mapped to custom open file descriptors. File descriptors
19 * can be added, removed, and accessed. All operations take constant time. The
20 * maximum file descriptor number needs to be known upfront.
21 *
22 * Note that new file descriptors do not necessarily have the smallest available
23 * number but any number between 0..max_open_fds.
24 *
25 * This class is used by a couple of cache managers.
26 */
27 template<class HandleT>
28 class FdTable : SingleCopy {
29 public:
30 1269 FdTable(unsigned max_open_fds, const HandleT &invalid_handle)
31 1269 : invalid_handle_(invalid_handle)
32 1269 , fd_pivot_(0)
33
1/2
✓ Branch 2 taken 1269 times.
✗ Branch 3 not taken.
1269 , fd_index_(max_open_fds)
34
4/7
✓ Branch 3 taken 80 times.
✓ Branch 4 taken 1189 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 80 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 80 times.
✗ Branch 10 not taken.
2538 , open_fds_(max_open_fds, FdWrapper(invalid_handle_, 0)) {
35
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1269 times.
1269 assert(max_open_fds > 0);
36
2/2
✓ Branch 0 taken 1727652 times.
✓ Branch 1 taken 1269 times.
1728921 for (unsigned i = 0; i < max_open_fds; ++i) {
37 1727652 fd_index_[i] = i;
38 1727652 open_fds_[i].index = i;
39 }
40 1269 }
41
42 /**
43 * Used to restore the state.
44 */
45 36 void AssignFrom(const FdTable<HandleT> &other) {
46 36 invalid_handle_ = other.invalid_handle_;
47 36 fd_pivot_ = other.fd_pivot_;
48 36 fd_index_.resize(other.fd_index_.size());
49
1/5
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
36 open_fds_.resize(other.open_fds_.size(), FdWrapper(invalid_handle_, 0));
50
2/2
✓ Branch 1 taken 4608 times.
✓ Branch 2 taken 36 times.
4644 for (unsigned i = 0; i < fd_index_.size(); ++i) {
51 4608 fd_index_[i] = other.fd_index_[i];
52 4608 open_fds_[i] = other.open_fds_[i];
53 }
54 36 }
55
56 /**
57 * Used to save the state.
58 */
59 36 FdTable<HandleT> *Clone() {
60 36 FdTable<HandleT> *result = new FdTable<HandleT>(open_fds_.size(),
61
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 invalid_handle_);
62 36 result->fd_pivot_ = fd_pivot_;
63
2/2
✓ Branch 1 taken 4608 times.
✓ Branch 2 taken 36 times.
4644 for (unsigned i = 0; i < fd_index_.size(); ++i) {
64 4608 result->fd_index_[i] = fd_index_[i];
65 4608 result->open_fds_[i] = open_fds_[i];
66 }
67 36 return result;
68 }
69
70
71 /**
72 * Registers fd with a currently unused number. If the table is full,
73 * returns -ENFILE;
74 */
75 21241402 int OpenFd(const HandleT &handle) {
76
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 21026040 times.
✓ Branch 2 taken 215362 times.
21241402 if (handle == invalid_handle_)
77 return -EINVAL;
78
2/2
✓ Branch 1 taken 3527047 times.
✓ Branch 2 taken 17714355 times.
21241402 if (fd_pivot_ >= fd_index_.size())
79 3527047 return -ENFILE;
80
81 17714355 size_t next_fd = fd_index_[fd_pivot_];
82
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17714355 times.
17714355 assert(next_fd < open_fds_.size());
83
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 17499048 times.
✓ Branch 3 taken 215307 times.
17714355 assert(open_fds_[next_fd].handle == invalid_handle_);
84
1/2
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
17714355 open_fds_[next_fd] = FdWrapper(handle, fd_pivot_);
85 17714355 ++fd_pivot_;
86 17714355 return next_fd;
87 }
88
89 /**
90 * For invalid and unused numbers, the invalid handle is returned.
91 */
92 21407480 HandleT GetHandle(int fd) {
93
2/2
✓ Branch 1 taken 17926969 times.
✓ Branch 2 taken 3480511 times.
21407480 return IsValid(fd) ? open_fds_[fd].handle : invalid_handle_;
94 }
95
96
97 /**
98 * Releases fd back to the set of available numbers. Gracefully handles
99 * invalid handles (-EBADFD)
100 */
101 21189699 int CloseFd(int fd) {
102
2/2
✓ Branch 1 taken 3475794 times.
✓ Branch 2 taken 17713905 times.
21189699 if (!IsValid(fd))
103 3475794 return -EBADF;
104
105 17713905 unsigned index = open_fds_[fd].index;
106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17713905 times.
17713905 assert(index < fd_index_.size());
107
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17713905 times.
17713905 assert(fd_pivot_ <= fd_index_.size());
108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17713905 times.
17713905 assert(fd_pivot_ > 0);
109 17713905 open_fds_[fd].handle = invalid_handle_;
110 17713905 --fd_pivot_;
111
2/2
✓ Branch 0 taken 9720635 times.
✓ Branch 1 taken 7993270 times.
17713905 if (index < fd_pivot_) {
112 9720635 unsigned other = fd_index_[fd_pivot_];
113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9720635 times.
9720635 assert(other < open_fds_.size());
114
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 9508968 times.
✓ Branch 3 taken 211667 times.
9720635 assert(open_fds_[other].handle != invalid_handle_);
115 9720635 open_fds_[other].index = index;
116 9720635 fd_index_[index] = other;
117 9720635 fd_index_[fd_pivot_] = fd;
118 }
119 17713905 return 0;
120 }
121
122 4608 unsigned GetMaxFds() const { return fd_index_.size(); }
123
124 private:
125 struct FdWrapper {
126 17715660 FdWrapper(HandleT h, unsigned i) : handle(h), index(i) { }
127
128 HandleT handle;
129 /**
130 * Back-pointer into fd_index_, which is needed when closing a file.
131 */
132 unsigned index;
133 };
134
135
136 42597179 inline bool IsValid(int fd) {
137
6/6
✓ Branch 0 taken 42597095 times.
✓ Branch 1 taken 84 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 42597011 times.
✓ Branch 5 taken 168 times.
✓ Branch 6 taken 42597011 times.
42597179 if ((fd < 0) || (static_cast<unsigned>(fd) >= open_fds_.size()))
138 168 return false;
139 42597011 return open_fds_[fd].handle != invalid_handle_;
140 }
141
142 /**
143 * An unused (available) file descriptor.
144 */
145 HandleT invalid_handle_;
146 /**
147 * The index of the first available file descriptor in fd_index_.
148 */
149 unsigned fd_pivot_;
150 /**
151 * Maps into open_fds_. Until fd_pivot_, file descriptors are used. As of
152 * fd_pivot_, points to free file descriptors. Used to acquire new file
153 * descriptors in constant time.
154 */
155 std::vector<unsigned> fd_index_;
156 /**
157 * The file descriptor number mapped to a user-defined file descriptor
158 * (struct). The fd integer passed to users of the file descriptor table
159 * points into this array.
160 */
161 std::vector<FdWrapper> open_fds_;
162 }; // class FdTable
163
164 #endif // CVMFS_FD_TABLE_H_
165