Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2024-05-18 08:29:45

0001 /*-
0002  * Copyright (c) 2009, 2020 Oracle and/or its affiliates.  All rights reserved.
0003  *
0004  * See the file LICENSE for license information.
0005  *
0006  * $Id$
0007  */
0008 
0009 #ifndef _DB_STL_CONTAINER_H__
0010 #define _DB_STL_CONTAINER_H__
0011 
0012 #include "dbstl_common.h"
0013 #include "dbstl_resource_manager.h"
0014 #include <assert.h>
0015 
0016 START_NS(dbstl)
0017 
0018 class ResourceManager;
0019 
0020 //////////////////////////////////////////////////////////////////////////
0021 //////////////////////////////////////////////////////////////////////////
0022 //
0023 // db_container class definition
0024 //
0025 // This class's begin_txn, commit/abort_txn is used to wrap each DB related
0026 // operation inside dbstl. When auto commit is enabled, each operation will
0027 // be auto committed before returning, and aborted when an exception is thrown.
0028 //
0029 // It also contains members to hold all needed parameters and flags for
0030 // transaction and cursor related calls.
0031 //
0032 // Container classes will inherit from this class. Each container will enclose
0033 // every db related operation with db_container::begin_txn and
0034 // db_container::commit_txn, and if exception is not caught, abort_txn()
0035 // should be called.
0036 
0037 /** \defgroup dbstl_containers dbstl container classes
0038 A dbstl container is very much like a C++ STL container. It stores a 
0039 collection of data items, or key/data pairs. 
0040 Each container is backed by a Berkeley DB database created in an explicit
0041 database environment or an internal private environment; And the database
0042 itself can be created explicitly with all kinds of configurations, or
0043 by dbstl internally. For each type of container, some specific type of 
0044 database and/or configurations must be used or specified to the database
0045 and its environment. dbstl will check the database and environment conform 
0046 to the requirement. When users don't have a chance to specify a container's
0047 backing database and environment, like in copy constructors, dbstl will
0048 create proper databases and/or environment for it. There are two helper 
0049 functions to make it easier to create/open an environment or database, they
0050 are dbstl::open_db() and dbstl::open_env();
0051 \sa dbstl::open_db() dbstl::open_env() db_vector db_map db_multimap db_set 
0052 db_multiset
0053 */
0054 
0055 /** \ingroup dbstl_containers
0056 @{
0057 This class is the base class for all db container classes, you don't directly
0058 use this class, but all container classes inherit from this class, so you need
0059 to know the methods that can be accessed via concrete container classes.
0060 This class is also used to support auto commit transactions. Autocommit is
0061 enabled when DB_AUTO_COMMIT is set to the database or database environment
0062 handle and the environment is transactional.
0063 
0064 Inside dbstl, there are transactions begun and committed/aborted if the backing
0065 database and/or environment requires auto commit, and there are cursors
0066 opened internally, and you can set the flags used by the transaction and cursor
0067 functions via set functions of this class.
0068 
0069 All dbstl containers are fully multi-threaded, you should not need any
0070 synchronization to use them in the correct way, but this class is not thread
0071 safe, access to its members are not proctected by any mutex because the data
0072 members of this class are supposed to be set before they are used, 
0073 and remain read only afterwards. If this is not the case, you must synchronize
0074 the access.
0075 */
0076 class _exported db_container
0077 {
0078 private:
0079     // By default these flags are 0, users should configure these values
0080     // on container initialization.
0081     //
0082     u_int32_t txn_begin_flags_, commit_flags_;
0083     mutable u_int32_t cursor_oflags_;
0084 
0085     // Berkeley DB database handle for each container. Subclasses do not
0086     // need to define it.
0087     //
0088     Db *pdb_;
0089 
0090     // Berkeley DB environment handle in which the db handle is opened.
0091     DbEnv *dbenv_;
0092 
0093     // db_map_iterator<> needs to know whether the container is a
0094     // db_(multi)set or not
0095     //
0096     bool is_set_;
0097 
0098     // Determined automatically, by inspecting users the Berkeley DB
0099     // database and environment configuration options.
0100     //
0101     bool auto_commit_;
0102 
0103     // If exisiting random temporary database name generation mechanism is
0104     // still causing name clashes, users can set this global suffix number
0105     // which will be append to each temporary database file name and by 
0106     // default it is 0. there is a dbstl::set_global_dbfile_suffix_number
0107     // to do so.
0108     static u_int32_t g_db_file_suffix_;
0109     friend void set_global_dbfile_suffix_number(u_int32_t);
0110 protected:
0111 
0112     // Does not clone or copy data from database parameter.
0113     // Return the db file name back in the dbfname parameter.
0114     // We construct a default database name the user can rename it using
0115     // either DbEnv::dbrename or Db::rename.
0116     //
0117     Db* clone_db_config(Db *dbp, std::string &dbfname);
0118     Db* clone_db_config(Db *dbp);
0119 
0120     // Store the name into name parameter whose length is n. Return -1 if
0121     // not enough space.
0122     int construct_db_file_name(std::string &filename) const;
0123 
0124     // Check that this container and cntnr are backed by different databases
0125     // and if any one of them is using transactions, both should be in the
0126     // same transactional environment.
0127     // Called by all deriving classes' methods
0128     // which have a container parameter.
0129     void verify_db_handles(const db_container &cntnr) const;
0130 
0131     void open_db_handles(Db *&pdb, DbEnv *&penv, DBTYPE dbtype,
0132         u_int32_t oflags, u_int32_t sflags);
0133 
0134     inline void set_is_set(bool b)
0135     {
0136         is_set_ = b;
0137     }
0138 
0139     inline bool is_set() const
0140     {
0141         return is_set_;
0142     }
0143 
0144     // Database and environment handles and autocommit and is_set_ are 
0145     // not assigned, because they are the nature of my own db, not 
0146     // that of dbctnr.
0147     inline const db_container &operator=(const db_container & dbctnr)
0148     {
0149         ASSIGNMENT_PREDCOND(dbctnr)
0150         txn_begin_flags_ = dbctnr.txn_begin_flags_;
0151         commit_flags_ = dbctnr.commit_flags_;
0152         cursor_oflags_ = dbctnr.cursor_oflags_;
0153         return dbctnr;
0154     }
0155 
0156 public:
0157     /// Default constructor.
0158     db_container();
0159 
0160     /// Copy constructor.
0161     /// The new container will be backed by another database within the
0162     /// same environment unless dbctnr's backing database is in its own
0163     /// internal private environment. The name of the database is coined
0164     /// based on current time and thread id and some random number. If
0165     /// this is still causing naming clashes, you can set a suffix number
0166     /// via "set_global_dbfile_suffix_number" function; And following db
0167     /// file will suffix this number in the file name for additional 
0168     /// randomness. And the suffix will be incremented after each such use.
0169     /// You can change the file name via DbEnv::rename.
0170     /// If dbctnr is using an anonymous database, the newly constructed
0171     /// container will also use an anonymous one.
0172     /// \param dbctnr The container to initialize this container.
0173     db_container(const db_container &dbctnr);
0174 
0175     /**
0176     This constructor is not directly called by the user, but invoked by
0177     constructors of concrete container classes. The statement about the
0178     parameters applies to constructors of all container classes.
0179     \param dbp Database handle. dbp is supposed to be opened inside envp.
0180     Each dbstl container is backed by a Berkeley DB database, so dbstl 
0181     will create an internal anonymous database if dbp is NULL. 
0182     \param envp Environment handle. And envp can also be NULL, meaning the
0183     dbp handle may be created in its internal private environment.
0184     */
0185     db_container(Db *dbp, DbEnv *envp);
0186 
0187     /// The backing database is not closed in this function. It is closed
0188     /// when current thread exits and the database is no longer referenced
0189     /// by any other container instances in this process. 
0190     /// In order to make the reference counting work alright, you must call
0191     /// register_db(Db*) and register_db_env(DbEnv*) correctly.
0192     /// \sa register_db(Db*) register_db_env(DbEnv*) 
0193     virtual ~db_container(){}
0194 
0195     /// \name Get and set functions for data members.
0196     /// Note that these functions are not thread safe, because all data 
0197     /// members of db_container are supposed to be set on container 
0198     /// construction and initialization, and remain read only afterwards.
0199     //@{
0200     /// Get the backing database's open flags.
0201     /// \return The backing database's open flags.
0202     inline u_int32_t get_db_open_flags()   const
0203     {
0204         u_int32_t oflags;
0205         pdb_->get_open_flags(&oflags);
0206         return oflags;
0207     }
0208 
0209     /// Get the backing database's flags that are set via Db::set_flags()
0210     /// function.
0211     /// \return Flags set to this container's database handle.
0212     inline u_int32_t get_db_set_flags()   const
0213     {
0214         u_int32_t oflags;
0215         pdb_->get_flags(&oflags);
0216         return oflags;
0217     }
0218 
0219     /// Get the backing database's handle. 
0220     /// \return The backing database handle of this container.
0221     inline Db* get_db_handle() const
0222     {
0223         return pdb_;
0224     }
0225 
0226     /// Get the backing database environment's handle. 
0227     /// \return The backing database environment handle of this container.
0228     inline DbEnv* get_db_env_handle()  const
0229     {
0230         return dbenv_;
0231     }
0232 
0233     /** 
0234     Set the underlying database's handle, and optionally environment 
0235     handle if the environment has also changed. That is, users can change
0236     the container object's underlying database while the object is alive.
0237     dbstl will verify that the handles set conforms to the concrete 
0238     container's requirement to Berkeley DB database/environment handles.
0239     \param dbp The database handle to set.
0240     \param newenv The database environment handle to set.
0241     */
0242     void set_db_handle(Db *dbp, DbEnv *newenv = NULL);
0243 
0244     /** Set the flags required by the Berkeley DB functions 
0245     DbEnv::txn_begin(), DbTxn::commit() and DbEnv::cursor(). These flags
0246     will be set to this container's auto commit member functions when 
0247     auto commit transaction is used, except that cursor_oflags is set to 
0248     the Dbc::cursor when creating an iterator for this container.
0249     By default the three flags are all zero.
0250     You can also set the values of the flags individually by using the 
0251     appropriate set functions in this class. The corresponding get 
0252     functions return the flags actually used.
0253     \param txn_begin_flags Flags to be set to DbEnv::txn_begin().
0254     \param commit_flags Flags to be set to DbTxn::commit().
0255     \param cursor_open_flags Flags to be set to Db::cursor().
0256     */
0257     inline void set_all_flags(u_int32_t txn_begin_flags,
0258         u_int32_t commit_flags, u_int32_t cursor_open_flags)
0259     {
0260         this->txn_begin_flags_ = txn_begin_flags;
0261         this->commit_flags_ = commit_flags;
0262         this->cursor_oflags_ = cursor_open_flags;
0263     }
0264 
0265     /// Set flag of DbEnv::txn_begin() call.
0266     /// \param flag Flags to be set to DbEnv::txn_begin().
0267     inline void set_txn_begin_flags(u_int32_t flag )
0268     {
0269         txn_begin_flags_ = flag;
0270     }
0271 
0272     /// Get flag of DbEnv::txn_begin() call.
0273     /// \return Flags to be set to DbEnv::txn_begin().
0274     inline u_int32_t get_txn_begin_flags()  const
0275     {
0276         return txn_begin_flags_;
0277     }
0278 
0279     /// Set flag of DbTxn::commit() call.
0280     /// \param flag Flags to be set to DbTxn::commit().
0281     inline void set_commit_flags(u_int32_t flag)
0282     {
0283         commit_flags_ = flag;
0284     }
0285 
0286     /// Get flag of DbTxn::commit() call.
0287     /// \return Flags to be set to DbTxn::commit().
0288     inline u_int32_t get_commit_flags()  const
0289     {
0290         return commit_flags_;
0291     }
0292 
0293     /// Get flag of Db::cursor() call.
0294     /// \return Flags to be set to Db::cursor().
0295     inline u_int32_t get_cursor_open_flags()  const
0296     {
0297         return cursor_oflags_;
0298     }
0299 
0300     /// Set flag of Db::cursor() call.
0301     /// \param flag Flags to be set to Db::cursor().
0302     inline void set_cursor_open_flags(u_int32_t flag)
0303     {
0304         cursor_oflags_ = flag;
0305     }
0306     //@} // getter_setters
0307 
0308 protected:
0309     void init_members();
0310     void init_members(Db *pdb, DbEnv *env);
0311     void init_members(const db_container&cnt);
0312     // Called internally by concrete container constructors. Verification
0313     // is done by the specialized constructors
0314     void set_db_handle_int(Db *dbp, DbEnv *envp)
0315     {
0316         this->pdb_ = dbp;
0317         this->dbenv_ = envp;
0318     }
0319 
0320     // Child classes override this function to check the db and environment
0321     // handles are correctly configured.
0322     virtual const char* verify_config(Db* pdb, DbEnv* penv) const
0323     {
0324         if (pdb != NULL && ((pdb->get_create_flags() & 
0325             DB_CXX_NO_EXCEPTIONS) == 0))
0326             return 
0327 "Db and DbEnv object must be constructed with DB_CXX_NO_EXCEPTIONS flag set.";
0328 
0329         if (penv != NULL && ((penv->get_create_flags() & 
0330             DB_CXX_NO_EXCEPTIONS) == 0))
0331             return 
0332 "Db and DbEnv object must be constructed with DB_CXX_NO_EXCEPTIONS flag set.";
0333         return NULL;
0334     }
0335 
0336     // Use db and dbenv_ to determine whether to enable autocommit. If
0337     // DB_AUTOCOMMIT is set on dbenv_ or db and dbenv_ is transactional,
0338     // that db should be autocommit.
0339     //
0340     void set_auto_commit(Db* db);
0341 
0342     // Begin a transaction. Used to make a container's db related
0343     // operations auto commit when the operation completes and abort
0344     // when the operation fails. If there is already a transaction for this
0345     // container's environment, then that transaction is used. If the
0346     // transaction was created by DB STL, its reference count is
0347     // incremented (user created and external transactions are not
0348     // reference counted because they can be nested.).
0349     inline DbTxn* begin_txn() const
0350     {
0351         DbTxn *txn = NULL;
0352 
0353         if (this->auto_commit_) {
0354             txn = ResourceManager::instance()->begin_txn(
0355                 this->txn_begin_flags_, dbenv_, 0);
0356         }
0357         return txn;
0358     }
0359 
0360     inline void commit_txn()  const
0361     {
0362         if (this->auto_commit_) {
0363             ResourceManager::instance()->
0364                 commit_txn(pdb_->get_env(), this->commit_flags_);
0365         }
0366     }
0367 
0368     inline void abort_txn() const
0369     {
0370         if (this->auto_commit_)
0371             ResourceManager::instance()->
0372                 abort_txn(pdb_->get_env());
0373     }
0374 
0375     inline DbTxn *current_txn() const
0376     {
0377         return ResourceManager::instance()->
0378             current_txn(pdb_->get_env());
0379     }
0380 }; // db_container
0381 /** @} */ // dbstl_containers
0382 
0383 /// \addtogroup dbstl_helper_classes
0384 //@{
0385 /// Bulk retrieval configuration helper class. Used by the begin() function of
0386 /// a container.
0387 class _exported BulkRetrievalOption
0388 {
0389 public:
0390     enum Option {BulkRetrieval, NoBulkRetrieval};
0391 
0392 protected:
0393     Option bulk_retrieve;
0394     u_int32_t bulk_buf_sz_;
0395 
0396     inline BulkRetrievalOption()
0397     {
0398         bulk_retrieve = NoBulkRetrieval;
0399         bulk_buf_sz_ = DBSTL_BULK_BUF_SIZE;
0400     }
0401 
0402 public:
0403     inline BulkRetrievalOption(Option bulk_retrieve1, 
0404         u_int32_t bulk_buf_sz = DBSTL_BULK_BUF_SIZE)
0405     {
0406         this->bulk_retrieve = bulk_retrieve1;
0407         this->bulk_buf_sz_ = bulk_buf_sz;
0408     }
0409 
0410     // The following two static members should best be const, but this is
0411     // impossible because in C++ this definition is a function declaration:
0412     // const static BulkRetrievalOption BulkRetrieval(BulkRetrieval);
0413     // i.e. const static members can only be inited with default copy
0414     // constructor.
0415     //
0416     // Static data members can't be compiled into a .lib for a dll on
0417     // Windows, code using the static members will have link error---
0418     // unresolved symbols, so we have to use a static function here.
0419     /// This function indicates that you need a bulk retrieval iterator, 
0420     /// and it can be also used to optionally set the bulk read buffer size.
0421     inline static BulkRetrievalOption bulk_retrieval(
0422         u_int32_t bulk_buf_sz = DBSTL_BULK_BUF_SIZE)
0423     {
0424         return BulkRetrievalOption(BulkRetrieval, bulk_buf_sz);
0425     }
0426   
0427     /// This function indicates that you do not need a bulk retrieval 
0428     /// iterator.
0429     inline static BulkRetrievalOption no_bulk_retrieval()
0430     {
0431         return BulkRetrievalOption(NoBulkRetrieval, 0);
0432     }
0433   
0434     /// Equality comparison.
0435     inline bool operator==(const BulkRetrievalOption& bro) const
0436     {
0437         return bulk_retrieve == bro.bulk_retrieve;
0438     }
0439   
0440     /// Assignment operator.
0441     inline void operator=(BulkRetrievalOption::Option opt)
0442     {
0443         bulk_retrieve = opt;
0444     }
0445   
0446     /// Return the buffer size set to this object.
0447     inline u_int32_t bulk_buf_size()
0448     {
0449         return bulk_buf_sz_;
0450     }
0451 };
0452 //@}
0453 
0454 /// \addtogroup dbstl_helper_classes
0455 //@{
0456 /// Read-modify-write cursor configuration helper class. Used by each begin()
0457 /// function of all containers.
0458 class _exported ReadModifyWriteOption
0459 {
0460 protected:
0461     enum Option{ReadModifyWrite, NoReadModifyWrite};
0462     Option rmw;
0463 
0464     inline ReadModifyWriteOption(Option rmw1)
0465     {
0466         this->rmw = rmw1;
0467     }
0468 
0469     inline ReadModifyWriteOption()
0470     {
0471         rmw = NoReadModifyWrite;
0472     }
0473 
0474 public:
0475     /// Assignment operator.
0476     inline void operator=(ReadModifyWriteOption::Option rmw1)
0477     {
0478         this->rmw = rmw1;
0479     }
0480 
0481     /// Equality comparison.
0482     inline bool operator==(const ReadModifyWriteOption &rmw1) const
0483     {
0484         return this->rmw == rmw1.rmw;
0485     }
0486 
0487     /// Call this function to tell the container's begin() function that
0488     /// you need a read-modify-write iterator.
0489     inline static ReadModifyWriteOption read_modify_write()
0490     {
0491         return ReadModifyWriteOption(ReadModifyWrite);
0492     }
0493 
0494     /// Call this function to tell the container's begin() function that
0495     /// you do not need a read-modify-write iterator. This is the default
0496     /// value for the parameter of any container's begin() function.
0497     inline static ReadModifyWriteOption no_read_modify_write()
0498     {
0499         return ReadModifyWriteOption(NoReadModifyWrite);
0500     }
0501 
0502 };
0503 //@} // dbstl_helper_classes
0504 
0505 // The classes in the Berkeley DB C++ API do not expose data and p_ member.
0506 // Extend the class to provide this functionality, rather than altering the
0507 // internal implementations.
0508 //
0509 class _exported DbstlMultipleIterator : protected DbMultipleIterator
0510 {
0511 protected:
0512     DbstlMultipleIterator(const Dbt &dbt) : DbMultipleIterator(dbt) {}
0513 public:
0514     u_int32_t get_pointer()
0515     {
0516         u_int32_t off;
0517         off = (u_int32_t)((u_int8_t*)p_ - data_);
0518         return off;
0519     }
0520 
0521     inline void set_pointer(u_int32_t offset)
0522     {
0523         p_ = (u_int32_t*)(data_ + offset);
0524     }
0525 
0526 };
0527 
0528 class _exported DbstlMultipleKeyDataIterator : public DbstlMultipleIterator
0529 {
0530 public:
0531     DbstlMultipleKeyDataIterator(const Dbt &dbt)
0532         : DbstlMultipleIterator(dbt) {}
0533     bool next(Dbt &key, Dbt &data);
0534 };
0535 
0536 class _exported DbstlMultipleRecnoDataIterator : public DbstlMultipleIterator
0537 {
0538 public:
0539     DbstlMultipleRecnoDataIterator(const Dbt &dbt)
0540        : DbstlMultipleIterator(dbt) {}
0541     bool next(db_recno_t &recno, Dbt &data);
0542 };
0543 
0544 class _exported DbstlMultipleDataIterator : public DbstlMultipleIterator
0545 {
0546 public:
0547     DbstlMultipleDataIterator(const Dbt &dbt)
0548         : DbstlMultipleIterator(dbt) {}
0549     bool next(Dbt &data);
0550 };
0551 
0552 // These classes are used to give data values meaningful default
0553 // initializations. They are only necessary for types that do not have a
0554 // reasonable default constructor - explicitly char *, wchar_t * and T*.
0555 // The string types don't have a reasonable default initializer since we store
0556 // the underlying content, not a pointer.
0557 // So we fully instantiate types for T* and const T* and set the pointers to
0558 // NULL and leave other types intact.
0559 template <Typename T>
0560 class DbstlInitializeDefault
0561 {
0562 public:
0563     DbstlInitializeDefault(T&){}
0564 };
0565 
0566 template <Typename T>
0567 class DbstlInitializeDefault<T *>
0568 {
0569 public:
0570     DbstlInitializeDefault(T *& t){t = NULL;}
0571 };
0572 
0573 template <Typename T>
0574 class DbstlInitializeDefault<const T *>
0575 {
0576 public:
0577     DbstlInitializeDefault(const T *& t){t = NULL;}
0578 };
0579 
0580 END_NS
0581 
0582 #endif //_DB_STL_CONTAINER_H__