IceDB.h
Go to the documentation of this file.
1// **********************************************************************
2//
3// Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
4//
5// This copy of Ice is licensed to you under the terms described in the
6// ICE_LICENSE file included in this distribution.
7//
8// **********************************************************************
9
10#ifndef ICE_DB_H
11#define ICE_DB_H
12
13#include <Ice/Initialize.h>
14#include <Ice/InputStream.h>
15#include <Ice/OutputStream.h>
16#include <IceUtil/Exception.h>
17#include <IceUtil/FileUtil.h>
18
19#include <lmdb.h>
20
21#ifndef ICE_DB_API
22#if defined(ICE_STATIC_LIBS)
23#define ICE_DB_API /**/
24#elif defined(ICE_DB_API_EXPORTS)
25#define ICE_DB_API ICE_DECLSPEC_EXPORT
26#else
27#define ICE_DB_API ICE_DECLSPEC_IMPORT
28#endif
29#endif
30
31//
32// Automatically link IceDB37[D|++11|++11D].lib with Visual C++
33//
34#if !defined(ICE_BUILDING_ICE_DB) && defined(ICE_DB_API_EXPORTS)
35#define ICE_BUILDING_ICE_DB
36#endif
37
38#if defined(_MSC_VER) && !defined(ICE_BUILDING_ICE_DB)
39#pragma comment(lib, ICE_LIBNAME("IceDB"))
40#endif
41
42namespace IceDB
43{
44
45 const size_t maxKeySize = 511;
46
47 //
48 // LMDBException wraps an error condition (and error code)
49 // returned by LMDB
50 //
51 class ICE_DB_API LMDBException : public IceUtil::Exception
52 {
53 public:
54 LMDBException(const char*, int, int);
55#ifndef ICE_CPP11_COMPILER
56 virtual ~LMDBException() throw();
57#endif
58
59 virtual std::string ice_id() const;
60 virtual void ice_print(std::ostream&) const;
61#ifndef ICE_CPP11_MAPPING
62 virtual LMDBException* ice_clone() const;
63#endif
64 virtual void ice_throw() const;
65
66 int error() const;
67
68 private:
69 const int _error;
70 static const char* _name;
71 };
72
73 //
74 // KeyTooLongException is thrown if we attempt to marshal a
75 // key with a marshaled representation longer than maxKeySize.
76 //
77 class ICE_DB_API KeyTooLongException : public IceUtil::Exception
78 {
79 public:
80 KeyTooLongException(const char*, int, size_t);
81#ifndef ICE_CPP11_COMPILER
82 virtual ~KeyTooLongException() throw();
83#endif
84
85 virtual std::string ice_id() const;
86 virtual void ice_print(std::ostream&) const;
87#ifndef ICE_CPP11_MAPPING
89#endif
90 virtual void ice_throw() const;
91
92 private:
93 const size_t _size;
94 static const char* _name;
95 };
96
97 //
98 // The creation of an Env fails with BadEnvException when this
99 // Env's max key size is smaller than maxKeySize.
100 //
101 class ICE_DB_API BadEnvException : public IceUtil::Exception
102 {
103 public:
104 BadEnvException(const char*, int, size_t);
105#ifndef ICE_CPP11_COMPILER
106 virtual ~BadEnvException() throw();
107#endif
108
109 virtual std::string ice_id() const;
110 virtual void ice_print(std::ostream&) const;
111#ifndef ICE_CPP11_MAPPING
112 virtual BadEnvException* ice_clone() const;
113#endif
114 virtual void ice_throw() const;
115
116 private:
117 const size_t _size;
118 static const char* _name;
119 };
120
121 //
122 // Codec reads and writes T to/from MDB_val
123 //
124 // Partial specializations of this template must provide:
125 //
126 // Read [out] T from [in] MDB_val using [in] context C
127 // static void read(T& , const MDB_val&, const C&);
128 //
129 // Write [in] T into [out] MDB_val using [in] context C
130 // [out] H& holds the memory for MDB_val.mv_data.
131 // static void write(const T&, MDB_val&, H&, const C&);
132 //
133 // Write [in] T into [in/out] MDB_val using [in] context C
134 // [in] MDB_val contains the destination array
135 // write returns true on success, and false if the provided
136 // array is too small.
137 // On failure, MDB_val.mv_size contains the marshaled key
138 // size if known, and 0 if not know.
139 // static bool write(const T&, MDB_val&, H&, const C&);
140 //
141 template <typename T, typename C, typename H>
142 struct Codec;
143
145 {
146 public:
147 explicit Env(const std::string&, MDB_dbi = 0, size_t = 0, unsigned int = 0);
149
150 void close();
151
152 MDB_env* menv() const;
153
154 private:
155 // Not implemented: class is not copyable
156 Env(const Env&);
157 void operator=(const Env&);
158
159 MDB_env* _menv;
160 };
161
163 {
164 public:
165 virtual ~Txn();
166
167 void commit();
168 void rollback();
169
170 MDB_txn* mtxn() const;
171
172 protected:
173 explicit Txn(const Env&, unsigned int);
174
175 MDB_txn* _mtxn;
176
177 private:
178 // Not implemented: class is not copyable
179 Txn(const Txn&);
180 void operator=(const Txn&);
181 };
182
184 {
185 public:
186 virtual ~ReadOnlyTxn();
187
188 explicit ReadOnlyTxn(const Env&);
189
190 void reset();
191 void renew();
192 };
193
195 {
196 public:
197 virtual ~ReadWriteTxn();
198
199 explicit ReadWriteTxn(const Env&);
200 };
201
203 {
204 public:
205 void clear(const ReadWriteTxn&);
206 MDB_dbi mdbi() const;
207
208 virtual ~DbiBase();
209
210 protected:
211 DbiBase(const Txn&, const std::string&, unsigned int, MDB_cmp_func*);
213
214 // default copy ctor and assignment operator are OK
215
216 bool get(const Txn&, MDB_val*, MDB_val*) const;
217 void put(const ReadWriteTxn&, MDB_val*, MDB_val*, unsigned int);
218 bool find(const Txn&, MDB_val*) const;
219 bool del(const ReadWriteTxn&, MDB_val*, MDB_val*);
220
221 private:
222 MDB_dbi _mdbi;
223 };
224
225 template <typename K, typename D, typename C, typename H>
226 class Dbi : public DbiBase
227 {
228 public:
229 Dbi(const Txn& txn,
230 const std::string& name,
231 const C& ctx,
232 unsigned int flags = 0,
233 MDB_cmp_func* cmp = 0) :
234 DbiBase(txn, name, flags, cmp), _marshalingContext(ctx)
235 {
236 }
237
239 {
240 }
241
242 bool
243 get(const Txn& txn, const K& key, D& data) const
244 {
245 unsigned char kbuf[maxKeySize];
246 MDB_val mkey = {maxKeySize, kbuf};
247
248 if (Codec<K, C, H>::write(key, mkey, _marshalingContext))
249 {
250 MDB_val mdata;
251 if (DbiBase::get(txn, &mkey, &mdata))
252 {
253 Codec<D, C, H>::read(data, mdata, _marshalingContext);
254 return true;
255 }
256 }
257 return false;
258 }
259
260 void
261 put(const ReadWriteTxn& txn, const K& key, const D& data, unsigned int flags = 0)
262 {
263 unsigned char kbuf[maxKeySize];
264 MDB_val mkey = {maxKeySize, kbuf};
265
266 if (Codec<K, C, H>::write(key, mkey, _marshalingContext))
267 {
268 H hdata;
269 MDB_val mdata;
270 Codec<D, C, H>::write(data, mdata, hdata, _marshalingContext);
271 DbiBase::put(txn, &mkey, &mdata, flags);
272 }
273 else
274 {
275 throw KeyTooLongException(__FILE__, __LINE__, mkey.mv_size);
276 }
277 }
278
279 bool
280 find(const Txn& txn, const K& key) const
281 {
282 unsigned char kbuf[maxKeySize];
283 MDB_val mkey = {maxKeySize, kbuf};
284 if (Codec<K, C, H>::write(key, mkey, _marshalingContext))
285 {
286 return DbiBase::find(txn, &mkey);
287 }
288 else
289 {
290 return false;
291 }
292 }
293
294 bool
295 del(const ReadWriteTxn& txn, const K& key, const D& data)
296 {
297 unsigned char kbuf[maxKeySize];
298 MDB_val mkey = {maxKeySize, kbuf};
299 if (Codec<K, C, H>::write(key, mkey, _marshalingContext))
300 {
301 H hdata;
302 MDB_val mdata;
303 Codec<D, C, H>::write(data, mdata, hdata, _marshalingContext);
304 return DbiBase::del(txn, &mkey, &mdata);
305 }
306 else
307 {
308 return false;
309 }
310 }
311
312 bool
313 del(const ReadWriteTxn& txn, const K& key)
314 {
315 unsigned char kbuf[maxKeySize];
316 MDB_val mkey = {maxKeySize, kbuf};
317 if (Codec<K, C, H>::write(key, mkey, _marshalingContext))
318 {
319 return DbiBase::del(txn, &mkey, 0);
320 }
321 else
322 {
323 return false;
324 }
325 }
326
327 C
329 {
330 return _marshalingContext;
331 }
332
333 private:
334 C _marshalingContext;
335 };
336
338 {
339 public:
340 void close();
341
342 MDB_cursor* mcursor() const;
343
344 virtual ~CursorBase();
345
346 protected:
347 CursorBase(MDB_dbi dbi, const Txn& txn, bool);
348
349 bool get(MDB_val*, MDB_val*, MDB_cursor_op);
350 void put(MDB_val*, MDB_val*, unsigned int);
351 bool find(MDB_val*);
352 bool find(MDB_val*, MDB_val*);
353 void del(unsigned int);
354 void renew(const ReadOnlyTxn&);
355
356 private:
357 // Not implemented: class is not copyable
358 CursorBase(const CursorBase&);
359 void operator=(const CursorBase&);
360
361 MDB_cursor* _mcursor;
362 const bool _readOnly;
363 };
364
365 template <typename K, typename D, typename C, typename H>
366 class Cursor : public CursorBase
367 {
368 public:
369 Cursor(const Dbi<K, D, C, H>& dbi, const ReadOnlyTxn& txn) :
370 CursorBase(dbi.mdbi(), txn, true), _marshalingContext(dbi.marshalingContext())
371 {
372 }
373
374 Cursor(const Dbi<K, D, C, H>& dbi, const ReadWriteTxn& txn) :
375 CursorBase(dbi.mdbi(), txn, false), _marshalingContext(dbi.marshalingContext())
376 {
377 }
378
379 Cursor(const Dbi<K, D, C, H>& dbi, const Txn& txn) :
380 CursorBase(dbi.mdbi(), txn, dynamic_cast<const ReadOnlyTxn*>(&txn) != 0),
381 _marshalingContext(dbi.marshalingContext())
382 {
383 }
384
385 bool
386 get(K& key, D& data, MDB_cursor_op op)
387 {
388 MDB_val mkey, mdata;
389 if (CursorBase::get(&mkey, &mdata, op))
390 {
393 return true;
394 }
395 return false;
396 }
397
398 bool
399 find(const K& key)
400 {
401 unsigned char kbuf[maxKeySize];
402 MDB_val mkey = {maxKeySize, kbuf};
404 {
405 return CursorBase::find(&mkey);
406 }
407 else
408 {
409 return false;
410 }
411 }
412
413 bool
414 find(const K& key, D& data)
415 {
416 unsigned char kbuf[maxKeySize];
417 MDB_val mkey = {maxKeySize, kbuf};
419 {
420 MDB_val mdata;
421 if (CursorBase::find(&mkey, &mdata))
422 {
424 return true;
425 }
426 }
427 return false;
428 }
429
430 protected:
432 };
433
434 template <typename K, typename D, typename C, typename H>
435 class ReadWriteCursor : public Cursor<K, D, C, H>
436 {
437 public:
439 Cursor<K, D, C, H>(dbi, txn)
440 {
441 }
442
443 void
444 put(const K& key, const D& data, unsigned int flags = 0)
445 {
446 unsigned char kbuf[maxKeySize];
447 MDB_val mkey = {maxKeySize, kbuf};
448 if (Codec<K, C, H>::write(key, mkey, this->_marshalingContext))
449 {
450 H hdata;
451 MDB_val mdata;
452 Codec<D, C, H>::write(data, mdata, hdata, this->_marshalingContext);
453 CursorBase::put(&mkey, &mdata, flags);
454 }
455 else
456 {
457 throw KeyTooLongException(__FILE__, __LINE__, mkey.mv_size);
458 }
459 }
460
461 void
462 del(unsigned int flags = 0)
463 {
464 CursorBase::del(flags);
465 }
466 };
467
468 template <typename K, typename D, typename C, typename H>
469 class ReadOnlyCursor : public Cursor<K, D, C, H>
470 {
471 public:
473 Cursor<K, D, C, H>(dbi, txn)
474 {
475 }
476
477 void
478 renew(const ReadOnlyTxn& txn)
479 {
481 }
482 };
483
484 //
485 // Partial specialization of Codec for Ice encoding
486 //
488 {
490 Ice::EncodingVersion encoding;
491 };
492
493 template <typename T>
494 struct Codec<T, IceContext, Ice::OutputStream>
495 {
496 static void
497 read(T& t, const MDB_val& val, const IceContext& ctx)
498 {
499 std::pair<const Ice::Byte*, const Ice::Byte*> p(
500 static_cast<const Ice::Byte*>(val.mv_data),
501 static_cast<const Ice::Byte*>(val.mv_data) + val.mv_size);
502 Ice::InputStream in(ctx.communicator, ctx.encoding, p);
503 in.read(t);
504 }
505
506 static void
507 write(const T& t, MDB_val& val, Ice::OutputStream& holder, const IceContext& ctx)
508 {
509 holder.initialize(ctx.communicator, ctx.encoding);
510 holder.write(t);
511 val.mv_size = holder.b.size();
512 val.mv_data = &holder.b[0];
513 }
514
515 static bool
516 write(const T& t, MDB_val& val, const IceContext& ctx)
517 {
518 const size_t limit = val.mv_size;
519 std::pair<Ice::Byte*, Ice::Byte*> p(reinterpret_cast<Ice::Byte*>(val.mv_data),
520 reinterpret_cast<Ice::Byte*>(val.mv_data) + limit);
521 Ice::OutputStream stream(ctx.communicator, ctx.encoding, p);
522 stream.write(t);
523 val.mv_size = stream.b.size();
524 return stream.b.size() > limit ? false : true;
525 }
526 };
527
528 //
529 // Returns computed mapSize in bytes.
530 // When the input parameter is <= 0, returns a platform-dependent default
531 // (currently 0 on Windows and 100 MB on other platforms).
532 // Otherwise, returns input parameter * 1 MB.
533 //
534
536
537} // namespace IceDB
538
539#endif
uint8_t data[1]
#define ICE_DB_API
Definition IceDB.h:27
virtual BadEnvException * ice_clone() const
virtual void ice_print(std::ostream &) const
virtual void ice_throw() const
virtual std::string ice_id() const
BadEnvException(const char *, int, size_t)
MDB_cursor * mcursor() const
void del(unsigned int)
void put(MDB_val *, MDB_val *, unsigned int)
void renew(const ReadOnlyTxn &)
bool find(MDB_val *, MDB_val *)
bool find(MDB_val *)
CursorBase(MDB_dbi dbi, const Txn &txn, bool)
virtual ~CursorBase()
bool get(MDB_val *, MDB_val *, MDB_cursor_op)
bool get(K &key, D &data, MDB_cursor_op op)
Definition IceDB.h:386
Cursor(const Dbi< K, D, C, H > &dbi, const ReadWriteTxn &txn)
Definition IceDB.h:374
bool find(const K &key, D &data)
Definition IceDB.h:414
Cursor(const Dbi< K, D, C, H > &dbi, const Txn &txn)
Definition IceDB.h:379
bool find(const K &key)
Definition IceDB.h:399
C _marshalingContext
Definition IceDB.h:431
Cursor(const Dbi< K, D, C, H > &dbi, const ReadOnlyTxn &txn)
Definition IceDB.h:369
DbiBase(const Txn &, const std::string &, unsigned int, MDB_cmp_func *)
virtual ~DbiBase()
MDB_dbi mdbi() const
bool get(const Txn &, MDB_val *, MDB_val *) const
bool del(const ReadWriteTxn &, MDB_val *, MDB_val *)
void put(const ReadWriteTxn &, MDB_val *, MDB_val *, unsigned int)
bool find(const Txn &, MDB_val *) const
void clear(const ReadWriteTxn &)
void put(const ReadWriteTxn &txn, const K &key, const D &data, unsigned int flags=0)
Definition IceDB.h:261
bool get(const Txn &txn, const K &key, D &data) const
Definition IceDB.h:243
bool del(const ReadWriteTxn &txn, const K &key)
Definition IceDB.h:313
bool del(const ReadWriteTxn &txn, const K &key, const D &data)
Definition IceDB.h:295
bool find(const Txn &txn, const K &key) const
Definition IceDB.h:280
Dbi(const Txn &txn, const std::string &name, const C &ctx, unsigned int flags=0, MDB_cmp_func *cmp=0)
Definition IceDB.h:229
C marshalingContext() const
Definition IceDB.h:328
Env(const std::string &, MDB_dbi=0, size_t=0, unsigned int=0)
MDB_env * menv() const
void close()
virtual KeyTooLongException * ice_clone() const
virtual void ice_print(std::ostream &) const
KeyTooLongException(const char *, int, size_t)
virtual void ice_throw() const
virtual std::string ice_id() const
virtual ~LMDBException()
LMDBException(const char *, int, int)
virtual void ice_print(std::ostream &) const
virtual LMDBException * ice_clone() const
virtual void ice_throw() const
virtual std::string ice_id() const
ReadOnlyCursor(const Dbi< K, D, C, H > &dbi, const ReadOnlyTxn &txn)
Definition IceDB.h:472
void renew(const ReadOnlyTxn &txn)
Definition IceDB.h:478
ReadOnlyTxn(const Env &)
virtual ~ReadOnlyTxn()
void del(unsigned int flags=0)
Definition IceDB.h:462
ReadWriteCursor(const Dbi< K, D, C, H > &dbi, const ReadWriteTxn &txn)
Definition IceDB.h:438
void put(const K &key, const D &data, unsigned int flags=0)
Definition IceDB.h:444
virtual ~ReadWriteTxn()
ReadWriteTxn(const Env &)
void rollback()
MDB_txn * mtxn() const
virtual ~Txn()
Txn(const Env &, unsigned int)
MDB_txn * _mtxn
Definition IceDB.h:175
void commit()
Definition IceDB.h:43
const size_t maxKeySize
Definition IceDB.h:45
ICE_DB_API size_t getMapSize(int)
::IceInternal::Handle<::Ice::Communicator > CommunicatorPtr
Definition IceManager.h:49
static void write(const T &t, MDB_val &val, Ice::OutputStream &holder, const IceContext &ctx)
Definition IceDB.h:507
static void read(T &t, const MDB_val &val, const IceContext &ctx)
Definition IceDB.h:497
static bool write(const T &t, MDB_val &val, const IceContext &ctx)
Definition IceDB.h:516
Ice::CommunicatorPtr communicator
Definition IceDB.h:489
Ice::EncodingVersion encoding
Definition IceDB.h:490