summaryrefslogtreecommitdiff
path: root/stl/dbstl_container.h
diff options
context:
space:
mode:
authorKim Kibum <kb0929.kim@samsung.com>2012-05-21 17:40:46 +0900
committerKim Kibum <kb0929.kim@samsung.com>2012-05-21 17:40:46 +0900
commit2e082c838d2ca750f5daac6dcdabecc22dfd4e46 (patch)
tree01c1dd87d4cc0b62a655c0d768ff695d2d244728 /stl/dbstl_container.h
parenta86e3ca152fb414b376e64c449c201d762e414dd (diff)
downloaddb4-2e082c838d2ca750f5daac6dcdabecc22dfd4e46.tar.gz
db4-2e082c838d2ca750f5daac6dcdabecc22dfd4e46.tar.bz2
db4-2e082c838d2ca750f5daac6dcdabecc22dfd4e46.zip
Upload Tizen:Base source
Diffstat (limited to 'stl/dbstl_container.h')
-rw-r--r--stl/dbstl_container.h582
1 files changed, 582 insertions, 0 deletions
diff --git a/stl/dbstl_container.h b/stl/dbstl_container.h
new file mode 100644
index 0000000..279fe40
--- /dev/null
+++ b/stl/dbstl_container.h
@@ -0,0 +1,582 @@
+/*-
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#ifndef _DB_STL_CONTAINER_H__
+#define _DB_STL_CONTAINER_H__
+
+#include "dbstl_common.h"
+#include "dbstl_resource_manager.h"
+#include <assert.h>
+
+START_NS(dbstl)
+
+class ResourceManager;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//
+// db_container class definition
+//
+// This class's begin_txn, commit/abort_txn is used to wrap each DB related
+// operation inside dbstl. When auto commit is enabled, each operation will
+// be auto committed before returning, and aborted when an exception is thrown.
+//
+// It also contains members to hold all needed parameters and flags for
+// transaction and cursor related calls.
+//
+// Container classes will inherit from this class. Each container will enclose
+// every db related operation with db_container::begin_txn and
+// db_container::commit_txn, and if exception is not caught, abort_txn()
+// should be called.
+
+/** \defgroup dbstl_containers dbstl container classes
+A dbstl container is very much like a C++ STL container. It stores a
+collection of data items, or key/data pairs.
+Each container is backed by a Berkeley DB database created in an explicit
+database environment or an internal private environment; And the database
+itself can be created explicitly with all kinds of configurations, or
+by dbstl internally. For each type of container, some specific type of
+database and/or configurations must be used or specified to the database
+and its environment. dbstl will check the database and environment conform
+to the requirement. When users don't have a chance to specify a container's
+backing database and environment, like in copy constructors, dbstl will
+create proper databases and/or environment for it. There are two helper
+functions to make it easier to create/open an environment or database, they
+are dbstl::open_db() and dbstl::open_env();
+\sa dbstl::open_db() dbstl::open_env() db_vector db_map db_multimap db_set
+db_multiset
+*/
+
+/** \ingroup dbstl_containers
+@{
+This class is the base class for all db container classes, you don't directly
+use this class, but all container classes inherit from this class, so you need
+to know the methods that can be accessed via concrete container classes.
+This class is also used to support auto commit transactions. Autocommit is
+enabled when DB_AUTO_COMMIT is set to the database or database environment
+handle and the environment is transactional.
+
+Inside dbstl, there are transactions begun and committed/aborted if the backing
+database and/or environment requires auto commit, and there are cursors
+opened internally, and you can set the flags used by the transaction and cursor
+functions via set functions of this class.
+
+All dbstl containers are fully multi-threaded, you should not need any
+synchronization to use them in the correct way, but this class is not thread
+safe, access to its members are not proctected by any mutex because the data
+members of this class are supposed to be set before they are used,
+and remain read only afterwards. If this is not the case, you must synchronize
+the access.
+*/
+class _exported db_container
+{
+private:
+ // By default these flags are 0, users should configure these values
+ // on container initialization.
+ //
+ u_int32_t txn_begin_flags_, commit_flags_;
+ mutable u_int32_t cursor_oflags_;
+
+ // Berkeley DB database handle for each container. Subclasses do not
+ // need to define it.
+ //
+ Db *pdb_;
+
+ // Berkeley DB environment handle in which the db handle is opened.
+ DbEnv *dbenv_;
+
+ // db_map_iterator<> needs to know whether the container is a
+ // db_(multi)set or not
+ //
+ bool is_set_;
+
+ // Determined automatically, by inspecting users the Berkeley DB
+ // database and environment configuration options.
+ //
+ bool auto_commit_;
+
+ // If exisiting random temporary database name generation mechanism is
+ // still causing name clashes, users can set this global suffix number
+ // which will be append to each temporary database file name and by
+ // default it is 0. there is a dbstl::set_global_dbfile_suffix_number
+ // to do so.
+ static u_int32_t g_db_file_suffix_;
+ friend void set_global_dbfile_suffix_number(u_int32_t);
+protected:
+
+ // Does not clone or copy data from database parameter.
+ // Return the db file name back in the dbfname parameter.
+ // We construct a default database name the user can rename it using
+ // either DbEnv::dbrename or Db::rename.
+ //
+ Db* clone_db_config(Db *dbp, std::string &dbfname);
+ Db* clone_db_config(Db *dbp);
+
+ // Store the name into name parameter whose length is n. Return -1 if
+ // not enough space.
+ int construct_db_file_name(std::string &filename) const;
+
+ // Check that this container and cntnr are backed by different databases
+ // and if any one of them is using transactions, both should be in the
+ // same transactional environment.
+ // Called by all deriving classes' methods
+ // which have a container parameter.
+ void verify_db_handles(const db_container &cntnr) const;
+
+ void open_db_handles(Db *&pdb, DbEnv *&penv, DBTYPE dbtype,
+ u_int32_t oflags, u_int32_t sflags);
+
+ inline void set_is_set(bool b)
+ {
+ is_set_ = b;
+ }
+
+ inline bool is_set() const
+ {
+ return is_set_;
+ }
+
+ // Database and environment handles and autocommit and is_set_ are
+ // not assigned, because they are the nature of my own db, not
+ // that of dbctnr.
+ inline const db_container &operator=(const db_container & dbctnr)
+ {
+ ASSIGNMENT_PREDCOND(dbctnr)
+ txn_begin_flags_ = dbctnr.txn_begin_flags_;
+ commit_flags_ = dbctnr.commit_flags_;
+ cursor_oflags_ = dbctnr.cursor_oflags_;
+ return dbctnr;
+ }
+
+public:
+ /// Default constructor.
+ db_container();
+
+ /// Copy constructor.
+ /// The new container will be backed by another database within the
+ /// same environment unless dbctnr's backing database is in its own
+ /// internal private environment. The name of the database is coined
+ /// based on current time and thread id and some random number. If
+ /// this is still causing naming clashes, you can set a suffix number
+ /// via "set_global_dbfile_suffix_number" function; And following db
+ /// file will suffix this number in the file name for additional
+ /// randomness. And the suffix will be incremented after each such use.
+ /// You can change the file name via DbEnv::rename.
+ /// If dbctnr is using an anonymous database, the newly constructed
+ /// container will also use an anonymous one.
+ /// \param dbctnr The container to initialize this container.
+ db_container(const db_container &dbctnr);
+
+ /**
+ This constructor is not directly called by the user, but invoked by
+ constructors of concrete container classes. The statement about the
+ parameters applies to constructors of all container classes.
+ \param dbp Database handle. dbp is supposed to be opened inside envp.
+ Each dbstl container is backed by a Berkeley DB database, so dbstl
+ will create an internal anonymous database if dbp is NULL.
+ \param envp Environment handle. And envp can also be NULL, meaning the
+ dbp handle may be created in its internal private environment.
+ */
+ db_container(Db *dbp, DbEnv *envp);
+
+ /// The backing database is not closed in this function. It is closed
+ /// when current thread exits and the database is no longer referenced
+ /// by any other container instances in this process.
+ /// In order to make the reference counting work alright, you must call
+ /// register_db(Db*) and register_db_env(DbEnv*) correctly.
+ /// \sa register_db(Db*) register_db_env(DbEnv*)
+ virtual ~db_container(){}
+
+ /// \name Get and set functions for data members.
+ /// Note that these functions are not thread safe, because all data
+ /// members of db_container are supposed to be set on container
+ /// construction and initialization, and remain read only afterwards.
+ //@{
+ /// Get the backing database's open flags.
+ /// \return The backing database's open flags.
+ inline u_int32_t get_db_open_flags() const
+ {
+ u_int32_t oflags;
+ pdb_->get_open_flags(&oflags);
+ return oflags;
+ }
+
+ /// Get the backing database's flags that are set via Db::set_flags()
+ /// function.
+ /// \return Flags set to this container's database handle.
+ inline u_int32_t get_db_set_flags() const
+ {
+ u_int32_t oflags;
+ pdb_->get_flags(&oflags);
+ return oflags;
+ }
+
+ /// Get the backing database's handle.
+ /// \return The backing database handle of this container.
+ inline Db* get_db_handle() const
+ {
+ return pdb_;
+ }
+
+ /// Get the backing database environment's handle.
+ /// \return The backing database environment handle of this container.
+ inline DbEnv* get_db_env_handle() const
+ {
+ return dbenv_;
+ }
+
+ /**
+ Set the underlying database's handle, and optionally environment
+ handle if the environment has also changed. That is, users can change
+ the container object's underlying database while the object is alive.
+ dbstl will verify that the handles set conforms to the concrete
+ container's requirement to Berkeley DB database/environment handles.
+ \param dbp The database handle to set.
+ \param newenv The database environment handle to set.
+ */
+ void set_db_handle(Db *dbp, DbEnv *newenv = NULL);
+
+ /** Set the flags required by the Berkeley DB functions
+ DbEnv::txn_begin(), DbTxn::commit() and DbEnv::cursor(). These flags
+ will be set to this container's auto commit member functions when
+ auto commit transaction is used, except that cursor_oflags is set to
+ the Dbc::cursor when creating an iterator for this container.
+ By default the three flags are all zero.
+ You can also set the values of the flags individually by using the
+ appropriate set functions in this class. The corresponding get
+ functions return the flags actually used.
+ \param txn_begin_flags Flags to be set to DbEnv::txn_begin().
+ \param commit_flags Flags to be set to DbTxn::commit().
+ \param cursor_open_flags Flags to be set to Db::cursor().
+ */
+ inline void set_all_flags(u_int32_t txn_begin_flags,
+ u_int32_t commit_flags, u_int32_t cursor_open_flags)
+ {
+ this->txn_begin_flags_ = txn_begin_flags;
+ this->commit_flags_ = commit_flags;
+ this->cursor_oflags_ = cursor_open_flags;
+ }
+
+ /// Set flag of DbEnv::txn_begin() call.
+ /// \param flag Flags to be set to DbEnv::txn_begin().
+ inline void set_txn_begin_flags(u_int32_t flag )
+ {
+ txn_begin_flags_ = flag;
+ }
+
+ /// Get flag of DbEnv::txn_begin() call.
+ /// \return Flags to be set to DbEnv::txn_begin().
+ inline u_int32_t get_txn_begin_flags() const
+ {
+ return txn_begin_flags_;
+ }
+
+ /// Set flag of DbTxn::commit() call.
+ /// \param flag Flags to be set to DbTxn::commit().
+ inline void set_commit_flags(u_int32_t flag)
+ {
+ commit_flags_ = flag;
+ }
+
+ /// Get flag of DbTxn::commit() call.
+ /// \return Flags to be set to DbTxn::commit().
+ inline u_int32_t get_commit_flags() const
+ {
+ return commit_flags_;
+ }
+
+ /// Get flag of Db::cursor() call.
+ /// \return Flags to be set to Db::cursor().
+ inline u_int32_t get_cursor_open_flags() const
+ {
+ return cursor_oflags_;
+ }
+
+ /// Set flag of Db::cursor() call.
+ /// \param flag Flags to be set to Db::cursor().
+ inline void set_cursor_open_flags(u_int32_t flag)
+ {
+ cursor_oflags_ = flag;
+ }
+ //@} // getter_setters
+
+protected:
+ void init_members();
+ void init_members(Db *pdb, DbEnv *env);
+ void init_members(const db_container&cnt);
+ // Called internally by concrete container constructors. Verification
+ // is done by the specialized constructors
+ void set_db_handle_int(Db *dbp, DbEnv *envp)
+ {
+ this->pdb_ = dbp;
+ this->dbenv_ = envp;
+ }
+
+ // Child classes override this function to check the db and environment
+ // handles are correctly configured.
+ virtual const char* verify_config(Db* pdb, DbEnv* penv) const
+ {
+ if (pdb != NULL && ((pdb->get_create_flags() &
+ DB_CXX_NO_EXCEPTIONS) == 0))
+ return
+"Db and DbEnv object must be constructed with DB_CXX_NO_EXCEPTIONS flag set.";
+
+ if (penv != NULL && ((penv->get_create_flags() &
+ DB_CXX_NO_EXCEPTIONS) == 0))
+ return
+"Db and DbEnv object must be constructed with DB_CXX_NO_EXCEPTIONS flag set.";
+ return NULL;
+ }
+
+ // Use db and dbenv_ to determine whether to enable autocommit. If
+ // DB_AUTOCOMMIT is set on dbenv_ or db and dbenv_ is transactional,
+ // that db should be autocommit.
+ //
+ void set_auto_commit(Db* db);
+
+ // Begin a transaction. Used to make a container's db related
+ // operations auto commit when the operation completes and abort
+ // when the operation fails. If there is already a transaction for this
+ // container's environment, then that transaction is used. If the
+ // transaction was created by DB STL, its reference count is
+ // incremented (user created and external transactions are not
+ // reference counted because they can be nested.).
+ inline DbTxn* begin_txn() const
+ {
+ DbTxn *txn = NULL;
+
+ if (this->auto_commit_) {
+ txn = ResourceManager::instance()->begin_txn(
+ this->txn_begin_flags_, dbenv_, 0);
+ }
+ return txn;
+ }
+
+ inline void commit_txn() const
+ {
+ if (this->auto_commit_) {
+ ResourceManager::instance()->
+ commit_txn(pdb_->get_env(), this->commit_flags_);
+ }
+ }
+
+ inline void abort_txn() const
+ {
+ if (this->auto_commit_)
+ ResourceManager::instance()->
+ abort_txn(pdb_->get_env());
+ }
+
+ inline DbTxn *current_txn() const
+ {
+ return ResourceManager::instance()->
+ current_txn(pdb_->get_env());
+ }
+}; // db_container
+/** @} */ // dbstl_containers
+
+/// \addtogroup dbstl_helper_classes
+//@{
+/// Bulk retrieval configuration helper class. Used by the begin() function of
+/// a container.
+class _exported BulkRetrievalOption
+{
+public:
+ enum Option {BulkRetrieval, NoBulkRetrieval};
+
+protected:
+ Option bulk_retrieve;
+ u_int32_t bulk_buf_sz_;
+
+ inline BulkRetrievalOption()
+ {
+ bulk_retrieve = NoBulkRetrieval;
+ bulk_buf_sz_ = DBSTL_BULK_BUF_SIZE;
+ }
+
+public:
+ inline BulkRetrievalOption(Option bulk_retrieve1,
+ u_int32_t bulk_buf_sz = DBSTL_BULK_BUF_SIZE)
+ {
+ this->bulk_retrieve = bulk_retrieve1;
+ this->bulk_buf_sz_ = bulk_buf_sz;
+ }
+
+ // The following two static members should best be const, but this is
+ // impossible because in C++ this definition is a function declaration:
+ // const static BulkRetrievalOption BulkRetrieval(BulkRetrieval);
+ // i.e. const static members can only be inited with default copy
+ // constructor.
+ //
+ // Static data members can't be compiled into a .lib for a dll on
+ // Windows, code using the static members will have link error---
+ // unresolved symbols, so we have to use a static function here.
+ /// This function indicates that you need a bulk retrieval iterator,
+ /// and it can be also used to optionally set the bulk read buffer size.
+ inline static BulkRetrievalOption bulk_retrieval(
+ u_int32_t bulk_buf_sz = DBSTL_BULK_BUF_SIZE)
+ {
+ return BulkRetrievalOption(BulkRetrieval, bulk_buf_sz);
+ }
+
+ /// This function indicates that you do not need a bulk retrieval
+ /// iterator.
+ inline static BulkRetrievalOption no_bulk_retrieval()
+ {
+ return BulkRetrievalOption(NoBulkRetrieval, 0);
+ }
+
+ /// Equality comparison.
+ inline bool operator==(const BulkRetrievalOption& bro) const
+ {
+ return bulk_retrieve == bro.bulk_retrieve;
+ }
+
+ /// Assignment operator.
+ inline void operator=(BulkRetrievalOption::Option opt)
+ {
+ bulk_retrieve = opt;
+ }
+
+ /// Return the buffer size set to this object.
+ inline u_int32_t bulk_buf_size()
+ {
+ return bulk_buf_sz_;
+ }
+};
+//@}
+
+/// \addtogroup dbstl_helper_classes
+//@{
+/// Read-modify-write cursor configuration helper class. Used by each begin()
+/// function of all containers.
+class _exported ReadModifyWriteOption
+{
+protected:
+ enum Option{ReadModifyWrite, NoReadModifyWrite};
+ Option rmw;
+
+ inline ReadModifyWriteOption(Option rmw1)
+ {
+ this->rmw = rmw1;
+ }
+
+ inline ReadModifyWriteOption()
+ {
+ rmw = NoReadModifyWrite;
+ }
+
+public:
+ /// Assignment operator.
+ inline void operator=(ReadModifyWriteOption::Option rmw1)
+ {
+ this->rmw = rmw1;
+ }
+
+ /// Equality comparison.
+ inline bool operator==(const ReadModifyWriteOption &rmw1) const
+ {
+ return this->rmw == rmw1.rmw;
+ }
+
+ /// Call this function to tell the container's begin() function that
+ /// you need a read-modify-write iterator.
+ inline static ReadModifyWriteOption read_modify_write()
+ {
+ return ReadModifyWriteOption(ReadModifyWrite);
+ }
+
+ /// Call this function to tell the container's begin() function that
+ /// you do not need a read-modify-write iterator. This is the default
+ /// value for the parameter of any container's begin() function.
+ inline static ReadModifyWriteOption no_read_modify_write()
+ {
+ return ReadModifyWriteOption(NoReadModifyWrite);
+ }
+
+};
+//@} // dbstl_helper_classes
+
+// The classes in the Berkeley DB C++ API do not expose data and p_ member.
+// Extend the class to provide this functionality, rather than altering the
+// internal implementations.
+//
+class _exported DbstlMultipleIterator : protected DbMultipleIterator
+{
+protected:
+ DbstlMultipleIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {}
+public:
+ u_int32_t get_pointer()
+ {
+ u_int32_t off;
+ off = (u_int32_t)((u_int8_t*)p_ - data_);
+ return off;
+ }
+
+ inline void set_pointer(u_int32_t offset)
+ {
+ p_ = (u_int32_t*)(data_ + offset);
+ }
+
+};
+
+class _exported DbstlMultipleKeyDataIterator : public DbstlMultipleIterator
+{
+public:
+ DbstlMultipleKeyDataIterator(const Dbt &dbt)
+ : DbstlMultipleIterator(dbt) {}
+ bool next(Dbt &key, Dbt &data);
+};
+
+class _exported DbstlMultipleRecnoDataIterator : public DbstlMultipleIterator
+{
+public:
+ DbstlMultipleRecnoDataIterator(const Dbt &dbt)
+ : DbstlMultipleIterator(dbt) {}
+ bool next(db_recno_t &recno, Dbt &data);
+};
+
+class _exported DbstlMultipleDataIterator : public DbstlMultipleIterator
+{
+public:
+ DbstlMultipleDataIterator(const Dbt &dbt)
+ : DbstlMultipleIterator(dbt) {}
+ bool next(Dbt &data);
+};
+
+// These classes are used to give data values meaningful default
+// initializations. They are only necessary for types that do not have a
+// reasonable default constructor - explicitly char *, wchar_t * and T*.
+// The string types don't have a reasonable default initializer since we store
+// the underlying content, not a pointer.
+// So we fully instantiate types for T* and const T* and set the pointers to
+// NULL and leave other types intact.
+template <Typename T>
+class DbstlInitializeDefault
+{
+public:
+ DbstlInitializeDefault(T&){}
+};
+
+template <Typename T>
+class DbstlInitializeDefault<T *>
+{
+public:
+ DbstlInitializeDefault(T *& t){t = NULL;}
+};
+
+template <Typename T>
+class DbstlInitializeDefault<const T *>
+{
+public:
+ DbstlInitializeDefault(const T *& t){t = NULL;}
+};
+
+END_NS
+
+#endif //_DB_STL_CONTAINER_H__