1 // Author:  Bruce Allen
2 // Created: 2/25/2013
3 //
4 // The software provided here is released by the Naval Postgraduate
5 // School, an agency of the U.S. Department of Navy.  The software
6 // bears no warranty, either expressed or implied. NPS does not assume
7 // legal liability nor responsibility for a User's use of the software
8 // or the results of such use.
9 //
10 // Please note that within the United States, copyright protection,
11 // under Section 105 of the United States Code, Title 17, is not
12 // available for any work of the United States Government and/or for
13 // any works created by United States Government employees. User
14 // acknowledges that this software contains work which was created by
15 // NPS government employees and is therefore in the public domain and
16 // not subject to copyright.
17 //
18 // Released into the public domain on February 25, 2013 by Bruce Allen.
19 
20 /**
21  * \file
22  * Provides a working context for accessing a LMDB DB.
23  *
24  * A context must be opened then closed exactly once.
25  */
26 
27 #ifndef LMDB_CONTEXT_HPP
28 #define LMDB_CONTEXT_HPP
29 #include "lmdb.h"
30 
31 namespace hashdb {
32   class lmdb_context_t {
33     private:
34     MDB_env* env;
35     unsigned int txn_flags; // example MDB_RDONLY
36     unsigned int dbi_flags; // example MDB_DUPSORT
37     int state;
38 
39     // do not allow copy or assignment
40     lmdb_context_t(const lmdb_context_t&);
41     lmdb_context_t& operator=(const lmdb_context_t&);
42 
43     public:
44     MDB_txn* txn;
45     MDB_dbi dbi;
46     MDB_cursor* cursor;
47     MDB_val key;
48     MDB_val data;
49 
lmdb_context_t(MDB_env * p_env,bool is_writable,bool is_duplicates)50     lmdb_context_t(MDB_env* p_env, bool is_writable, bool is_duplicates) :
51            env(p_env), txn_flags(0), dbi_flags(0),
52            state(0), txn(0), dbi(0), cursor(0), key(), data() {
53 
54       // set flags based on bool inputs
55       if (is_writable) {
56         dbi_flags |= MDB_CREATE;  // DBI
57       } else {
58         txn_flags |= MDB_RDONLY;  // TXN
59       }
60       if (is_duplicates) {
61         dbi_flags |= MDB_DUPSORT; // DBI
62       }
63     }
64 
~lmdb_context_t()65     ~lmdb_context_t() {
66       if (state != 2) {
67         std::cerr << "Error: LMDB context not 2: state " << state << "\n";
68         assert(0);
69       }
70     }
71 
open()72     void open() {
73       if (state++ != 0) {
74         std::cerr << "Error: LMDB context not 0: state " << state << "\n";
75         assert(0);
76       }
77 
78       // create txn object
79       int rc = mdb_txn_begin(env, NULL, txn_flags, &txn);
80       if (rc != 0) {
81         std::cerr << "LMDB txn error: " << mdb_strerror(rc) << "\n";
82         assert(0);
83       }
84 
85       // create the database handle integer
86       rc = mdb_dbi_open(txn, NULL, dbi_flags, &dbi);
87       if (rc != 0) {
88         std::cerr << "LMDB dbi error: " << mdb_strerror(rc) << "\n";
89         assert(0);
90       }
91 
92       // create a cursor object to use with this txn
93       rc = mdb_cursor_open(txn, dbi, &cursor);
94       if (rc != 0) {
95         std::cerr << "LMDB cursor error: " << mdb_strerror(rc) << "\n";
96         assert(0);
97       }
98     }
99 
close()100     void close() {
101       if (state++ != 1) {
102         assert(0);
103       }
104 
105       // free cursor
106       mdb_cursor_close(cursor);
107 
108       // do not close dbi handle, why not close it?
109 
110       // free txn object
111       if ((txn_flags & MDB_RDONLY) != MDB_RDONLY) {
112 
113         // RW
114         int rc = mdb_txn_commit(txn);
115         if (rc != 0) {
116           std::cerr << "LMDB txn commit error: " << mdb_strerror(rc) << "\n";
117           assert(0);
118         }
119 
120       } else {
121         // RO
122         mdb_txn_abort(txn);
123       }
124     }
125   };
126 }
127 
128 #endif
129 
130