Joedb 9.1.4
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Posix_File.cpp
Go to the documentation of this file.
3
4#include <sys/file.h>
5#include <sys/types.h>
6#include <sys/stat.h>
7#include <fcntl.h>
8#include <unistd.h>
9#include <errno.h>
10#include <string.h>
11
12#ifdef JOEDB_HAS_BROKEN_POSIX_LOCKING
13#define JOEDB_SETLK F_SETLK
14#define JOEDB_SETLKW F_SETLKW
15//#warning is C++23
16//#warning Joedb is using old-style POSIX locks. File locking is broken if you open the same file more than once within the same process. New OFD locks work better and should be enabled if your system supports them.
17#else
18#define JOEDB_SETLK F_OFD_SETLK
19#define JOEDB_SETLKW F_OFD_SETLKW
20#endif
21
22namespace joedb
23{
24#ifndef _FILE_OFFSET_BITS
25 static_assert
26 (
27 sizeof(off_t) == sizeof(int64_t),
28 "Define the _FILE_OFFSET_BITS macro to 32 or 64 to silence this error. 64 is recommended if possible. Joedb does not check for file-size overflow."
29 );
30#endif
31
32 /////////////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////////////
35 (
36 const char *action,
37 const char *file_name
38 )
39 {
40 throw Exception
41 (
42 std::string(action) + ' ' + file_name + ": " + strerror(errno)
43 );
44 }
45
46 /////////////////////////////////////////////////////////////////////////////
47 // NOLINTNEXTLINE(readability-make-member-function-const)
48 int Posix_FD::lock(int command, short type, int64_t start, int64_t size)
49 /////////////////////////////////////////////////////////////////////////////
50 {
51 struct flock lock;
52 lock.l_type = type;
53 lock.l_whence = SEEK_SET;
54 lock.l_start = off_t(start);
55 lock.l_len = off_t(size);
56 lock.l_pid = 0;
57
58 return fcntl(fd, command, &lock);
59 }
60
61 /////////////////////////////////////////////////////////////////////////////
62 bool Posix_FD::try_exclusive_lock(int64_t start, int64_t size)
63 /////////////////////////////////////////////////////////////////////////////
64 {
65 return lock(JOEDB_SETLK, F_WRLCK, start, size) == 0;
66 }
67
68 /////////////////////////////////////////////////////////////////////////////
69 void Posix_FD::shared_lock(int64_t start, int64_t size)
70 /////////////////////////////////////////////////////////////////////////////
71 {
72 if (lock(JOEDB_SETLKW, F_RDLCK, start, size) < 0)
73 throw_last_error("Read-locking", "file");
74 }
75
76 /////////////////////////////////////////////////////////////////////////////
77 void Posix_FD::exclusive_lock(int64_t start, int64_t size)
78 /////////////////////////////////////////////////////////////////////////////
79 {
80 if (lock(JOEDB_SETLKW, F_WRLCK, start, size) < 0)
81 throw_last_error("Write-locking", "file");
82 }
83
84 /////////////////////////////////////////////////////////////////////////////
85 void Posix_FD::unlock(int64_t start, int64_t size) noexcept
86 /////////////////////////////////////////////////////////////////////////////
87 {
88 lock(JOEDB_SETLK, F_UNLCK, start, size);
89 }
90
91 /////////////////////////////////////////////////////////////////////////////
92 size_t Posix_FD::pread(char *buffer, size_t size, int64_t offset) const
93 /////////////////////////////////////////////////////////////////////////////
94 {
95 const ssize_t result = ::pread(fd, buffer, size, offset);
96
97 if (result < 0)
98 throw_last_error("Reading", "file");
99
100 return size_t(result);
101 }
102
103 /////////////////////////////////////////////////////////////////////////////
104 void Posix_FD::pwrite(const char *buffer, size_t size, int64_t offset)
105 /////////////////////////////////////////////////////////////////////////////
106 {
107 size_t written = 0;
108
109 while (written < size)
110 {
111 const ssize_t result = ::pwrite
112 (
113 fd,
114 buffer + written,
115 size - written,
116 offset + written
117 );
118
119 if (result < 0)
120 throw_last_error("Writing", "file");
121 else
123 }
124 }
125
126 /////////////////////////////////////////////////////////////////////////////
128 /////////////////////////////////////////////////////////////////////////////
129 {
130#ifdef __APPLE__
131 if (fcntl(fd, F_FULLFSYNC) == -1)
132#else
133 if (fsync(fd) == -1)
134#endif
135 {
136 throw_last_error("syncing", "file");
137 }
138 }
139
140 /////////////////////////////////////////////////////////////////////////////
141 Posix_FD::Posix_FD(const char *file_name, const Open_Mode mode):
142 /////////////////////////////////////////////////////////////////////////////
143 Buffered_File(mode)
144 {
145 if (mode == Open_Mode::read_existing)
146 fd = open(file_name, O_RDONLY);
147 else if (mode == Open_Mode::write_existing)
148 fd = open(file_name, O_RDWR);
149 else if (mode == Open_Mode::create_new)
150 fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, 00644);
151 else if
152 (
154 mode == Open_Mode::shared_write ||
156 )
157 {
158 fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, 00644);
159 if (fd < 0)
160 fd = open(file_name, O_RDWR);
161 }
162
163 if (fd < 0)
164 throw_last_error("Opening", file_name);
165 }
166
167 /////////////////////////////////////////////////////////////////////////////
168 Posix_File::Posix_File(const char *file_name, const Open_Mode mode):
169 /////////////////////////////////////////////////////////////////////////////
170 Posix_FD(file_name, mode)
171 {
173 {
174 if (mode == Open_Mode::write_lock)
176 else if (!try_exclusive_lock(last_position, 1))
177 throw_last_error("Locking", file_name);
178 }
179 }
180
181 /////////////////////////////////////////////////////////////////////////////
182 int64_t Posix_FD::get_size() const
183 /////////////////////////////////////////////////////////////////////////////
184 {
185 struct stat s;
186
187 if (fstat(fd, &s) < 0)
188 throw_last_error("Getting size of", "file");
189
190 return int64_t(s.st_size);
191 }
192
193 /////////////////////////////////////////////////////////////////////////////
195 /////////////////////////////////////////////////////////////////////////////
196 {
198 close(fd);
199 }
200}
#define JOEDB_SETLKW
#define JOEDB_SETLK
static constexpr int64_t last_position
void destructor_flush() noexcept
~Posix_FD() override
size_t pread(char *buffer, size_t size, int64_t offset) const override
static void throw_last_error(const char *action, const char *file_name)
void pwrite(const char *buffer, size_t size, int64_t offset) override
bool try_exclusive_lock(int64_t start, int64_t size)
int64_t get_size() const override
void sync() override
void unlock(int64_t start, int64_t size) noexcept override
void shared_lock(int64_t start, int64_t size) override
void exclusive_lock(int64_t start, int64_t size) override
Posix_FD(int fd, Open_Mode mode)
Definition Posix_File.h:28
Posix_File(int fd, Open_Mode mode)
Definition Posix_File.h:58
Open_Mode
Definition Open_Mode.h:8
@ create_new
fails if already exists, locks the file for writing
@ 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
@ write_existing_or_create_new
either write_existing or create_new depending on whether the file exists. Racy in Posix,...
@ write_lock
like write_existing_or_create_new, but waits instead of failing if already locked
@ read_existing
fails if does not exist
Definition Blob.h:7