Joedb 10.2.1
The Journal-Only Embedded Database
Loading...
Searching...
No Matches
Writable_Client.h
Go to the documentation of this file.
1#ifndef joedb_Writable_Client_declared
2#define joedb_Writable_Client_declared
3
6
7namespace joedb
8{
9 /// Writable specialization of Client
10 ///
11 /// @ingroup concurrency
12 class Writable_Client: public Client
13 {
14 friend class Client_Lock;
15
16 protected:
17 template<typename F> auto transaction(F f)
18 {
19 const Journal_Lock lock(get_writable_journal());
20
21 start_transaction();
22
23 using T = decltype(f());
24
25 if constexpr (std::is_void<T>::value)
26 {
27 try
28 {
29 f();
30 do_checkpoint();
31 }
32 catch (...)
33 {
35 throw;
36 }
37
39 }
40 else
41 {
42 const T result = [&]()
43 {
44 try
45 {
46 const T inner_result = f();
47 do_checkpoint();
48 return inner_result;
49 }
50 catch (...)
51 {
53 throw;
54 }
55 } ();
56
58 return result;
59 }
60 }
61
62 private:
63 Writable_Journal &get_writable_journal()
64 {
65 return static_cast<Writable_Journal&>(Client::journal);
66 }
67
68 bool use_valid_data = false;
69 bool use_timestamp = false;
70 bool use_hard_checkpoint = false;
71
72 void do_checkpoint()
73 {
74 if (use_valid_data)
75 get_writable_journal().valid_data();
76
77 if (use_timestamp)
78 get_writable_journal().timestamp(std::time(nullptr));
79
80 get_writable_journal().soft_checkpoint();
81
82 if (use_hard_checkpoint)
83 get_writable_journal().hard_checkpoint();
84 }
85
86 void start_transaction()
87 {
89 (
92 get_writable_journal()
93 );
94
96 }
97
98 public:
107
108 /// Automatically write valid_data at every checkpoint (default = false)
109 void set_valid_data(bool b) {use_valid_data = b;}
110
111 /// Automatically write time stamp at every checkpoint (default = false)
112 void set_timestamp(bool b) {use_timestamp = b;}
113
114 /// Use hard checkpoints (default = false)
115 void set_hard_checkpoint(bool b) {use_hard_checkpoint = b;}
116
117 /// @param wait indicates how long the connection may wait for new data
118 ///
119 /// @return number of bytes pulled
120 int64_t pull
121 (
122 std::chrono::milliseconds wait = std::chrono::milliseconds(0)
123 ) override
124 {
125 const int64_t old_checkpoint = get_journal_checkpoint();
126
127 const Journal_Lock lock(get_writable_journal());
128
130 (
133 get_writable_journal(),
134 wait
135 );
136
137 read_journal();
138
139 return get_journal_checkpoint() - old_checkpoint;
140 }
141
143 {
144 transaction([](){});
145 }
146
147 int64_t push_unlock()
148 {
150 }
151
152 int64_t push_if_ahead(int64_t until) override
153 {
156 else
158 }
159
161 };
162
163 /// Lock object that allows writing to a database managed by a joedb::Client
164 ///
165 /// At the end of the life of this object, right before destruction, you
166 /// should call either @ref unlock to cancel the transaction, or
167 /// @ref push_unlock to confirm it. If you fail to do so, the destructor
168 /// will call @ref unlock. But calling unlock explicitly is better,
169 /// if possible, because it can throw exceptions, unlike the destructor.
170 ///
171 /// @ingroup concurrency
173 {
174 protected:
177 bool locked;
178
179 public:
181 client(client),
182 journal_lock(client.get_writable_journal()),
183 locked(true)
184 {
185 client.start_transaction();
186 }
187
188 Client_Lock(const Client_Lock &) = delete;
190
191 /// Checkpoint current journal, but do not push yet
193 {
195 client.do_checkpoint();
196 }
197
198 /// Push if the journal checkpoint is ahead of the connection checkpoint
199 ///
200 /// This function keeps the connection locked
207
208 /// Checkpoint current journal, and push to the connection
209 ///
210 /// Unlike @ref push_unlock, you can call this function multiple
211 /// times during the life of the lock.
213 {
215 client.do_checkpoint();
217 }
218
219 /// Confirm the transaction right before lock destruction
220 ///
221 /// Destruction should happen right after this function.
222 /// Do not call any other member function after this one.
224 {
226 client.do_checkpoint();
228 locked = false;
229 }
230
231 /// Cancel the transaction right before lock destruction
232 ///
233 /// Destruction should happen right after this function.
234 /// Do not call any other member function after this one.
235 void unlock()
236 {
239 locked = false;
240 }
241
242 /// The destructor unlocks the connection if necessary
244 {
245 if (locked)
246 {
247 Destructor_Logger::warning("Client_Lock: locked, cancelling transaction");
248 try { unlock(); } catch (...) {}
249 }
250 }
251 };
252}
253
254#endif
Lock object that allows writing to a database managed by a joedb::Client.
void checkpoint_and_push_unlock()
Confirm the transaction right before lock destruction.
Writable_Client & client
void do_checkpoint()
Checkpoint current journal, but do not push yet.
void push_if_ahead()
Push if the journal checkpoint is ahead of the connection checkpoint.
Client_Lock(Writable_Client &client)
void checkpoint_and_push()
Checkpoint current journal, and push to the connection.
void unlock()
Cancel the transaction right before lock destruction.
Client_Lock(const Client_Lock &)=delete
~Client_Lock()
The destructor unlocks the connection if necessary.
const Journal_Lock journal_lock
Client_Lock & operator=(const Client_Lock &)=delete
Handle concurrent access to a file with a joedb::Connection.
Definition Client.h:12
virtual void read_journal()
Definition Client.h:14
int64_t connection_checkpoint
Definition Client.h:17
int64_t get_journal_checkpoint() const
Definition Client.h:67
int64_t push(int64_t until, Unlock_Action unlock_action)
Definition Client.h:19
Readonly_Journal & journal
Definition Client.h:15
int64_t push_if_ahead()
Definition Client.h:89
Connection & connection
Definition Client.h:16
int64_t get_connection_checkpoint() const
Definition Client.h:77
static Connection dummy
Since this class has no internal state, this global variable can be used instead of creating an insta...
Definition Connection.h:107
virtual void unlock()
Unlock the connection.
virtual int64_t pull(Lock_Action lock_action, Data_Transfer data_transfer, Writable_Journal &client_journal, std::chrono::milliseconds wait=std::chrono::milliseconds(0))
Pull from the connection.
static void warning(std::string_view message) noexcept
Writable specialization of Client.
void set_valid_data(bool b)
Automatically write valid_data at every checkpoint (default = false)
void set_hard_checkpoint(bool b)
Use hard checkpoints (default = false)
void set_timestamp(bool b)
Automatically write time stamp at every checkpoint (default = false)
int64_t pull(std::chrono::milliseconds wait=std::chrono::milliseconds(0)) override
Writable_Client(Writable_Journal &journal, Connection &connection=Connection::dummy, Content_Check content_check=Content_Check::fast)
int64_t push_if_ahead(int64_t until) override
void timestamp(int64_t timestamp) override
Content_Check
Definition Connection.h:20
#define JOEDB_DEBUG_ASSERT(x)
assertion tested in debug mode
Definition assert.h:19