reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
PersistentMessageQueue.cxx
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
4
5//#include <fcntl.h>
6//#include "rutil/ResipAssert.h"
7//#include <cstdlib>
8
9#include "rutil/Data.hxx"
10#include "rutil/FileSystem.hxx"
11#include "rutil/Logger.hxx"
12
15
16using namespace resip;
17using namespace repro;
18using namespace std;
19
20#define RESIPROCATE_SUBSYSTEM Subsystem::REPRO
21
22#ifndef DISABLE_BERKELEYDB_USE
23
25{
27 {
28 }
29
30 void init(DbEnv * dbenv)
31 {
32 // let caller catch exceptions
33 dbenv->txn_begin(NULL, &mDbTxn, 0);
34 }
35
37 {
38 abort();
39 }
40
41 void abort()
42 {
43 // don't throw exceptions since this is called in destructor
44 if(mDbTxn !=0 )
45 {
46 try
47 {
48 mDbTxn->abort();
49 }
50 catch(DbException&) {}
51 catch(std::exception&) {}
52 catch(...) {}
53
54 mDbTxn = 0;
55 }
56 }
57
58 void commit()
59 {
60 // let caller catch exceptions
61 if(mDbTxn !=0 )
62 {
63 mDbTxn->commit(0);
64 mDbTxn = 0;
65 }
66 }
67
68 DbTxn* mDbTxn;
69};
70
71struct Cursor
72{
73 Cursor() : mDbc(0)
74 {
75 }
76
77 void init(Db* db, DbTxn* t)
78 {
79 // let caller catch exceptions
80 db->cursor(t, &mDbc, 0);
81 }
82
84 {
85 close();
86 }
87
88 void close()
89 {
90 // don't throw exceptions since this is called in destructor
91 if(mDbc)
92 {
93 try
94 {
95 mDbc->close();
96 }
97 catch(DbException&) {}
98 catch(std::exception&) {}
99 catch(...) {}
100
101 mDbc = 0;
102 }
103 }
104
105 Dbc* mDbc;
106};
107#endif
108
110#ifndef DISABLE_BERKELEYDB_USE
111 DbEnv(0u),
112 mDb(0),
113#endif
114 mBaseDir(baseDir),
115 mRecoveryNeeded(false)
116{
117}
118
120{
121#ifndef DISABLE_BERKELEYDB_USE
122 if(mDb)
123 {
124 try
125 {
126 mDb->close(0);
127 }
128 catch(DbException&) {}
129 catch(std::exception&) {}
130 catch(...) {}
131 }
132
133 try
134 {
135 delete mDb;
136 close(0);
137 }
138 catch(DbException&) {}
139 catch(std::exception&) {}
140 catch(...) {}
141#endif
142}
143
144bool
145PersistentMessageQueue::init(bool sync, const resip::Data& queueName)
146{
147#ifndef DISABLE_BERKELEYDB_USE
148 try
149 {
150 // For Berkeley DB Concurrent Data Store applications, perform locking on an environment-wide basis rather than per-database.
151 set_flags(DB_CDB_ALLDB, 1);
152
153 if(sync)
154 {
155 // Write changes to disk on transaction commit
156 set_flags(DB_TXN_NOSYNC, 0);
157 }
158 else
159 {
160 set_flags(DB_TXN_NOSYNC, 1);
161 }
162
163 Data homeDir;
164 if (mBaseDir.postfix("/") ||
165 mBaseDir.postfix("\\") ||
166 mBaseDir.empty())
167 {
168 homeDir = mBaseDir + queueName;
169 }
170 else
171 {
172 homeDir = mBaseDir + Data("/") + queueName;
173 }
174
175 // Create directory if it doesn't exist
176 FileSystem::Directory dir(homeDir);
177 dir.create();
178
179 open(homeDir.c_str(), // home directory
180 DB_INIT_LOCK // Initialize Locking (needed for transactions)
181 | DB_INIT_LOG // Initialize Logging (needed for transactions)
182 | DB_INIT_TXN // Initialize transactions
183 | DB_INIT_MPOOL // Initialize the cache (needed for transactions)
184 | DB_REGISTER // Check to see if recovery needs to be performed before opening the database environment
185 | DB_RECOVER // Run normal recovery
186 | DB_CREATE // If the env does not exist, then create it
187 | DB_THREAD, // Free-thread the env handle
188 0); // mode
189
190 mDb = new Db(this, 0);
191
192 // cause the logical record numbers to be mutable, and change as records are added to and deleted from the database.
193 mDb->set_flags(DB_RENUMBER);
194
195 mDb->open(0, // txnid
196 "msgqueue", // filename
197 0, // database name
198 DB_RECNO, // database type
199 DB_AUTO_COMMIT // enclose db->open within a transaction
200 | DB_CREATE // create the database if it doesn't already exist
201 | DB_THREAD, // allow free-threaded db access
202 0); // mode
203
204 return true;
205 }
206 catch(DbException& e)
207 {
208 if(e.get_errno() == DB_RUNRECOVERY)
209 {
210 mRecoveryNeeded = true;
211 }
212 WarningLog( << "PersistentMessageQueue::init - DBException: " << e.what());
213 }
214 catch(std::exception& e)
215 {
216 WarningLog( << "PersistentMessageQueue::init - std::exception: " << e.what());
217 }
218 catch(...)
219 {
220 WarningLog( << "PersistentMessageQueue::init - unknown exception");
221 }
222#endif
223 return false;
224}
225
226bool
231
232bool
234{
235#ifndef DISABLE_BERKELEYDB_USE
236 int res;
237
238 try
239 {
240 Transaction transaction;
241 transaction.init(this);
242
243 db_recno_t recno;
244 recno = 0;
245 Dbt val((void*)data.c_str(), (u_int32_t)data.size());
246 Dbt key((void*)&recno, sizeof(recno));
247
248 key.set_ulen(sizeof(recno));
249 key.set_flags(DB_DBT_USERMEM);
250
251 res = mDb->put(transaction.mDbTxn, &key, &val, DB_APPEND);
252 if(res == 0)
253 {
254 transaction.commit();
255 return true;
256 }
257 else
258 {
259 WarningLog( << "PersistentMessageEnqueue::push - put failed: " << db_strerror(res));
260 return false;
261 }
262 }
263 catch(DbException& e)
264 {
265 if(e.get_errno() == DB_RUNRECOVERY)
266 {
267 mRecoveryNeeded = true;
268 }
269 WarningLog( << "PersistentMessageEnqueue::push - DBException: " << e.what());
270 }
271 catch(std::exception& e)
272 {
273 WarningLog( << "PersistentMessageEnqueue::push - std::exception: " << e.what());
274 }
275 catch(...)
276 {
277 WarningLog( << "PersistentMessageEnqueue::push - unknown exception");
278 }
279#endif
280 return false;
281}
282
283// returns true for success, false for failure - can return true and 0 records if none available
284// Note: if autoCommit is used then it is safe to allow multiple consumers
285bool
286PersistentMessageDequeue::pop(size_t numRecords, std::vector<resip::Data>& records, bool autoCommit)
287{
288#ifndef DISABLE_BERKELEYDB_USE
289 if(mNumRecords != 0) // TODO, warning previous pop wasn't committed
290 {
291 abort();
292 }
293 records.clear();
294
295 // Get a cursor and Read
296 try
297 {
298 Transaction transaction; // Only used with auto-commit
299 Cursor cursor;
300 if(autoCommit)
301 {
302 transaction.init(this);
303 }
304 cursor.init(mDb, transaction.mDbTxn); // If autoCommit is false then mDbTxn is 0
305
306 Dbt val;
307 db_recno_t recno = 0;
308 Dbt key((void*)&recno, sizeof(recno));
309
310 for(size_t i = 0; i < numRecords; i ++ )
311 {
312 int get_res = cursor.mDbc->get(&key, &val, DB_NEXT | (autoCommit ? DB_RMW : 0));
313
314 if(get_res == 0)
315 {
316 records.push_back(Data((const char *)val.get_data(), val.get_size()));
317 if(autoCommit)
318 {
319 cursor.mDbc->del(0);
320 }
321 }
322 else
323 {
324 break;
325 }
326 }
327
328 cursor.close();
329 if(autoCommit)
330 {
331 transaction.commit();
332 }
333 else
334 {
335 mNumRecords = records.size();
336 }
337 return true;
338 }
339 catch(DbException& e)
340 {
341 if(e.get_errno() == DB_RUNRECOVERY)
342 {
343 mRecoveryNeeded = true;
344 }
345 WarningLog( << "PersistentMessageDequeue::pop - DBException: " << e.what());
346 abort();
347 }
348 catch(std::exception& e)
349 {
350 WarningLog( << "PersistentMessageDequeue::pop - std::exception: " << e.what());
351 abort();
352 }
353 catch(...)
354 {
355 WarningLog( << "PersistentMessageDequeue::pop - unknown exception");
356 return false;
357 }
358#endif
359 return false;
360}
361
362bool
364{
365#ifndef DISABLE_BERKELEYDB_USE
366 if(mNumRecords == 0)
367 {
368 return true;
369 }
370
371 // Read and delete
372 try
373 {
374 Transaction transaction;
375 Cursor cursor;
376
377 transaction.init(this);
378 cursor.init(mDb, transaction.mDbTxn);
379
380 Dbt val;
381 db_recno_t recno = 0;
382 Dbt key((void*)&recno, sizeof(recno));
383
384 for(size_t i = 0; i < mNumRecords; i++)
385 {
386 int get_res = cursor.mDbc->get(&key, &val, DB_NEXT | DB_RMW);
387 if(get_res == 0)
388 {
389 cursor.mDbc->del(0);
390 }
391 else
392 {
393 break; // this is bad!
394 }
395 }
396
397 mNumRecords = 0;
398 cursor.close();
399 transaction.commit();
400
401 return true;
402 }
403 catch(DbException& e)
404 {
405 if(e.get_errno() == DB_RUNRECOVERY)
406 {
407 mRecoveryNeeded = true;
408 }
409 WarningLog( << "PersistentMessageDequeue::commit - DBException: " << e.what());
410 }
411 catch(std::exception& e)
412 {
413 WarningLog( << "PersistentMessageDequeue::commit - std::exception: " << e.what());
414 }
415 catch(...)
416 {
417 WarningLog( << "PersistentMessageDequeue::commit - unknown exception");
418 }
419#endif
420 return false;
421}
422
423void
425{
426 mNumRecords = 0;
427}
428
429
430/* ====================================================================
431 * The Vovida Software License, Version 1.0
432 *
433 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
434 *
435 * Redistribution and use in source and binary forms, with or without
436 * modification, are permitted provided that the following conditions
437 * are met:
438 *
439 * 1. Redistributions of source code must retain the above copyright
440 * notice, this list of conditions and the following disclaimer.
441 *
442 * 2. Redistributions in binary form must reproduce the above copyright
443 * notice, this list of conditions and the following disclaimer in
444 * the documentation and/or other materials provided with the
445 * distribution.
446 *
447 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
448 * and "Vovida Open Communication Application Library (VOCAL)" must
449 * not be used to endorse or promote products derived from this
450 * software without prior written permission. For written
451 * permission, please contact vocal@vovida.org.
452 *
453 * 4. Products derived from this software may not be called "VOCAL", nor
454 * may "VOCAL" appear in their name, without prior written
455 * permission of Vovida Networks, Inc.
456 *
457 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
458 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
459 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
460 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
461 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
462 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
463 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
464 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
465 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
466 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
467 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
468 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
469 * DAMAGE.
470 *
471 * ====================================================================
472 */
#define WarningLog(args_)
Definition Logger.hxx:134
bool pop(size_t numRecords, std::vector< resip::Data > &records, bool autoCommit)
bool push(const resip::Data &data)
PersistentMessageQueue(const resip::Data &baseDir)
bool init(bool sync, const resip::Data &queueName)
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
const char * c_str() const
Returns a null-terminated string representing.
Definition Data.cxx:1097
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
size_type size() const noexcept
Returns the number of bytes in this Data.
Definition Data.hxx:599
bool postfix(const Data &post) const noexcept
Returns true if this Data ends with the bytes indicated by the passed-in Data.
Definition Data.cxx:1910
This Class is used to implement a primitive form of RPC using loose XML formatting.
dcm! – add UnusedChecking(_enum) below;
void init(Db *db, DbTxn *t)
void init(DbEnv *dbenv)