1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2009 Oracle.  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
16START_NS(dbstl)
17
18class 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
38A dbstl container is very much like a C++ STL container. It stores a
39collection of data items, or key/data pairs.
40Each container is backed by a Berkeley DB database created in an explicit
41database environment or an internal private environment; And the database
42itself can be created explicitly with all kinds of configurations, or
43by dbstl internally. For each type of container, some specific type of
44database and/or configurations must be used or specified to the database
45and its environment. dbstl will check the database and environment conform
46to the requirement. When users don't have a chance to specify a container's
47backing database and environment, like in copy constructors, dbstl will
48create proper databases and/or environment for it. There are two helper
49functions to make it easier to create/open an environment or database, they
50are dbstl::open_db() and dbstl::open_env();
51\sa dbstl::open_db() dbstl::open_env() db_vector db_map db_multimap db_set
52db_multiset
53*/
54
55/** \ingroup dbstl_containers
56@{
57This class is the base class for all db container classes, you don't directly
58use this class, but all container classes inherit from this class, so you need
59to know the methods that can be accessed via concrete container classes.
60This class is also used to support auto commit transactions. Autocommit is
61enabled when DB_AUTO_COMMIT is set to the database or database environment
62handle and the environment is transactional.
63
64Inside dbstl, there are transactions begun and committed/aborted if the backing
65database and/or environment requires auto commit, and there are cursors
66opened internally, and you can set the flags used by the transaction and cursor
67functions via set functions of this class.
68
69All dbstl containers are fully multi-threaded, you should not need any
70synchronization to use them in the correct way, but this class is not thread
71safe, access to its members are not proctected by any mutex because the data
72members of this class are supposed to be set before they are used,
73and remain read only afterwards. If this is not the case, you must synchronize
74the access.
75*/
76class _exported db_container
77{
78private:
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);
110protected:
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
156public:
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
308protected:
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.
387class _exported BulkRetrievalOption
388{
389public:
390	enum Option {BulkRetrieval, NoBulkRetrieval};
391
392protected:
393	Option bulk_retrieve;
394	u_int32_t bulk_buf_sz_;
395
396	inline BulkRetrievalOption()
397	{
398		bulk_retrieve = NoBulkRetrieval;
399		bulk_buf_sz_ = DBSTL_BULK_BUF_SIZE;
400	}
401
402public:
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.
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.
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.
458class _exported ReadModifyWriteOption
459{
460protected:
461	enum Option{ReadModifyWrite, NoReadModifyWrite};
462	Option rmw;
463
464	inline ReadModifyWriteOption(Option rmw1)
465	{
466		this->rmw = rmw1;
467	}
468
469	inline ReadModifyWriteOption()
470	{
471		rmw = NoReadModifyWrite;
472	}
473
474public:
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.
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.
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//
509class _exported DbstlMultipleIterator : protected DbMultipleIterator
510{
511protected:
512	DbstlMultipleIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {}
513public:
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
521	inline void set_pointer(u_int32_t offset)
522	{
523		p_ = (u_int32_t*)(data_ + offset);
524	}
525
526};
527
528class _exported DbstlMultipleKeyDataIterator : public DbstlMultipleIterator
529{
530public:
531	DbstlMultipleKeyDataIterator(const Dbt &dbt)
532	    : DbstlMultipleIterator(dbt) {}
533	bool next(Dbt &key, Dbt &data);
534};
535
536class _exported DbstlMultipleRecnoDataIterator : public DbstlMultipleIterator
537{
538public:
539	DbstlMultipleRecnoDataIterator(const Dbt &dbt)
540	   : DbstlMultipleIterator(dbt) {}
541	bool next(db_recno_t &recno, Dbt &data);
542};
543
544class _exported DbstlMultipleDataIterator : public DbstlMultipleIterator
545{
546public:
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.
559template <Typename T>
560class DbstlInitializeDefault
561{
562public:
563	DbstlInitializeDefault(T&){}
564};
565
566template <Typename T>
567class DbstlInitializeDefault<T *>
568{
569public:
570	DbstlInitializeDefault(T *& t){t = NULL;}
571};
572
573template <Typename T>
574class DbstlInitializeDefault<const T *>
575{
576public:
577	DbstlInitializeDefault(const T *& t){t = NULL;}
578};
579
580END_NS
581
582#endif //_DB_STL_CONTAINER_H__
583