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