Back to home page

EIC code displayed by LXR

 
 

    


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

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_RESOURCE_MANAGER_H__
0010 #define _DB_STL_RESOURCE_MANAGER_H__
0011 
0012 #include <map>
0013 #include <vector>
0014 #include <stack>
0015 #include <set>
0016 
0017 #include "dbstl_common.h"
0018 #include "dbstl_inner_utility.h"
0019 
0020 START_NS(dbstl)
0021 
0022 class DbCursorBase;
0023 using std::map;
0024 using std::multimap;
0025 using std::set;
0026 using std::stack;
0027 
0028 ///////////////////////////////////////////////////////////////////////
0029 /////////////////////////////////////////////////////////////////////////
0030 //
0031 // ResourceManager class definition
0032 //
0033 // This class manages all the Berkeley DB handles and their mapping
0034 // relationship. When it's only thread-specific instance is destructed,
0035 // these handles are automatically closed in the correct order (the db and
0036 // dbenv handles will be closed when the last thread using the handles in
0037 // the process is destructed).
0038 //
0039 // The Db* and DbEnv* handles are process-wide global, they can be shared
0040 // among multithreads, so they are stored into a static stl map, and access
0041 // to the two map objects (open_dbs_ & open_envs_) is protected by a process
0042 // wide mutex because few stl implementations support multithreaded access.
0043 // We use reference counting in the two map objects to make sure each handle
0044 // is closed when the last thread using it exits. Each thread sharing the
0045 // handle should call ResourceManager::register_db/dbenv to tell DBSTL that
0046 // it will use the handle, otherwise the handle may be closed prematurely.
0047 //
0048 // The transaction and cursor handles are thread specific. They are stored
0049 // into stl containers and each instance of the ResourceManager is stored
0050 // into thread local storage(TLS) of each thread. Thus the DB STL containers
0051 // are thread safe.
0052 //
0053 
0054 // This map contains cursors of all open databases opened in the same thread.
0055 // We can only duplicate a cursor of the same database; We don't allow sharing
0056 // Berkeley DB cursor handles across multiple threads, each thread needs to
0057 // open their own cursor handle;
0058 //
0059 typedef map<Db *, set<dbstl::DbCursorBase *> *> db_csr_map_t;
0060 
0061 // The set of cursors that belong to a db handle or a transaction.
0062 typedef set<dbstl::DbCursorBase *> csrset_t;
0063 // The cursors opened in each transaction.
0064 typedef map<DbTxn *, set<DbCursorBase *> *> txncsr_t;
0065 
0066 // This stack contains the transactions started in current thread. Each
0067 // transaction is the child transaction of the one under it in the stack.
0068 //
0069 // We support nested transactions for those created by the dbstl
0070 // users, but still keep reference counting for dbstl internally
0071 // created transactions so that the autocommit methods are really
0072 // autocommit with least overhead (nested transactions are overheads). The
0073 // way we keep both nested transaction and reference counting to internal
0074 // transactions in the same stack is:
0075 // 1. When creating an external transaction, look at the stack top, if there
0076 // is a transaction, it must be an external one too, so use it as the parent
0077 // transaction to create the external transaction.
0078 // 2. When creating an internal transaction, look at the stack top, if there
0079 // is one, call it T, look for its the reference counting, if there is a
0080 // reference count for it, T is an internal one, so we increment its
0081 // reference count; Otherwise, T is an external one, and according to the DB
0082 // autocommit semantics, this function should be in T's context, so we
0083 // simply use T and add it to the reference counting structure, and set its
0084 // reference count to 2.
0085 //
0086 // We don't support expanding a transaction across multiple threads,
0087 // because there are many restrictions to doing so, making it meaningless.
0088 //
0089 typedef stack<DbTxn *> txnstk_t;
0090 typedef map<DbEnv *, txnstk_t> env_txns_t;
0091 
0092 #ifdef WIN32
0093 #pragma warning( push )
0094 #pragma warning( disable:4251 )
0095 #endif
0096 // This class is used to wrap a ResourceManager instance pointer, so that
0097 // each thread has its own ResourceManager singleton.
0098 
0099 #ifdef TLS_DECL_MODIFIER
0100 template <Typename T>
0101 class TlsWrapper
0102 {
0103 public:
0104     static T *get_tls_obj()
0105     {
0106         return tinst_;
0107     }
0108 
0109     static void set_tls_obj(T *objp)
0110     {
0111         tinst_ = objp;
0112     }
0113 
0114 private:
0115     TlsWrapper(){}
0116 
0117     // Thread local pointer to the instance of type T.
0118     static TLS_DECL_MODIFIER T *tinst_;
0119 }; // TlsWrapper<>
0120 
0121 #elif defined(HAVE_PTHREAD_TLS)
0122 template <Typename T>
0123 class TlsWrapper
0124 {
0125 public:
0126     static T *get_tls_obj()
0127     {
0128         return static_cast<T*>(pthread_getspecific(tls_key_));
0129     }
0130 
0131     static void set_tls_obj(T *objp)
0132     {
0133         pthread_setspecific(tls_key_, objp);
0134     }
0135 
0136     // Friend declarations don't work portably, so we have to declare 
0137     // tls_key_ public.
0138     static pthread_key_t tls_key_;
0139 private:
0140     TlsWrapper();
0141 
0142 }; // TlsWrapper<>
0143 
0144 #else
0145 #error "A multi-threaded build of STL for Berkeley DB requires thread local storage.  None is configured."
0146 #endif
0147 
0148 class _exported ResourceManager : public DbstlGlobalInnerObject
0149 {
0150 private:
0151 
0152     ResourceManager(void);
0153     // open_dbs_ & open_envs_ are shared among threads, protected by
0154     // ghdl_mtx;
0155     static map<Db *, size_t> open_dbs_;
0156     static map<DbEnv *, size_t>open_envs_;
0157 
0158     // Transaction stack of all environments. Use a stack to allow nested
0159     // transactions. The transaction at the top of the stack is the
0160     // current active transaction.
0161     //
0162     env_txns_t env_txns_;
0163 
0164     // Cursors opened in a corresponding transaction context. When
0165     // committing or aborting a transaction, first close all open cursors.
0166     //
0167     txncsr_t txn_csrs_;
0168 
0169     // If in container X, its methods X::A and X::B both call begin and
0170     // commit transaction. X::A calls X::B after it's begin transaction
0171     // call, then X::B will commit the transaction prematurally. To avoid
0172     // will commit the only transaction prematurally, to avoid this, we use
0173     // this, we use this map to record each transaction's reference count.
0174     // Each begin/commit_txn() will increment/decrement the reference
0175     // count, when reference count goes to 0, the transaction is committed.
0176     // Abort_txn will unconditionally abort the transaction.
0177     //
0178     map<DbTxn *, size_t> txn_count_;
0179 
0180     // Contains the cursors opened in the current thread for each database,
0181     // So that we can close them in the right way, freeing any Berkeley DB
0182     // handles before exiting.
0183     //
0184     db_csr_map_t all_csrs_;
0185 
0186     // Remove cursors opened in the transaction txn's context, should be
0187     // called before commiting or aborting a transaction.
0188     //
0189     void remove_txn_cursor(DbTxn *txn);
0190 
0191     // Add a cursor to the current transaction's set of open cursors.
0192     void add_txn_cursor(DbCursorBase *dcbcsr, DbEnv *env);
0193 
0194     // The environment mtx_env_ and mtx_handle_ are used for synchronizing
0195     // multiple threads' access to open_dbs_ and open_envs_ and glob_objs_.
0196     // They are discarded when program exits, no deallocation/release
0197     // is done.
0198     static DbEnv *mtx_env_;
0199     static db_mutex_t mtx_handle_;
0200     static db_mutex_t mtx_globj_;
0201     static set<DbstlGlobalInnerObject *> glob_objs_;
0202 
0203     // This set stores db handles that are new'ed by open_db, and thus 
0204     // should be deleted after this db is closed automatically by dbstl.
0205     // If a db is new'ed and created by user without using open_db, users
0206     // should delete it.
0207     static set<Db *> deldbs; 
0208     static set<DbEnv *> delenvs; // Similar to deldbs, works with open_envs.
0209     static void set_global_callbacks();
0210 public:
0211     
0212     // This function should be called in a single thread inside a process, 
0213     // before any use of dbstl.
0214     static void global_startup();
0215     // Delete registered DbstlGlobalInnerObject objects.
0216     static void global_exit();
0217 
0218     // Delete the ResourceManager singleton of current thread, and remove it 
0219     // from glob_objs.
0220     static void thread_exit();
0221     static void register_global_object(DbstlGlobalInnerObject *gio);
0222     static DbEnv *get_mutex_env() { return mtx_env_; }
0223     // Lock mtx_handle_, if it is 0, allocate it first.
0224     static int global_lock(db_mutex_t dbcontainer_mtx);
0225     static int global_unlock(db_mutex_t dbcontainer_mtx);
0226     // Close pdb regardless of its reference count, users must make sure
0227     // pdb is not used by others before calling this method. We can't
0228     // close by reference count in this method, otherwise when the thread
0229     // exits pdb's reference count is decremented twice.
0230     void close_db(Db *pdb);
0231 
0232     // Close all db handles regardless of reference count, used to clean up
0233     // the calling thread's ResourceManager singleton.
0234     void close_all_dbs();
0235 
0236     // Close specified db env handle and remove it from resource manager.
0237     void close_db_env(DbEnv *penv);
0238 
0239     // Close and remove all db env registered in the resource manager.
0240     // Used to clean up the calling thread's ResourceManager singleton.
0241     void close_all_db_envs();
0242 
0243     // Begin a new transaction in the specified environment. When outtxn
0244     // is non-zero support nested transactions - the new transaction will
0245     // be started as a child of the current transaction. If outtxn is 0
0246     // we are starting an internal transaction for autocommit, no new
0247     // transaction will be started, but the current transaction's
0248     // reference count will be incremented if it already has a reference
0249     // count; otherwise, it was created by user, and we simply use this
0250     // transaction, set its reference count to 2.
0251     //
0252     // This function is called by both containers to begin an internal
0253     // transaction for autocommit, and by db stl users to begin an
0254     // external transaction.
0255     //
0256     DbTxn *begin_txn(u_int32_t flags/* flags for DbEnv::txn_begin */,
0257         DbEnv *env, int outtxn);
0258 
0259     // Decrement reference count if it exists and if it goes to 0, commit
0260     // current transaction T opened in env;
0261     // If T has no reference count(outside transaction), simply find
0262     // it by popping the stack and commit it.
0263     //
0264     // This function is called by db_container to commit a transaction
0265     // for auto commit, also can be called by db stl user to commit
0266     // an external explicit transaction.
0267     //
0268     void commit_txn(DbEnv *env, u_int32_t flags = 0);
0269 
0270     // Commit specified transaction txn: find it by popping the stack,
0271     // discard all its child transactions and commit it.
0272     //
0273     // This function is called by dbstl user to commit an external
0274     // explicit transaction.
0275     //
0276     void commit_txn(DbEnv *env, DbTxn *txn, u_int32_t flags = 0);
0277 
0278     // Abort current transaction of the environment.
0279     //
0280     void abort_txn(DbEnv *env);
0281 
0282     // Abort specified transaction: find it by popping the stack, discard
0283     // all its child transactions and abort it.
0284     //
0285     // This function is called by dbstl user to abort an external
0286     // explicit transaction.
0287     //
0288     void abort_txn(DbEnv *env, DbTxn *txn);
0289 
0290     // Set env's current transaction handle. The original transaction
0291     // handle is returned without aborting or commiting. This API can be
0292     // used to share a transaction handle among multiple threads.
0293     DbTxn* set_current_txn_handle(DbEnv *env, DbTxn *newtxn);
0294 
0295     // Register a Db handle. This handle and handles opened in it
0296     // will be closed by ResourceManager, so application code must not
0297     // try to close or delete it. Users can configure the handle before
0298     // opening the Db and then register it via this function.
0299     //
0300     void register_db(Db *pdb1);
0301 
0302     // Register a DbEnv handle. This handle and handles opened in it
0303     // will be closed by ResourceManager, so application code must not try
0304     // to close or delete it. Users can configure the handle before
0305     // opening the Environment and then register it via this function.
0306     //
0307     void register_db_env(DbEnv *env1);
0308 
0309     // Helper function to open a database and register it into
0310     // ResourceManager.
0311     // Users can set the create flags, open flags, db type, and flags
0312     // needing to be set before open.
0313     //
0314     Db* open_db (DbEnv *penv, const char *filename, DBTYPE dbtype,
0315         u_int32_t oflags, u_int32_t set_flags, int mode = 0644,
0316         DbTxn* txn = NULL, u_int32_t cflags = 0,
0317         const char *dbname = NULL);
0318 
0319     // Helper function to open a dbenv and register it into
0320     // ResourceManager.
0321     // Users can set the create flags, open flags, db type, and flags
0322     // needing to be set before open.
0323     //
0324     DbEnv *open_env(const char *env_home, u_int32_t set_flags,
0325         u_int32_t oflags = DB_CREATE | DB_INIT_MPOOL,
0326         u_int32_t cachesize = 4 * 1024 * 1024, int mode = 0644,
0327         u_int32_t cflags = 0/* Flags for DbEnv constructor. */);
0328 
0329     static ResourceManager *instance();
0330 
0331     // Release all registered resource in the right order.
0332     virtual ~ResourceManager(void);
0333 
0334     // Return current transaction of environment env, that is, the one on
0335     // the transaction stack top, the active one.
0336     //
0337     DbTxn *current_txn(DbEnv *env);
0338 
0339     // Open a Berkeley DB cursor.
0340     //
0341     int open_cursor(DbCursorBase *dcbcsr, Db *pdb, int flags = 0);
0342 
0343     // Add a db-cursor mapping.
0344     void add_cursor(Db *dbp, DbCursorBase *csr);
0345 
0346     // Close all cursors opened in the database.
0347     size_t close_db_cursors(Db *dbp1);
0348 
0349     // Close and remove a cursor from ResourceManager.
0350     //
0351     int remove_cursor(DbCursorBase *csr, bool remove_from_txncsrs = true);
0352 
0353 }; // ResourceManager
0354 
0355 END_NS
0356 #ifdef WIN32
0357 #pragma warning( pop )
0358 #endif
0359 #endif // !_DB_STL_RESOURCE_MANAGER_H__