Joedb 10.3.0
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 Tail_Exclusive_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 void touch()
109 {
110 get_writable_journal().touch();
111 }
112
113 /// Automatically write valid_data at every checkpoint (default = false)
114 void set_valid_data(bool b) {use_valid_data = b;}
115
116 /// Automatically write time stamp at every checkpoint (default = false)
117 void set_timestamp(bool b) {use_timestamp = b;}
118
119 /// Use hard checkpoints (default = false)
120 void set_hard_checkpoint(bool b) {use_hard_checkpoint = b;}
121
122 /// @param wait indicates how long the connection may wait for new data
123 ///
124 /// @return number of bytes pulled
125 int64_t pull
126 (
127 std::chrono::milliseconds wait = std::chrono::milliseconds(0)
128 ) override
129 {
130 const int64_t old_checkpoint = get_journal_checkpoint();
131
132 const Tail_Exclusive_Lock lock(get_writable_journal());
133
135 (
138 get_writable_journal(),
139 wait
140 );
141
142 read_journal();
143
144 return get_journal_checkpoint() - old_checkpoint;
145 }
146
148 {
149 transaction([](){});
150 }
151
152 int64_t push_unlock()
153 {
155 }
156
157 int64_t push_if_ahead(int64_t until) override
158 {
161 else
163 }
164
166 };
167
168 /// Lock object that allows writing to a database managed by a joedb::Client
169 ///
170 /// At the end of the life of this object, right before destruction, you
171 /// should call either @ref unlock to cancel the transaction, or
172 /// @ref push_unlock to confirm it. If you fail to do so, the destructor
173 /// will call @ref unlock. But calling unlock explicitly is better,
174 /// if possible, because it can throw exceptions, unlike the destructor.
175 ///
176 /// @ingroup concurrency
178 {
179 protected:
182 bool locked;
183
184 public:
186 client(client),
187 journal_lock(client.get_writable_journal()),
188 locked(true)
189 {
190 client.start_transaction();
191 }
192
193 Client_Lock(const Client_Lock &) = delete;
195
196 /// Checkpoint current journal, but do not push yet
198 {
200 client.do_checkpoint();
201 }
202
203 /// Push if the journal checkpoint is ahead of the connection checkpoint
204 ///
205 /// This function keeps the connection locked
212
213 /// Checkpoint current journal, and push to the connection
214 ///
215 /// Unlike @ref push_unlock, you can call this function multiple
216 /// times during the life of the lock.
218 {
220 client.do_checkpoint();
222 }
223
224 /// Confirm the transaction right before lock destruction
225 ///
226 /// Destruction should happen right after this function.
227 /// Do not call any other member function after this one.
229 {
231 client.do_checkpoint();
233 locked = false;
234 }
235
236 /// Cancel the transaction right before lock destruction
237 ///
238 /// Destruction should happen right after this function.
239 /// Do not call any other member function after this one.
240 void unlock()
241 {
244 locked = false;
245 }
246
247 /// The destructor unlocks the connection if necessary
249 {
250 if (locked)
251 {
252 Destructor_Logger::warning("Client_Lock: locked, cancelling transaction");
253 try { unlock(); } catch (...) {}
254 }
255 }
256 };
257}
258
259#endif
Lock object that allows writing to a database managed by a joedb::Client.
const Tail_Exclusive_Lock journal_lock
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.
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(const std::string &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