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 |
|
93 |
class FdTable : SingleCopy { |
29 |
|
|
public: |
30 |
|
95 |
FdTable( |
31 |
|
|
unsigned max_open_fds, |
32 |
|
|
const HandleT &invalid_handle) |
33 |
|
|
: invalid_handle_(invalid_handle) |
34 |
|
|
, fd_pivot_(0) |
35 |
|
|
, fd_index_(max_open_fds) |
36 |
|
95 |
, open_fds_(max_open_fds, FdWrapper(invalid_handle_, 0)) |
37 |
|
|
{ |
38 |
✗✓ |
95 |
assert(max_open_fds > 0); |
39 |
✓✓ |
248307 |
for (unsigned i = 0; i < max_open_fds; ++i) { |
40 |
|
248212 |
fd_index_[i] = i; |
41 |
|
248212 |
open_fds_[i].index = i; |
42 |
|
|
} |
43 |
|
95 |
} |
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 |
|
2 |
open_fds_.resize(other.open_fds_.size(), FdWrapper(invalid_handle_, 0)); |
53 |
✓✓ |
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 |
|
|
FdTable<HandleT> *result = |
64 |
|
2 |
new FdTable<HandleT>(open_fds_.size(), invalid_handle_); |
65 |
|
2 |
result->fd_pivot_ = fd_pivot_; |
66 |
✓✓ |
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 |
|
|
* Registeres fd with a currently unused number. If the table is full, |
76 |
|
|
* returns -ENFILE; |
77 |
|
|
*/ |
78 |
|
1011477 |
int OpenFd(const HandleT &handle) { |
79 |
✗✓✓ |
1011477 |
if (handle == invalid_handle_) |
80 |
|
|
return -EINVAL; |
81 |
✓✓ |
1011477 |
if (fd_pivot_ >= fd_index_.size()) |
82 |
|
167665 |
return -ENFILE; |
83 |
|
|
|
84 |
|
843812 |
size_t next_fd = fd_index_[fd_pivot_]; |
85 |
✗✓ |
843812 |
assert(next_fd < open_fds_.size()); |
86 |
✗✓✓ |
843812 |
assert(open_fds_[next_fd].handle == invalid_handle_); |
87 |
|
843812 |
open_fds_[next_fd] = FdWrapper(handle, fd_pivot_); |
88 |
|
843812 |
++fd_pivot_; |
89 |
|
843812 |
return next_fd; |
90 |
|
|
} |
91 |
|
|
|
92 |
|
|
/** |
93 |
|
|
* For invalid and unused numbers, the invalid handle is returned. |
94 |
|
|
*/ |
95 |
|
1023129 |
HandleT GetHandle(int fd) { |
96 |
✓✓ |
1023129 |
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 |
|
1011674 |
int CloseFd(int fd) { |
105 |
✓✓ |
1011674 |
if (!IsValid(fd)) |
106 |
|
167888 |
return -EBADF; |
107 |
|
|
|
108 |
|
843786 |
unsigned index = open_fds_[fd].index; |
109 |
✗✓ |
843786 |
assert(index < fd_index_.size()); |
110 |
✗✓ |
843786 |
assert(fd_pivot_ <= fd_index_.size()); |
111 |
✗✓ |
843786 |
assert(fd_pivot_ > 0); |
112 |
✗✓ |
843786 |
open_fds_[fd].handle = invalid_handle_; |
113 |
|
843786 |
--fd_pivot_; |
114 |
✓✓ |
843786 |
if (index < fd_pivot_) { |
115 |
|
461878 |
unsigned other = fd_index_[fd_pivot_]; |
116 |
✗✓ |
461878 |
assert(other < open_fds_.size()); |
117 |
✗✓✓ |
461878 |
assert(open_fds_[other].handle != invalid_handle_); |
118 |
|
461878 |
open_fds_[other].index = index; |
119 |
|
461878 |
fd_index_[index] = other; |
120 |
|
461878 |
fd_index_[fd_pivot_] = fd; |
121 |
|
|
} |
122 |
|
843786 |
return 0; |
123 |
|
|
} |
124 |
|
|
|
125 |
|
|
private: |
126 |
|
|
struct FdWrapper { |
127 |
|
843909 |
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 |
|
2034803 |
inline bool IsValid(int fd) { |
138 |
✓✓✓✓ ✓✓ |
2034803 |
if ((fd < 0) || (static_cast<unsigned>(fd) >= open_fds_.size())) |
139 |
|
8 |
return false; |
140 |
|
2034795 |
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_ |