1 /*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2009, 2013 Oracle and/or its affiliates. All rights reserved.
5 *
6 * $Id$
7 */
8
9 #ifndef _DB_STL_CONTAINER_H__
10 #define _DB_STL_CONTAINER_H__
11
12 #include "dbstl_common.h"
13 #include "dbstl_resource_manager.h"
14 #include <assert.h>
15
START_NS(dbstl)16 START_NS(dbstl)
17
18 class ResourceManager;
19
20 //////////////////////////////////////////////////////////////////////////
21 //////////////////////////////////////////////////////////////////////////
22 //
23 // db_container class definition
24 //
25 // This class's begin_txn, commit/abort_txn is used to wrap each DB related
26 // operation inside dbstl. When auto commit is enabled, each operation will
27 // be auto committed before returning, and aborted when an exception is thrown.
28 //
29 // It also contains members to hold all needed parameters and flags for
30 // transaction and cursor related calls.
31 //
32 // Container classes will inherit from this class. Each container will enclose
33 // every db related operation with db_container::begin_txn and
34 // db_container::commit_txn, and if exception is not caught, abort_txn()
35 // should be called.
36
37 /** \defgroup dbstl_containers dbstl container classes
38 A dbstl container is very much like a C++ STL container. It stores a
39 collection of data items, or key/data pairs.
40 Each container is backed by a Berkeley DB database created in an explicit
41 database environment or an internal private environment; And the database
42 itself can be created explicitly with all kinds of configurations, or
43 by dbstl internally. For each type of container, some specific type of
44 database and/or configurations must be used or specified to the database
45 and its environment. dbstl will check the database and environment conform
46 to the requirement. When users don't have a chance to specify a container's
47 backing database and environment, like in copy constructors, dbstl will
48 create proper databases and/or environment for it. There are two helper
49 functions to make it easier to create/open an environment or database, they
50 are dbstl::open_db() and dbstl::open_env();
51 \sa dbstl::open_db() dbstl::open_env() db_vector db_map db_multimap db_set
52 db_multiset
53 */
54
55 /** \ingroup dbstl_containers
56 @{
57 This class is the base class for all db container classes, you don't directly
58 use this class, but all container classes inherit from this class, so you need
59 to know the methods that can be accessed via concrete container classes.
60 This class is also used to support auto commit transactions. Autocommit is
61 enabled when DB_AUTO_COMMIT is set to the database or database environment
62 handle and the environment is transactional.
63
64 Inside dbstl, there are transactions begun and committed/aborted if the backing
65 database and/or environment requires auto commit, and there are cursors
66 opened internally, and you can set the flags used by the transaction and cursor
67 functions via set functions of this class.
68
69 All dbstl containers are fully multi-threaded, you should not need any
70 synchronization to use them in the correct way, but this class is not thread
71 safe, access to its members are not proctected by any mutex because the data
72 members of this class are supposed to be set before they are used,
73 and remain read only afterwards. If this is not the case, you must synchronize
74 the access.
75 */
76 class _exported db_container
77 {
78 private:
79 // By default these flags are 0, users should configure these values
80 // on container initialization.
81 //
82 u_int32_t txn_begin_flags_, commit_flags_;
83 mutable u_int32_t cursor_oflags_;
84
85 // Berkeley DB database handle for each container. Subclasses do not
86 // need to define it.
87 //
88 Db *pdb_;
89
90 // Berkeley DB environment handle in which the db handle is opened.
91 DbEnv *dbenv_;
92
93 // db_map_iterator<> needs to know whether the container is a
94 // db_(multi)set or not
95 //
96 bool is_set_;
97
98 // Determined automatically, by inspecting users the Berkeley DB
99 // database and environment configuration options.
100 //
101 bool auto_commit_;
102
103 // If exisiting random temporary database name generation mechanism is
104 // still causing name clashes, users can set this global suffix number
105 // which will be append to each temporary database file name and by
106 // default it is 0. there is a dbstl::set_global_dbfile_suffix_number
107 // to do so.
108 static u_int32_t g_db_file_suffix_;
109 friend void set_global_dbfile_suffix_number(u_int32_t);
110 protected:
111
112 // Does not clone or copy data from database parameter.
113 // Return the db file name back in the dbfname parameter.
114 // We construct a default database name the user can rename it using
115 // either DbEnv::dbrename or Db::rename.
116 //
117 Db* clone_db_config(Db *dbp, std::string &dbfname);
118 Db* clone_db_config(Db *dbp);
119
120 // Store the name into name parameter whose length is n. Return -1 if
121 // not enough space.
122 int construct_db_file_name(std::string &filename) const;
123
124 // Check that this container and cntnr are backed by different databases
125 // and if any one of them is using transactions, both should be in the
126 // same transactional environment.
127 // Called by all deriving classes' methods
128 // which have a container parameter.
129 void verify_db_handles(const db_container &cntnr) const;
130
131 void open_db_handles(Db *&pdb, DbEnv *&penv, DBTYPE dbtype,
132 u_int32_t oflags, u_int32_t sflags);
133
134 inline void set_is_set(bool b)
135 {
136 is_set_ = b;
137 }
138
139 inline bool is_set() const
140 {
141 return is_set_;
142 }
143
144 // Database and environment handles and autocommit and is_set_ are
145 // not assigned, because they are the nature of my own db, not
146 // that of dbctnr.
147 inline const db_container &operator=(const db_container & dbctnr)
148 {
149 ASSIGNMENT_PREDCOND(dbctnr)
150 txn_begin_flags_ = dbctnr.txn_begin_flags_;
151 commit_flags_ = dbctnr.commit_flags_;
152 cursor_oflags_ = dbctnr.cursor_oflags_;
153 return dbctnr;
154 }
155
156 public:
157 /// Default constructor.
158 db_container();
159
160 /// Copy constructor.
161 /// The new container will be backed by another database within the
162 /// same environment unless dbctnr's backing database is in its own
163 /// internal private environment. The name of the database is coined
164 /// based on current time and thread id and some random number. If
165 /// this is still causing naming clashes, you can set a suffix number
166 /// via "set_global_dbfile_suffix_number" function; And following db
167 /// file will suffix this number in the file name for additional
168 /// randomness. And the suffix will be incremented after each such use.
169 /// You can change the file name via DbEnv::rename.
170 /// If dbctnr is using an anonymous database, the newly constructed
171 /// container will also use an anonymous one.
172 /// \param dbctnr The container to initialize this container.
173 db_container(const db_container &dbctnr);
174
175 /**
176 This constructor is not directly called by the user, but invoked by
177 constructors of concrete container classes. The statement about the
178 parameters applies to constructors of all container classes.
179 \param dbp Database handle. dbp is supposed to be opened inside envp.
180 Each dbstl container is backed by a Berkeley DB database, so dbstl
181 will create an internal anonymous database if dbp is NULL.
182 \param envp Environment handle. And envp can also be NULL, meaning the
183 dbp handle may be created in its internal private environment.
184 */
185 db_container(Db *dbp, DbEnv *envp);
186
187 /// The backing database is not closed in this function. It is closed
188 /// when current thread exits and the database is no longer referenced
189 /// by any other container instances in this process.
190 /// In order to make the reference counting work alright, you must call
191 /// register_db(Db*) and register_db_env(DbEnv*) correctly.
192 /// \sa register_db(Db*) register_db_env(DbEnv*)
193 virtual ~db_container(){}
194
195 /// \name Get and set functions for data members.
196 /// Note that these functions are not thread safe, because all data
197 /// members of db_container are supposed to be set on container
198 /// construction and initialization, and remain read only afterwards.
199 //@{
200 /// Get the backing database's open flags.
201 /// \return The backing database's open flags.
202 inline u_int32_t get_db_open_flags() const
203 {
204 u_int32_t oflags;
205 pdb_->get_open_flags(&oflags);
206 return oflags;
207 }
208
209 /// Get the backing database's flags that are set via Db::set_flags()
210 /// function.
211 /// \return Flags set to this container's database handle.
212 inline u_int32_t get_db_set_flags() const
213 {
214 u_int32_t oflags;
215 pdb_->get_flags(&oflags);
216 return oflags;
217 }
218
219 /// Get the backing database's handle.
220 /// \return The backing database handle of this container.
221 inline Db* get_db_handle() const
222 {
223 return pdb_;
224 }
225
226 /// Get the backing database environment's handle.
227 /// \return The backing database environment handle of this container.
228 inline DbEnv* get_db_env_handle() const
229 {
230 return dbenv_;
231 }
232
233 /**
234 Set the underlying database's handle, and optionally environment
235 handle if the environment has also changed. That is, users can change
236 the container object's underlying database while the object is alive.
237 dbstl will verify that the handles set conforms to the concrete
238 container's requirement to Berkeley DB database/environment handles.
239 \param dbp The database handle to set.
240 \param newenv The database environment handle to set.
241 */
242 void set_db_handle(Db *dbp, DbEnv *newenv = NULL);
243
244 /** Set the flags required by the Berkeley DB functions
245 DbEnv::txn_begin(), DbTxn::commit() and DbEnv::cursor(). These flags
246 will be set to this container's auto commit member functions when
247 auto commit transaction is used, except that cursor_oflags is set to
248 the Dbc::cursor when creating an iterator for this container.
249 By default the three flags are all zero.
250 You can also set the values of the flags individually by using the
251 appropriate set functions in this class. The corresponding get
252 functions return the flags actually used.
253 \param txn_begin_flags Flags to be set to DbEnv::txn_begin().
254 \param commit_flags Flags to be set to DbTxn::commit().
255 \param cursor_open_flags Flags to be set to Db::cursor().
256 */
257 inline void set_all_flags(u_int32_t txn_begin_flags,
258 u_int32_t commit_flags, u_int32_t cursor_open_flags)
259 {
260 this->txn_begin_flags_ = txn_begin_flags;
261 this->commit_flags_ = commit_flags;
262 this->cursor_oflags_ = cursor_open_flags;
263 }
264
265 /// Set flag of DbEnv::txn_begin() call.
266 /// \param flag Flags to be set to DbEnv::txn_begin().
267 inline void set_txn_begin_flags(u_int32_t flag )
268 {
269 txn_begin_flags_ = flag;
270 }
271
272 /// Get flag of DbEnv::txn_begin() call.
273 /// \return Flags to be set to DbEnv::txn_begin().
274 inline u_int32_t get_txn_begin_flags() const
275 {
276 return txn_begin_flags_;
277 }
278
279 /// Set flag of DbTxn::commit() call.
280 /// \param flag Flags to be set to DbTxn::commit().
281 inline void set_commit_flags(u_int32_t flag)
282 {
283 commit_flags_ = flag;
284 }
285
286 /// Get flag of DbTxn::commit() call.
287 /// \return Flags to be set to DbTxn::commit().
288 inline u_int32_t get_commit_flags() const
289 {
290 return commit_flags_;
291 }
292
293 /// Get flag of Db::cursor() call.
294 /// \return Flags to be set to Db::cursor().
295 inline u_int32_t get_cursor_open_flags() const
296 {
297 return cursor_oflags_;
298 }
299
300 /// Set flag of Db::cursor() call.
301 /// \param flag Flags to be set to Db::cursor().
302 inline void set_cursor_open_flags(u_int32_t flag)
303 {
304 cursor_oflags_ = flag;
305 }
306 //@} // getter_setters
307
308 protected:
309 void init_members();
310 void init_members(Db *pdb, DbEnv *env);
311 void init_members(const db_container&cnt);
312 // Called internally by concrete container constructors. Verification
313 // is done by the specialized constructors
314 void set_db_handle_int(Db *dbp, DbEnv *envp)
315 {
316 this->pdb_ = dbp;
317 this->dbenv_ = envp;
318 }
319
320 // Child classes override this function to check the db and environment
321 // handles are correctly configured.
322 virtual const char* verify_config(Db* pdb, DbEnv* penv) const
323 {
324 if (pdb != NULL && ((pdb->get_create_flags() &
325 DB_CXX_NO_EXCEPTIONS) == 0))
326 return
327 "Db and DbEnv object must be constructed with DB_CXX_NO_EXCEPTIONS flag set.";
328
329 if (penv != NULL && ((penv->get_create_flags() &
330 DB_CXX_NO_EXCEPTIONS) == 0))
331 return
332 "Db and DbEnv object must be constructed with DB_CXX_NO_EXCEPTIONS flag set.";
333 return NULL;
334 }
335
336 // Use db and dbenv_ to determine whether to enable autocommit. If
337 // DB_AUTOCOMMIT is set on dbenv_ or db and dbenv_ is transactional,
338 // that db should be autocommit.
339 //
340 void set_auto_commit(Db* db);
341
342 // Begin a transaction. Used to make a container's db related
343 // operations auto commit when the operation completes and abort
344 // when the operation fails. If there is already a transaction for this
345 // container's environment, then that transaction is used. If the
346 // transaction was created by DB STL, its reference count is
347 // incremented (user created and external transactions are not
348 // reference counted because they can be nested.).
349 inline DbTxn* begin_txn() const
350 {
351 DbTxn *txn = NULL;
352
353 if (this->auto_commit_) {
354 txn = ResourceManager::instance()->begin_txn(
355 this->txn_begin_flags_, dbenv_, 0);
356 }
357 return txn;
358 }
359
360 inline void commit_txn() const
361 {
362 if (this->auto_commit_) {
363 ResourceManager::instance()->
364 commit_txn(pdb_->get_env(), this->commit_flags_);
365 }
366 }
367
368 inline void abort_txn() const
369 {
370 if (this->auto_commit_)
371 ResourceManager::instance()->
372 abort_txn(pdb_->get_env());
373 }
374
375 inline DbTxn *current_txn() const
376 {
377 return ResourceManager::instance()->
378 current_txn(pdb_->get_env());
379 }
380 }; // db_container
381 /** @} */ // dbstl_containers
382
383 /// \addtogroup dbstl_helper_classes
384 //@{
385 /// Bulk retrieval configuration helper class. Used by the begin() function of
386 /// a container.
387 class _exported BulkRetrievalOption
388 {
389 public:
390 enum Option {BulkRetrieval, NoBulkRetrieval};
391
392 protected:
393 Option bulk_retrieve;
394 u_int32_t bulk_buf_sz_;
395
BulkRetrievalOption()396 inline BulkRetrievalOption()
397 {
398 bulk_retrieve = NoBulkRetrieval;
399 bulk_buf_sz_ = DBSTL_BULK_BUF_SIZE;
400 }
401
402 public:
403 inline BulkRetrievalOption(Option bulk_retrieve1,
404 u_int32_t bulk_buf_sz = DBSTL_BULK_BUF_SIZE)
405 {
406 this->bulk_retrieve = bulk_retrieve1;
407 this->bulk_buf_sz_ = bulk_buf_sz;
408 }
409
410 // The following two static members should best be const, but this is
411 // impossible because in C++ this definition is a function declaration:
412 // const static BulkRetrievalOption BulkRetrieval(BulkRetrieval);
413 // i.e. const static members can only be inited with default copy
414 // constructor.
415 //
416 // Static data members can't be compiled into a .lib for a dll on
417 // Windows, code using the static members will have link error---
418 // unresolved symbols, so we have to use a static function here.
419 /// This function indicates that you need a bulk retrieval iterator,
420 /// and it can be also used to optionally set the bulk read buffer size.
421 inline static BulkRetrievalOption bulk_retrieval(
422 u_int32_t bulk_buf_sz = DBSTL_BULK_BUF_SIZE)
423 {
424 return BulkRetrievalOption(BulkRetrieval, bulk_buf_sz);
425 }
426
427 /// This function indicates that you do not need a bulk retrieval
428 /// iterator.
no_bulk_retrieval()429 inline static BulkRetrievalOption no_bulk_retrieval()
430 {
431 return BulkRetrievalOption(NoBulkRetrieval, 0);
432 }
433
434 /// Equality comparison.
435 inline bool operator==(const BulkRetrievalOption& bro) const
436 {
437 return bulk_retrieve == bro.bulk_retrieve;
438 }
439
440 /// Assignment operator.
441 inline void operator=(BulkRetrievalOption::Option opt)
442 {
443 bulk_retrieve = opt;
444 }
445
446 /// Return the buffer size set to this object.
bulk_buf_size()447 inline u_int32_t bulk_buf_size()
448 {
449 return bulk_buf_sz_;
450 }
451 };
452 //@}
453
454 /// \addtogroup dbstl_helper_classes
455 //@{
456 /// Read-modify-write cursor configuration helper class. Used by each begin()
457 /// function of all containers.
458 class _exported ReadModifyWriteOption
459 {
460 protected:
461 enum Option{ReadModifyWrite, NoReadModifyWrite};
462 Option rmw;
463
ReadModifyWriteOption(Option rmw1)464 inline ReadModifyWriteOption(Option rmw1)
465 {
466 this->rmw = rmw1;
467 }
468
ReadModifyWriteOption()469 inline ReadModifyWriteOption()
470 {
471 rmw = NoReadModifyWrite;
472 }
473
474 public:
475 /// Assignment operator.
476 inline void operator=(ReadModifyWriteOption::Option rmw1)
477 {
478 this->rmw = rmw1;
479 }
480
481 /// Equality comparison.
482 inline bool operator==(const ReadModifyWriteOption &rmw1) const
483 {
484 return this->rmw == rmw1.rmw;
485 }
486
487 /// Call this function to tell the container's begin() function that
488 /// you need a read-modify-write iterator.
read_modify_write()489 inline static ReadModifyWriteOption read_modify_write()
490 {
491 return ReadModifyWriteOption(ReadModifyWrite);
492 }
493
494 /// Call this function to tell the container's begin() function that
495 /// you do not need a read-modify-write iterator. This is the default
496 /// value for the parameter of any container's begin() function.
no_read_modify_write()497 inline static ReadModifyWriteOption no_read_modify_write()
498 {
499 return ReadModifyWriteOption(NoReadModifyWrite);
500 }
501
502 };
503 //@} // dbstl_helper_classes
504
505 // The classes in the Berkeley DB C++ API do not expose data and p_ member.
506 // Extend the class to provide this functionality, rather than altering the
507 // internal implementations.
508 //
509 class _exported DbstlMultipleIterator : protected DbMultipleIterator
510 {
511 protected:
DbstlMultipleIterator(const Dbt & dbt)512 DbstlMultipleIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {}
513 public:
get_pointer()514 u_int32_t get_pointer()
515 {
516 u_int32_t off;
517 off = (u_int32_t)((u_int8_t*)p_ - data_);
518 return off;
519 }
520
set_pointer(u_int32_t offset)521 inline void set_pointer(u_int32_t offset)
522 {
523 p_ = (u_int32_t*)(data_ + offset);
524 }
525
526 };
527
528 class _exported DbstlMultipleKeyDataIterator : public DbstlMultipleIterator
529 {
530 public:
DbstlMultipleKeyDataIterator(const Dbt & dbt)531 DbstlMultipleKeyDataIterator(const Dbt &dbt)
532 : DbstlMultipleIterator(dbt) {}
533 bool next(Dbt &key, Dbt &data);
534 };
535
536 class _exported DbstlMultipleRecnoDataIterator : public DbstlMultipleIterator
537 {
538 public:
DbstlMultipleRecnoDataIterator(const Dbt & dbt)539 DbstlMultipleRecnoDataIterator(const Dbt &dbt)
540 : DbstlMultipleIterator(dbt) {}
541 bool next(db_recno_t &recno, Dbt &data);
542 };
543
544 class _exported DbstlMultipleDataIterator : public DbstlMultipleIterator
545 {
546 public:
DbstlMultipleDataIterator(const Dbt & dbt)547 DbstlMultipleDataIterator(const Dbt &dbt)
548 : DbstlMultipleIterator(dbt) {}
549 bool next(Dbt &data);
550 };
551
552 // These classes are used to give data values meaningful default
553 // initializations. They are only necessary for types that do not have a
554 // reasonable default constructor - explicitly char *, wchar_t * and T*.
555 // The string types don't have a reasonable default initializer since we store
556 // the underlying content, not a pointer.
557 // So we fully instantiate types for T* and const T* and set the pointers to
558 // NULL and leave other types intact.
559 template <Typename T>
560 class DbstlInitializeDefault
561 {
562 public:
DbstlInitializeDefault(T &)563 DbstlInitializeDefault(T&){}
564 };
565
566 template <Typename T>
567 class DbstlInitializeDefault<T *>
568 {
569 public:
DbstlInitializeDefault(T * & t)570 DbstlInitializeDefault(T *& t){t = NULL;}
571 };
572
573 template <Typename T>
574 class DbstlInitializeDefault<const T *>
575 {
576 public:
DbstlInitializeDefault(const T * & t)577 DbstlInitializeDefault(const T *& t){t = NULL;}
578 };
579
580 END_NS
581
582 #endif //_DB_STL_CONTAINER_H__
583