Joedb 9.5.0
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 <errno.h>
8#include <string.h>
9
10#ifdef JOEDB_HAS_BROKEN_POSIX_LOCKING
11#define JOEDB_SETLK F_SETLK
12#define JOEDB_SETLKW F_SETLKW
13//#warning is C++23
14//#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.
15#else
16#define JOEDB_SETLK F_OFD_SETLK
17#define JOEDB_SETLKW F_OFD_SETLKW
18#endif
19
20namespace joedb
21{
22#ifndef _FILE_OFFSET_BITS
23 static_assert
24 (
25 sizeof(off_t) == sizeof(int64_t),
26 "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."
27 );
28#endif
29
30 /////////////////////////////////////////////////////////////////////////////
32 /////////////////////////////////////////////////////////////////////////////
33 (
34 const char *action,
35 const char *file_name
36 )
37 {
38 throw Exception
39 (
40 std::string(action) + ' ' + file_name + ": " + strerror(errno)
41 );
42 }
43
44 /////////////////////////////////////////////////////////////////////////////
45 // NOLINTNEXTLINE(readability-make-member-function-const)
46 int Posix_FD::lock(int command, short type, int64_t start, int64_t size)
47 /////////////////////////////////////////////////////////////////////////////
48 {
49 struct flock lock;
50 lock.l_type = type;
51 lock.l_whence = SEEK_SET;
52 lock.l_start = off_t(start);
53 lock.l_len = off_t(size);
54 lock.l_pid = 0;
55
56 return fcntl(fd, command, &lock);
57 }
58
59 /////////////////////////////////////////////////////////////////////////////
60 bool Posix_FD::try_exclusive_lock(int64_t start, int64_t size)
61 /////////////////////////////////////////////////////////////////////////////
62 {
63 return lock(JOEDB_SETLK, F_WRLCK, start, size) == 0;
64 }
65
66 /////////////////////////////////////////////////////////////////////////////
67 void Posix_FD::shared_lock(int64_t start, int64_t size)
68 /////////////////////////////////////////////////////////////////////////////
69 {
70 if (lock(JOEDB_SETLKW, F_RDLCK, start, size) < 0)
71 throw_last_error("Read-locking", "file");
72 }
73
74 /////////////////////////////////////////////////////////////////////////////
75 void Posix_FD::exclusive_lock(int64_t start, int64_t size)
76 /////////////////////////////////////////////////////////////////////////////
77 {
78 if (lock(JOEDB_SETLKW, F_WRLCK, start, size) < 0)
79 throw_last_error("Write-locking", "file");
80 }
81
82 /////////////////////////////////////////////////////////////////////////////
83 void Posix_FD::unlock(int64_t start, int64_t size) noexcept
84 /////////////////////////////////////////////////////////////////////////////
85 {
86 lock(JOEDB_SETLK, F_UNLCK, start, size);
87 }
88
89 /////////////////////////////////////////////////////////////////////////////
90 size_t Posix_FD::pread(char *buffer, size_t size, int64_t offset) const
91 /////////////////////////////////////////////////////////////////////////////
92 {
93 const ssize_t result = ::pread(fd, buffer, size, offset);
94
95 if (result < 0)
96 throw_last_error("Reading", "file");
97
98 return size_t(result);
99 }
100
101 /////////////////////////////////////////////////////////////////////////////
102 void Posix_FD::pwrite(const char *buffer, size_t size, int64_t offset)
103 /////////////////////////////////////////////////////////////////////////////
104 {
105 size_t written = 0;
106
107 while (written < size)
108 {
109 const ssize_t result = ::pwrite
110 (
111 fd,
112 buffer + written,
113 size - written,
114 offset + written
115 );
116
117 if (result < 0)
118 throw_last_error("Writing", "file");
119 else
120 written += size_t(result);
121 }
122 }
123
124 /////////////////////////////////////////////////////////////////////////////
126 /////////////////////////////////////////////////////////////////////////////
127 {
128#ifdef __APPLE__
129 if (fcntl(fd, F_FULLFSYNC) == -1)
130#else
131 if (fsync(fd) == -1)
132#endif
133 {
134 throw_last_error("syncing", "file");
135 }
136 }
137
138#if _POSIX_SYNCHRONIZED_IO > 0
139 /////////////////////////////////////////////////////////////////////////////
140 void Posix_FD::datasync()
141 /////////////////////////////////////////////////////////////////////////////
142 {
143 if (fdatasync(fd) == -1)
144 {
145 throw_last_error("syncing", "file");
146 }
147 }
148#endif
149
150 /////////////////////////////////////////////////////////////////////////////
151 Posix_FD::Posix_FD(const char *file_name, const Open_Mode mode):
152 /////////////////////////////////////////////////////////////////////////////
153 Buffered_File(mode)
154 {
155 if (mode == Open_Mode::read_existing)
156 fd = open(file_name, O_RDONLY);
157 else if (mode == Open_Mode::write_existing)
158 fd = open(file_name, O_RDWR);
159 else if (mode == Open_Mode::create_new)
160 fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, 00644);
161 else if
162 (
164 mode == Open_Mode::shared_write ||
166 )
167 {
168 fd = open(file_name, O_RDWR | O_CREAT | O_EXCL, 00644);
169 if (fd < 0)
170 fd = open(file_name, O_RDWR);
171 }
172
173 if (fd < 0)
174 throw_last_error("Opening", file_name);
175 }
176
177 /////////////////////////////////////////////////////////////////////////////
178 Posix_File::Posix_File(const char *file_name, const Open_Mode mode):
179 /////////////////////////////////////////////////////////////////////////////
180 Posix_FD(file_name, mode)
181 {
183 {
184 if (mode == Open_Mode::write_lock)
186 else if (!try_exclusive_lock(last_position, 1))
187 throw_last_error("Locking", file_name);
188 }
189 }
190
191 /////////////////////////////////////////////////////////////////////////////
192 int64_t Posix_FD::get_size() const
193 /////////////////////////////////////////////////////////////////////////////
194 {
195 struct stat s;
196
197 if (fstat(fd, &s) < 0)
198 throw_last_error("Getting size of", "file");
199
200 return int64_t(s.st_size);
201 }
202
203 /////////////////////////////////////////////////////////////////////////////
205 /////////////////////////////////////////////////////////////////////////////
206 {
208 close(fd);
209 }
210}
#define JOEDB_SETLKW
#define JOEDB_SETLK
virtual void datasync()
Write data durably to permanent storage.
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
Read a range of bytes.
static void throw_last_error(const char *action, const char *file_name)
void pwrite(const char *buffer, size_t size, int64_t offset) override
Write a range of bytes. Extend file size if necessary.
bool try_exclusive_lock(int64_t start, int64_t size)
int64_t get_size() const override
Get the size of the file, or -1 if it is unknown.
void sync() override
Write data and meta-data (such as file size) durably to permanent storage.
void unlock(int64_t start, int64_t size) noexcept override
Remove a lock. The range should match the range of a corresponding lock.
void shared_lock(int64_t start, int64_t size) override
Lock a range of bytes for reading (prevents writes, not reads)
void exclusive_lock(int64_t start, int64_t size) override
Lock a range of bytes for writing (prevents both writes and reads)
Posix_FD(int fd, Open_Mode mode)
Definition Posix_File.h:29
Posix_File(int fd, Open_Mode mode)
Definition Posix_File.h:62
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