GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/fd_table.h
Date: 2024-04-21 02:33:16
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 78 FdTable(
31 unsigned max_open_fds,
32 const HandleT &invalid_handle)
33 78 : invalid_handle_(invalid_handle)
34 78 , fd_pivot_(0)
35
1/2
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
78 , fd_index_(max_open_fds)
36
4/7
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 77 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
156 , open_fds_(max_open_fds, FdWrapper(invalid_handle_, 0))
37 {
38
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 assert(max_open_fds > 0);
39
2/2
✓ Branch 0 taken 92970 times.
✓ Branch 1 taken 78 times.
93048 for (unsigned i = 0; i < max_open_fds; ++i) {
40 92970 fd_index_[i] = i;
41 92970 open_fds_[i].index = i;
42 }
43 78 }
44
45 /**
46 * Used to restore the state.
47 */
48 2 void AssignFrom(const FdTable<HandleT> &other) {
49 2 invalid_handle_ = other.invalid_handle_;
50 2 fd_pivot_ = other.fd_pivot_;
51 2 fd_index_.resize(other.fd_index_.size());
52
1/5
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
2 open_fds_.resize(other.open_fds_.size(), FdWrapper(invalid_handle_, 0));
53
2/2
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 2 times.
258 for (unsigned i = 0; i < fd_index_.size(); ++i) {
54 256 fd_index_[i] = other.fd_index_[i];
55 256 open_fds_[i] = other.open_fds_[i];
56 }
57 2 }
58
59 /**
60 * Used to save the state.
61 */
62 2 FdTable<HandleT> *Clone() {
63 4 FdTable<HandleT> *result =
64
1/2
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
2 new FdTable<HandleT>(open_fds_.size(), invalid_handle_);
65 2 result->fd_pivot_ = fd_pivot_;
66
2/2
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 2 times.
258 for (unsigned i = 0; i < fd_index_.size(); ++i) {
67 256 result->fd_index_[i] = fd_index_[i];
68 256 result->open_fds_[i] = open_fds_[i];
69 }
70 2 return result;
71 }
72
73
74 /**
75 * Registers fd with a currently unused number. If the table is full,
76 * returns -ENFILE;
77 */
78 511687 int OpenFd(const HandleT &handle) {
79
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 500119 times.
✓ Branch 2 taken 11568 times.
511687 if (handle == invalid_handle_)
80 return -EINVAL;
81
2/2
✓ Branch 1 taken 83381 times.
✓ Branch 2 taken 428306 times.
511687 if (fd_pivot_ >= fd_index_.size())
82 83381 return -ENFILE;
83
84 428306 size_t next_fd = fd_index_[fd_pivot_];
85
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428306 times.
428306 assert(next_fd < open_fds_.size());
86
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 416741 times.
✓ Branch 3 taken 11565 times.
428306 assert(open_fds_[next_fd].handle == invalid_handle_);
87
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
428306 open_fds_[next_fd] = FdWrapper(handle, fd_pivot_);
88 428306 ++fd_pivot_;
89 428306 return next_fd;
90 }
91
92 /**
93 * For invalid and unused numbers, the invalid handle is returned.
94 */
95 523151 HandleT GetHandle(int fd) {
96
2/2
✓ Branch 1 taken 439726 times.
✓ Branch 2 taken 83424 times.
523151 return IsValid(fd) ? open_fds_[fd].handle : invalid_handle_;
97 }
98
99
100 /**
101 * Releases fd back to the set of available numbers. Gracefully handles
102 * invalid handles (-EBADFD)
103 */
104 511453 int CloseFd(int fd) {
105
2/2
✓ Branch 1 taken 83162 times.
✓ Branch 2 taken 428291 times.
511453 if (!IsValid(fd))
106 83162 return -EBADF;
107
108 428291 unsigned index = open_fds_[fd].index;
109
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428291 times.
428291 assert(index < fd_index_.size());
110
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 428291 times.
428291 assert(fd_pivot_ <= fd_index_.size());
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 428291 times.
428291 assert(fd_pivot_ > 0);
112 428291 open_fds_[fd].handle = invalid_handle_;
113 428291 --fd_pivot_;
114
2/2
✓ Branch 0 taken 237955 times.
✓ Branch 1 taken 190336 times.
428291 if (index < fd_pivot_) {
115 237955 unsigned other = fd_index_[fd_pivot_];
116
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 237955 times.
237955 assert(other < open_fds_.size());
117
2/3
✗ Branch 1 not taken.
✓ Branch 2 taken 226710 times.
✓ Branch 3 taken 11245 times.
237955 assert(open_fds_[other].handle != invalid_handle_);
118 237955 open_fds_[other].index = index;
119 237955 fd_index_[index] = other;
120 237955 fd_index_[fd_pivot_] = fd;
121 }
122 428291 return 0;
123 }
124
125 256 unsigned GetMaxFds() const { return fd_index_.size(); }
126
127 private:
128 struct FdWrapper {
129 428386 FdWrapper(HandleT h, unsigned i) : handle(h), index(i) { }
130
131 HandleT handle;
132 /**
133 * Back-pointer into fd_index_, which is needed when closing a file.
134 */
135 unsigned index;
136 };
137
138
139 1034604 inline bool IsValid(int fd) {
140
6/6
✓ Branch 0 taken 1034602 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1034599 times.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1034599 times.
1034604 if ((fd < 0) || (static_cast<unsigned>(fd) >= open_fds_.size()))
141 4 return false;
142 1034599 return open_fds_[fd].handle != invalid_handle_;
143 }
144
145 /**
146 * An unused (available) file descriptor.
147 */
148 HandleT invalid_handle_;
149 /**
150 * The index of the first available file descriptor in fd_index_.
151 */
152 unsigned fd_pivot_;
153 /**
154 * Maps into open_fds_. Until fd_pivot_, file descriptors are used. As of
155 * fd_pivot_, points to free file descriptors. Used to acquire new file
156 * descriptors in constant time.
157 */
158 std::vector<unsigned> fd_index_;
159 /**
160 * The file descriptor number mapped to a user-defined file descriptor
161 * (struct). The fd integer passed to users of the file descriptor table
162 * points into this array.
163 */
164 std::vector<FdWrapper> open_fds_;
165 }; // class FdTable
166
167 #endif // CVMFS_FD_TABLE_H_
168