Joedb 9.5.0
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Buffered_File.h
Go to the documentation of this file.
1#ifndef joedb_Buffered_File_declared
2#define joedb_Buffered_File_declared
3
6#include "joedb/Blob.h"
10#include "joedb/index_types.h"
11
12#include <string>
13
14namespace joedb
15{
16 /// @ingroup journal
18 {
19 friend class File_Hasher;
20
21 private:
22 Buffer<12> buffer;
23
24 size_t read_buffer_size;
25
26 //////////////////////////////////////////////////////////////////////////
27 bool buffer_has_write_data() const noexcept
28 //////////////////////////////////////////////////////////////////////////
29 {
30 return buffer.index > 0 && !read_buffer_size;
31 }
32
33 //////////////////////////////////////////////////////////////////////////
34 bool buffer_has_read_data() const
35 //////////////////////////////////////////////////////////////////////////
36 {
37 return read_buffer_size;
38 }
39
40 //////////////////////////////////////////////////////////////////////////
41 void read_buffer()
42 //////////////////////////////////////////////////////////////////////////
43 {
44 JOEDB_DEBUG_ASSERT(!buffer_has_write_data());
45 JOEDB_DEBUG_ASSERT(buffer.index <= read_buffer_size);
46
47 buffer.index = 0;
48 read_buffer_size = sequential_read(buffer.data, buffer.size);
49 if (read_buffer_size == 0)
51 }
52
53 //////////////////////////////////////////////////////////////////////////
54 void write_buffer()
55 //////////////////////////////////////////////////////////////////////////
56 {
57 JOEDB_DEBUG_ASSERT(!buffer_has_read_data());
58
59 sequential_write(buffer.data, buffer.index);
60 buffer.index = 0;
61 }
62
63 //////////////////////////////////////////////////////////////////////////
64 void check_write_buffer()
65 //////////////////////////////////////////////////////////////////////////
66 {
67 JOEDB_DEBUG_ASSERT(!buffer_has_read_data());
68
69 if (buffer.index >= buffer.size)
70 write_buffer();
71 }
72
73 Open_Mode mode;
74 bool locked_tail;
75
76 protected:
77 void destructor_flush() noexcept;
80
81 public:
83 void flush();
84 void flush_for_writing();
85
86 static constexpr int64_t last_position = (1ULL << 63) - 1;
87
89 {
91 locked_tail = true;
92 }
93
94 void unlock_tail() noexcept
95 {
97 locked_tail = false;
98 }
99
100 bool tail_is_locked() const noexcept {return locked_tail;}
103 void unlock_head() noexcept {unlock(0, 1);}
104
106 {
107 private:
108 Buffered_File &file;
109 public:
111 {
112 file.shared_lock_head();
113 }
115 {
116 file.unlock_head();
117 }
118 };
119
121 {
122 private:
123 Buffered_File &file;
124 public:
126 {
127 file.exclusive_lock_head();
128 }
130 {
131 file.unlock_head();
132 }
133 };
134
135 bool is_shared() const noexcept {return mode == Open_Mode::shared_write;}
136 bool is_readonly() const noexcept {return mode == Open_Mode::read_existing;}
137
138 // set_position must be called when switching between write and read
139 void set_position(int64_t position);
140
141 int64_t get_position() const noexcept
142 {
143 return Sequential_File::get_position() - read_buffer_size + buffer.index;
144 }
145
146 //////////////////////////////////////////////////////////////////////////
148 //////////////////////////////////////////////////////////////////////////
149 {
150 throw Exception("Trying to read past the end of file");
151 }
152
153 //////////////////////////////////////////////////////////////////////////
154 virtual void copy_to
155 //////////////////////////////////////////////////////////////////////////
156 (
157 Buffered_File &destination,
158 int64_t start,
159 int64_t size
160 ) const;
161
162 //////////////////////////////////////////////////////////////////////////
163 virtual bool equal_to
164 //////////////////////////////////////////////////////////////////////////
165 (
166 Buffered_File &destination,
167 int64_t from,
168 int64_t until
169 ) const;
170
171 //////////////////////////////////////////////////////////////////////////
172 void copy_to(Buffered_File &destination) const
173 //////////////////////////////////////////////////////////////////////////
174 {
175 copy_to(destination, 0, get_size());
176 }
177
178 //////////////////////////////////////////////////////////////////////////
179 template<typename T> void write(T x)
180 //////////////////////////////////////////////////////////////////////////
181 {
182 static_assert(sizeof(T) <= decltype(buffer)::extra_size);
183 buffer.write<T>(x);
184 check_write_buffer();
185 }
186
187 //////////////////////////////////////////////////////////////////////////
188 template<typename T> T read()
189 //////////////////////////////////////////////////////////////////////////
190 {
191 T result;
192 read_data(reinterpret_cast<char *>(&result), sizeof(result));
193 return result;
194 }
195
196 //////////////////////////////////////////////////////////////////////////
197 template<typename T> void compact_write(T x)
198 //////////////////////////////////////////////////////////////////////////
199 {
200 buffer.compact_write<T>(x);
201 check_write_buffer();
202 }
203
204 //////////////////////////////////////////////////////////////////////////
205 template<typename T> T compact_read()
206 //////////////////////////////////////////////////////////////////////////
207 {
208 if (buffer.index + 8 <= read_buffer_size)
209 return buffer.compact_read<T>();
210
211 const uint8_t first_byte = read<uint8_t>();
212 int extra_bytes = first_byte >> 5;
213 T result = first_byte & 0x1f;
214 while (--extra_bytes >= 0)
215 result = T((result << 8) | read<uint8_t>());
216 return result;
217 }
218
219 template<typename T> T read_strong_type()
220 {
221 return T(compact_read<typename std::underlying_type<T>::type>());
222 }
223
225 {
227 }
228
230 {
231 return Record_Id(compact_read<std::underlying_type<Record_Id>::type>());
232 }
233
234 void write_string(const std::string &s);
235 std::string read_string();
236 std::string safe_read_string(int64_t max_size);
237
238 void write_blob(Blob blob)
239 {
240 compact_write<int64_t>(blob.get_position());
241 compact_write<int64_t>(blob.get_size());
242 }
243
245 {
246 const int64_t position = compact_read<int64_t>();
247 const int64_t size = compact_read<int64_t>();
248 return Blob(position, size);
249 }
250
251 //////////////////////////////////////////////////////////////////////////
252 void write_data(const char *data, size_t n)
253 //////////////////////////////////////////////////////////////////////////
254 {
255 JOEDB_DEBUG_ASSERT(!buffer_has_read_data());
256
257 if (n <= buffer.extra_size)
258 {
259 std::memcpy(buffer.data + buffer.index, data, n);
260 buffer.index += n;
261 check_write_buffer();
262 }
263 else
264 {
265 const size_t remaining = buffer.size + buffer.extra_size - buffer.index;
266
267 if (n < remaining)
268 {
269 std::memcpy(buffer.data + buffer.index, data, n);
270 buffer.index += n;
271 check_write_buffer();
272 }
273 else
274 {
275 flush();
276 sequential_write(data, n);
277 }
278 }
279 }
280
281 //////////////////////////////////////////////////////////////////////////
282 size_t read_data(char *data, const size_t n)
283 //////////////////////////////////////////////////////////////////////////
284 {
285 JOEDB_DEBUG_ASSERT(!buffer_has_write_data());
286 JOEDB_DEBUG_ASSERT(buffer.index <= read_buffer_size);
287
288 if (buffer.index + n <= read_buffer_size)
289 {
290 std::memcpy(data, buffer.data + buffer.index, n);
291 buffer.index += n;
292 return n;
293 }
294 else
295 {
296 size_t n0 = read_buffer_size - buffer.index;
297 std::memcpy(data, buffer.data + buffer.index, n0);
298 buffer.index += n0;
299
300 if (n <= buffer.size)
301 {
302 read_buffer();
303
304 while (n0 < n && buffer.index < read_buffer_size)
305 data[n0++] = buffer.data[buffer.index++];
306 }
307
308 while (n0 < n)
309 {
310 const size_t actually_read = sequential_read(data + n0, n - n0);
311 if (actually_read == 0)
312 {
314 break;
315 }
316 n0 += actually_read;
317 }
318
319 return n0;
320 }
321 }
322
323 //////////////////////////////////////////////////////////////////////////
324 void ignore(const int64_t n)
325 //////////////////////////////////////////////////////////////////////////
326 {
327 if (buffer.index + n <= read_buffer_size)
328 buffer.index += n;
329 else
331 }
332
333 std::string read_blob(Blob blob) const;
334 };
335}
336
337#endif
virtual void shared_lock(int64_t start, int64_t size)
Lock a range of bytes for reading (prevents writes, not reads)
virtual int64_t get_size() const
Get the size of the file, or -1 if it is unknown.
virtual void unlock(int64_t start, int64_t size) noexcept
Remove a lock. The range should match the range of a corresponding lock.
virtual void exclusive_lock(int64_t start, int64_t size)
Lock a range of bytes for writing (prevents both writes and reads)
int64_t get_position() const noexcept
Definition Blob.h:29
int64_t get_size() const noexcept
Definition Blob.h:30
T compact_read()
Definition Buffer.h:69
size_t index
Definition Buffer.h:20
void write(T x)
Definition Buffer.h:23
static constexpr size_t extra_size
Definition Buffer.h:17
char data[size+extra_size]
Definition Buffer.h:19
static constexpr size_t size
Definition Buffer.h:15
void compact_write(T x)
Definition Buffer.h:43
void ignore(const int64_t n)
void write_reference(Record_Id id)
void write_blob(Blob blob)
virtual void copy_to(Buffered_File &destination, int64_t start, int64_t size) const
void set_position(int64_t position)
bool is_shared() const noexcept
virtual bool equal_to(Buffered_File &destination, int64_t from, int64_t until) const
void unlock_head() noexcept
bool tail_is_locked() const noexcept
static constexpr int64_t last_position
size_t read_data(char *data, const size_t n)
void write_string(const std::string &s)
static void reading_past_end_of_file()
void copy_to(Buffered_File &destination) const
bool is_readonly() const noexcept
void unlock_tail() noexcept
std::string read_string()
void destructor_flush() noexcept
void write_data(const char *data, size_t n)
Record_Id read_reference()
std::string safe_read_string(int64_t max_size)
int64_t get_position() const noexcept
size_t sequential_read(char *data, size_t size)
void sequential_write(const char *data, size_t size)
int64_t get_position() const
#define JOEDB_DEBUG_ASSERT(x)
Definition assert.h:20
Open_Mode
Definition Open_Mode.h:8
@ write_existing
fails if does not exist or locked, locks the file for writing
@ shared_write
like write_existing_or_create_new, but does not lock the file, and does not fail if locked
@ read_existing
fails if does not exist
Definition Blob.h:7
constexpr std::underlying_type< Table_Id >::type to_underlying(Table_Id id)
Definition index_types.h:21