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