2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 2009, 2012 Oracle and/or its affiliates. All rights reserved.
16 #include "dbstl_common.h"
17 #include "dbstl_dbt.h"
18 #include "dbstl_exception.h"
19 #include "dbstl_container.h"
20 #include "dbstl_resource_manager.h"
24 // Forward declarations.
27 template<Typename data_dt>
29 class DbstlMultipleKeyDataIterator;
30 class DbstlMultipleRecnoDataIterator;
33 /////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////
36 // LazyDupCursor class template definition.
38 // This class allows us to make a shallow copy on construction. When the
39 // cursor pointer is first dereferenced a deep copy is made.
41 // The allowed type for BaseType is DbCursor<> and RandDbCursor<>
42 // The expected usage of this class is:
43 // 1. Create an iterator in container::begin(), the iterator::pcsr.csr_ptr_
44 // points to an object, thus no need to duplicate.
45 // 2. The iterator is created with default argument, thus the
46 // iterator::pcsr.csr_ptr_ and dup_src_ is NULL, and this iterator is
47 // copied using copy constructor for may be many times, but until the
48 // cursor is really used, no cursor is duplicated.
50 // There is an informing mechanism between an instance of this class and
51 // its dup_src_ cursor: when that cursor is about to change state, it will
52 // inform all registered LazyDupCursor "listeners" of the change, so that
53 // they will duplicate from the cursor before the change, because that
54 // is the expected cursor state for the listeners.
56 template <Typename BaseType>
59 // dup_src_ is used by this class internally to duplicate another
60 // cursor and set to csr_ptr_, and it is assigned in the copy
61 // constructor from another LazyDupCursor object's csr_ptr_; csr_ptr_
62 // is the acutual pointer that is used to perform cursor operations.
64 BaseType *csr_ptr_, *dup_src_;
65 typedef LazyDupCursor<BaseType> self;
68 ////////////////////////////////////////////////////////////////////
70 // Begin public constructors and destructor.
72 inline LazyDupCursor()
78 // Used in all iterator types' constructors, dbcptr is created
79 // solely for this object, and the cursor is not yet opened, so we
80 // simply assign it to csr_ptr_.
81 explicit inline LazyDupCursor(BaseType *dbcptr)
84 // Already have pointer, do not need to duplicate.
88 // Do not copy to csr_ptr_, shallow copy from dp2.csr_ptr_.
89 LazyDupCursor(const self& dp2)
93 dup_src_ = dp2.csr_ptr_;
95 dup_src_ = dp2.dup_src_;
97 dup_src_->add_dupper(this);
102 // Not duplicated yet, remove from dup_src_.
103 if (csr_ptr_ == NULL && dup_src_ != NULL)
104 dup_src_->erase_dupper(this);
106 delete csr_ptr_;// Delete the cursor.
109 ////////////////////////////////////////////////////////////////////
112 inline const self& operator=(const self &dp2)
116 dcb = dp2.csr_ptr_ ? dp2.csr_ptr_ : dp2.dup_src_;
117 this->operator=(dcb);
123 inline BaseType *operator=(BaseType *dcb)
127 // Only dup_src_ will inform this, not csr_ptr_.
133 csr_ptr_ = new BaseType(*dcb);
134 if (dup_src_ != NULL) {
135 dup_src_->erase_dupper(this);
142 void set_cursor(BaseType *dbc)
146 // Only dup_src_ will inform this, not csr_ptr_.
152 if (dup_src_ != NULL) {
153 dup_src_->erase_dupper(this);
158 // If dup_src_ is informing this object, pass false parameter.
159 inline BaseType* duplicate(bool erase_dupper = true)
161 assert(dup_src_ != NULL);
163 // Only dup_src_ will inform this, not csr_ptr_.
167 csr_ptr_ = new BaseType(*dup_src_);
169 dup_src_->erase_dupper(this);
174 inline BaseType* operator->()
182 inline operator bool()
184 return csr_ptr_ != NULL;
187 inline bool operator!()
192 inline bool operator==(void *p)
194 return csr_ptr_ == p;
197 inline BaseType* base_ptr(){
205 /////////////////////////////////////////////////////////////////////////
206 /////////////////////////////////////////////////////////////////////////
208 // DbCursorBase class definition.
210 // DbCursorBase is the base class for DbCursor<> class template, this class
211 // wraps the Berkeley DB cursor, in order for the ResourceManager to close
212 // the Berkeley DB cursor and set the pointer to null.
213 // If we don't set the cursor to NULL, the handle could become valid again,
214 // since Berkeley DB recycles handles. DB STL would then try to use the same
215 // handle across different instances, which is not supported.
217 // In ResourceManager, whenver a cursor is opened, it stores the
218 // DbCursorBase* pointer, so that when need to close the cursor, it calls
219 // DbCursorBase::close() function.
230 enum DbcGetSkipOptions{SKIP_KEY, SKIP_DATA, SKIP_NONE};
231 inline DbTxn *get_owner_txn() const { return owner_txn_;}
232 inline void set_owner_txn(DbTxn *otxn) { owner_txn_ = otxn;}
234 inline Db *get_owner_db() const { return owner_db_;}
235 inline void set_owner_db(Db *odb) { owner_db_ = odb;}
237 inline Dbc *get_cursor() const { return csr_;}
238 inline Dbc *&get_cursor_reference() { return csr_;}
239 inline void set_cursor(Dbc*csr1)
242 ResourceManager::instance()->remove_cursor(this);
250 if (csr_ != NULL && (((DBC *)csr_)->flags & DBC_ACTIVE) != 0) {
264 DbCursorBase(const DbCursorBase &csrbase)
266 this->operator=(csrbase);
269 const DbCursorBase &operator=(const DbCursorBase &csrbase)
271 owner_txn_ = csrbase.owner_txn_;
272 owner_db_ = csrbase.owner_db_;
273 csr_ = NULL; // Need to call DbCursor<>::dup to duplicate.
278 virtual ~DbCursorBase()
284 ////////////////////////////////////////////////////////////////////////
285 ///////////////////////////////////////////////////////////////////////
287 // DbCursor class template definition
289 // DbCursor is the connection between Berkeley DB and dbstl container classes
290 // it is the wrapper class for Dbc* cursor of Berkeley Db, to be used for
291 // iterator classes of Berkeley DB backed STL container classes.
293 // 1. Deep copy using Dbc->dup.
294 // 2. Dbc*cursor management via ResourceManager class.
295 // 3. Provide methods to do increment, decrement and advance operations,
296 // advance is only available for random access iterator from DB_RECNO
300 template<typename key_dt, typename data_dt>
301 class DbCursor : public DbCursorBase{
303 // Lazy duplication support: store the LazyDupCursor objects which
304 // will duplicate from this cursor.
305 typedef LazyDupCursor<DbCursor<key_dt, data_dt> > dupper_t;
306 typedef LazyDupCursor<RandDbCursor<data_dt> > dupperr_t;
307 typedef set<LazyDupCursor<DbCursor<key_dt, data_dt> >* > dupset_t;
308 typedef set<LazyDupCursor<RandDbCursor<data_dt> >* > dupsetr_t;
310 set<LazyDupCursor<DbCursor<key_dt, data_dt> >* > sduppers1_;
311 set<LazyDupCursor<RandDbCursor<data_dt> >* > sduppers2_;
313 // We must use DB_DBT_USERMEM for Dbc::get and Db::get if they are
314 // used in multi-threaded application, so we use key_buf_ and
315 // data_buf_ data members for get operations, and initialize them
316 // to use user memory.
317 Dbt key_buf_, data_buf_;
319 // Similar to Berkeley DB C++ API's classes, used to iterate through
320 // bulk retrieved key/data pairs.
321 DbstlMultipleKeyDataIterator *multi_itr_;
322 DbstlMultipleRecnoDataIterator *recno_itr_;
324 // Whether to use bulk retrieval. If non-zero, do bulk retrieval,
325 // bulk buffer size is this member, otherwise not bulk read.
326 // By default this member is 0.
327 u_int32_t bulk_retrieval_;
328 // Whether to use DB_RMW flag in Dbc::get, by default false.
331 // Whether to poll data from cursor's current position on every
332 // get_current_key/data call.
333 // Note that curr_key_/curr_data_ members are always maintained
334 // to contain current k/d value of the pair pointed to by csr_.
335 // If doing bulk retrieval, this flag is ignored, we will always
336 // read data from bulk buffer.
339 // Inform LazyDupCursor objects registered in this object to do
340 // duplication because this cursor is to be changed.
341 // This function should be called in any function of
342 // DbCursor and RandDbCursor whenever the cursor is about to change
343 // state(move/close, etc).
344 inline void inform_duppers()
346 typename dupset_t::iterator i1;
347 typename dupsetr_t::iterator i2;
348 for (i1 = sduppers1_.begin(); i1 != sduppers1_.end(); i1++)
349 (*i1)->duplicate(false);
350 for (i2 = sduppers2_.begin(); i2 != sduppers2_.end(); i2++)
351 (*i2)->duplicate(false);
357 friend class DataItem;
359 // Current key/data pair pointed by "csr_" Dbc*cursor. They are both
360 // maintained on cursor movement. If directdb_get_ is true,
361 // they are both refreshed on every get_current{[_key][_data]} call and
362 // the retrieved key/data pair is returned to user.
366 typedef DbCursor<key_dt, data_dt> self;
368 // This function is used by all iterators to do equals comparison.
369 // Random iterators will also use it to do less than/greater than
371 // Internally, the page number difference or index difference is
372 // returned, so for btree and hash databases, if two cursors point to
373 // the same key/data pair, we will get 0 returned, meaning they are
374 // equal; if return value is not 0, it means no more than that they
375 // they are not equal. We can't assume any order information between
376 // the two cursors. For recno databases, we use the recno to do less
377 // than and greater than comparison. So we can get a reliable knowledge
378 // of the relative position of two iterators from the return value.
379 int compare(const self *csr2) const{
382 BDBOP(((DBC *)csr_)->cmp((DBC *)csr_, (DBC *)csr2->csr_,
387 ////////////////////////////////////////////////////////////////////
389 // Add and remove cursor change event listeners.
391 inline void add_dupper(dupper_t *dupper)
393 sduppers1_.insert(dupper);
396 inline void add_dupper(dupperr_t *dupper)
398 sduppers2_.insert(dupper);
401 inline void erase_dupper(dupper_t *dup1)
403 sduppers1_.erase(dup1);
406 inline void erase_dupper(dupperr_t *dup1)
408 sduppers2_.erase(dup1);
411 ////////////////////////////////////////////////////////////////////
415 inline bool get_rmw()
420 bool set_rmw(bool rmw, DB_ENV *env = NULL )
423 DB_ENV *dbenv = NULL;
429 dbenv = ((DBC*)csr_)->dbenv;
430 BDBOP(dbenv->get_open_flags(dbenv, &flag), ret);
432 // DB_RMW flag requires locking subsystem started.
433 if (rmw && ((flag & DB_INIT_LOCK) || (flag & DB_INIT_CDB) ||
434 (flag & DB_INIT_TXN)))
441 // Modify bulk buffer size. Bulk read is enabled when creating an
442 // iterator, so users later can only modify the bulk buffer size
443 // to another value, but can't enable/disable bulk read while an
444 // iterator is already alive.
445 // Returns true if succeeded, false otherwise.
446 inline bool set_bulk_buffer(u_int32_t sz)
448 if (bulk_retrieval_ && sz) {
449 normalize_bulk_bufsize(sz);
450 bulk_retrieval_ = sz;
458 inline u_int32_t get_bulk_bufsize()
460 return bulk_retrieval_;
463 inline void enlarge_dbt(Dbt &d, u_int32_t sz)
467 p = DbstlReAlloc(d.get_data(), sz);
468 dbstl_assert(p != NULL);
473 // Move forward or backward, often by 1 key/data pair, we can use
474 // different flags for Dbc::get function. Then update the key/data
475 // pair and csr_status_ members.
477 int increment(int flag)
480 Dbt &k = key_buf_, &d = data_buf_;
481 u_int32_t sz, getflags = 0, bulk_bufsz;
484 return INVALID_ITERATOR_CURSOR;
489 // Berkeley DB cursor flags are not bitwise set, so we can't
490 // use bit operations here.
492 if (this->bulk_retrieval_ != 0)
503 getflags |= DB_MULTIPLE_KEY;
504 if (data_buf_.get_ulen() != bulk_retrieval_)
505 enlarge_dbt(data_buf_, bulk_retrieval_);
512 // Do not use BDBOP or BDBOP2 here because it is likely
513 // that an iteration will step onto end() position.
514 retry: ret = csr_->get(&k, &d, flag | getflags);
516 if (bulk_retrieval_ && (getflags & DB_MULTIPLE_KEY)) {
517 // A new retrieval, so both multi_itr_ and
518 // recno_itr_ must be NULL.
519 if (((DBC*)csr_)->dbtype == DB_RECNO) {
525 new DbstlMultipleRecnoDataIterator(d);
532 DbstlMultipleKeyDataIterator(d);
535 // Non bulk retrieval succeeded.
536 curr_key_.set_dbt(k, false);
537 curr_data_.set_dbt(d, false);
538 limit_buf_size_after_use();
540 } else if (ret == DB_BUFFER_SMALL) {
541 // Either the key or data DBTs might trigger a
542 // DB_KEYSMALL return. Only enlarge the DBT if it
543 // is actually too small.
544 if (((sz = d.get_size()) > 0) && (sz > d.get_ulen()))
547 if (((sz = k.get_size()) > 0) && (sz > k.get_ulen()))
552 if (ret == DB_NOTFOUND) {
553 ret = INVALID_ITERATOR_POSITION;
554 this->curr_key_.reset();
555 this->curr_data_.reset();
556 } else if (bulk_retrieval_ &&
557 (getflags & DB_MULTIPLE_KEY)){
558 BDBOP(((DBC*)csr_)->dbp->
559 get_pagesize(((DBC*)csr_)->
560 dbp, &bulk_bufsz), ret);
561 if (bulk_bufsz > d.get_ulen()) {// buf size error
562 normalize_bulk_bufsize(bulk_bufsz);
563 bulk_retrieval_ = bulk_bufsz;
564 enlarge_dbt(d, bulk_bufsz);
568 "DbCursor<>::increment", ret);
571 "DbCursor<>::increment", ret);
578 // After each use of key_buf_ and data_buf_, limit their buffer size to
579 // a reasonable size so that they don't waste a big memory space.
580 inline void limit_buf_size_after_use()
583 // Bulk buffer has to be huge, so don't check it.
586 if (key_buf_.get_ulen() > DBSTL_MAX_KEY_BUF_LEN) {
587 key_buf_.set_data(DbstlReAlloc(key_buf_.get_data(),
588 DBSTL_MAX_KEY_BUF_LEN));
589 key_buf_.set_ulen(DBSTL_MAX_KEY_BUF_LEN);
591 if (data_buf_.get_ulen() > DBSTL_MAX_DATA_BUF_LEN) {
592 data_buf_.set_data(DbstlReAlloc(data_buf_.get_data(),
593 DBSTL_MAX_DATA_BUF_LEN));
594 data_buf_.set_ulen(DBSTL_MAX_DATA_BUF_LEN);
598 // Duplicate this object's cursor and set it to dbc1.
600 inline int dup(DbCursor<key_dt, data_dt>& dbc1) const
605 if (csr_ != 0 && csr_->dup(&pcsr, DB_POSITION) == 0) {
606 dbc1.set_cursor(pcsr);
607 dbc1.set_owner_db(this->get_owner_db());
608 dbc1.set_owner_txn(this->get_owner_txn());
609 ResourceManager::instance()->add_cursor(
610 this->get_owner_db(), &dbc1);
613 ret = ITERATOR_DUP_ERROR;
619 // Open a cursor, do not move it, it is at an invalid position.
620 // All cursors should be opened using this method.
622 inline int open(db_container *pdbc, int flags)
626 Db *pdb = pdbc->get_db_handle();
629 if (csr_) // Close before open.
631 ret = ResourceManager::instance()->
632 open_cursor(this, pdb, flags);
634 this->csr_status_ = ret;
638 // Move Berkeley DB cursor to specified key k, by default use DB_SET,
639 // but DB_SET_RANGE can and may also be used.
641 int move_to(const key_dt&k, u_int32_t flag = DB_SET)
646 DataItem k1(k, true);
649 return INVALID_ITERATOR_CURSOR;
655 // It is likely that k is not in db, causing get(DB_SET) to
656 // fail, we should not throw an exception because of this.
660 retry: ret = csr_->get(&k1.get_dbt(), &d1, flag);
663 curr_data_.set_dbt(d1, false);
664 limit_buf_size_after_use();
665 } else if (ret == DB_BUFFER_SMALL) {
671 if (ret == DB_NOTFOUND) {
672 ret = INVALID_ITERATOR_POSITION;
673 // Invalidate current values because it is
674 // at an invalid position.
675 this->curr_key_.reset();
676 this->curr_data_.reset();
678 throw_bdb_exception("DbCursor<>::move_to", ret);
685 // Returns the number of keys equal to the current one.
686 inline size_t count()
691 BDBOP2(csr_->count(&cnt, 0), ret, close());
695 int insert(const key_dt&k, const data_dt& d, int pos = DB_BEFORE)
698 // We do a deep copy of the input data into a local
699 // variable. Apparently not doing so causes issues
700 // when using gcc. Even though the put completes prior
701 // to returning from this function call.
702 // It would be best to avoid this additional copy.
704 // (k, d) pair may be a temporary pair, so we must copy them.
705 DataItem k1(k, false), d1(d, false);
708 if (pos == DB_AFTER) {
709 ret = this->csr_->put(&k1.get_dbt(), &d1.get_dbt(),
711 // May be using this flag for an empty database,
712 // because begin() an iterator of an empty db_vector
713 // equals its end() iterator, so use DB_KEYLAST to
716 if (ret == EINVAL || ret == 0)
719 throw_bdb_exception("DbCursor<>::insert", ret);
721 if (pos == DB_NODUPDATA)
722 BDBOP3(this->csr_->put(&k1.get_dbt(), &d1.get_dbt(),
723 pos), ret, DB_KEYEXIST, close());
725 BDBOP2(this->csr_->put(&k1.get_dbt(), &d1.get_dbt(),
727 this->csr_status_ = ret;
732 // This cursor points to the new key/data pair now.
736 // Replace current cursor-pointed data item with d.
737 inline int replace(const data_dt& d)
742 // We do a deep copy of the input data into a local
743 // variable. Apparently not doing so causes issues
744 // when using gcc. Even though the put completes prior
745 // to returning from this function call.
746 // It would be best to avoid this additional copy.
747 // d may be a temporary object, so we must copy it.
748 DataItem d1(d, false);
751 BDBOP2(this->csr_->put(&k1, &d1.get_dbt(), DB_CURRENT),
753 curr_data_ = d1; // Update current data.
755 this->csr_status_ = ret;
759 // Remove old key and insert new key-psuodo_data. First insert then
760 // move to old key and remove it so that the cursor remains at the
761 // old key's position, according to DB documentation.
762 // But from practice I can see
763 // the cursor after delete seems not at old position because a for
764 // loop iteration exits prematurelly, not all elements are passed.
766 inline int replace_key(const key_dt&k)
772 this->get_current_key_data(k0, d);
776 DbCursor<key_dt, data_dt> csr2;
778 // Delete current, then insert new key/data pair.
780 ret = csr2.insert(k, d, DB_KEYLAST);
781 this->csr_status_ = ret;
783 // Now this->csr_ is sitting on an invalid position, its
784 // iterator is invalidated. Must first move it to the next
785 // position before using it.
794 BDBOP2(csr_->del(0), ret, close());
796 // By default pos.csr_ will stay at where it was after delete,
797 // which now is an invalid position. So we need to move to
798 // next to conform to stl specifications, but we don't move it
799 // here, iterator::erase should move the iterator itself
802 this->csr_status_ = ret;
806 // Make sure the bulk buffer is large enough, and a multiple of 1KB.
807 // This function may be called prior to cursor initialization, it is
808 // not possible to verify that the buffer size is a multiple of the
810 u_int32_t normalize_bulk_bufsize(u_int32_t &bulksz)
815 while (bulksz < 16 * sizeof(data_dt))
818 bulksz = bulksz + 1024 - bulksz % 1024;
823 ////////////////////////////////////////////////////////////////////
825 // Begin public constructors and destructor.
827 explicit DbCursor(u_int32_t b_bulk_retrieval = 0, bool brmw1 = false,
828 bool directdbget = true) : DbCursorBase(),
829 curr_key_(sizeof(key_dt)), curr_data_(sizeof(data_dt))
831 u_int32_t bulksz = sizeof(data_dt); // non-bulk
833 this->bulk_retrieval_ =
834 normalize_bulk_bufsize(b_bulk_retrieval);
838 if (bulk_retrieval_) {
839 if (bulksz <= bulk_retrieval_)
840 bulksz = bulk_retrieval_;
842 normalize_bulk_bufsize(bulksz);
843 bulk_retrieval_ = bulksz;
846 key_buf_.set_data(DbstlMalloc(sizeof(key_dt)));
847 key_buf_.set_ulen(sizeof(key_dt));
848 key_buf_.set_flags(DB_DBT_USERMEM);
849 data_buf_.set_data(DbstlMalloc(bulksz));
850 data_buf_.set_ulen(bulksz);
851 data_buf_.set_flags(DB_DBT_USERMEM);
852 directdb_get_ = directdbget;
855 // Copy constructor, duplicate cursor here.
856 DbCursor(const DbCursor<key_dt, data_dt>& dbc) :
858 curr_key_(dbc.curr_key_), curr_data_(dbc.curr_data_)
863 csr_status_ = dbc.csr_status_;
864 if (csr_ || dbc.csr_)
865 this->rmw_get_ = set_rmw(dbc.rmw_get_,
866 ((DBC*)dbc.csr_)->dbenv);
868 rmw_get_ = dbc.rmw_get_;
870 bulk_retrieval_ = dbc.bulk_retrieval_;
872 // Now we have to copy key_buf_ and data_buf_ to support
873 // multiple retrieval.
874 key_buf_.set_data(pk = DbstlMalloc(dbc.key_buf_.get_ulen()));
875 key_buf_.set_ulen(dbc.key_buf_.get_ulen());
876 key_buf_.set_size(dbc.key_buf_.get_size());
877 key_buf_.set_flags(DB_DBT_USERMEM);
878 memcpy(pk, dbc.key_buf_.get_data(), key_buf_.get_ulen());
880 data_buf_.set_data(pd = DbstlMalloc(dbc.data_buf_.get_ulen()));
881 data_buf_.set_ulen(dbc.data_buf_.get_ulen());
882 data_buf_.set_size(dbc.data_buf_.get_size());
883 data_buf_.set_flags(DB_DBT_USERMEM);
884 memcpy(pd, dbc.data_buf_.get_data(), data_buf_.get_ulen());
885 if (dbc.recno_itr_) {
886 recno_itr_ = new DbstlMultipleRecnoDataIterator(
888 recno_itr_->set_pointer(dbc.recno_itr_->get_pointer());
891 if (dbc.multi_itr_) {
892 multi_itr_ = new DbstlMultipleKeyDataIterator(
894 multi_itr_->set_pointer(dbc.multi_itr_->get_pointer());
899 directdb_get_ = dbc.directdb_get_;
901 // Do not copy sduppers, they are private to each DbCursor<>
907 close(); // Call close() ahead of freeing following buffers.
908 free(key_buf_.get_data());
909 free(data_buf_.get_data());
916 ////////////////////////////////////////////////////////////////////
918 const DbCursor<key_dt, data_dt>& operator=
919 (const DbCursor<key_dt, data_dt>& dbc)
924 DbCursorBase::operator =(dbc);
926 curr_key_ = dbc.curr_key_;
927 curr_data_ = dbc.curr_data_;
928 rmw_get_ = dbc.rmw_get_;
929 this->bulk_retrieval_ = dbc.bulk_retrieval_;
930 this->directdb_get_ = dbc.directdb_get_;
931 // Now we have to copy key_buf_ and data_buf_ to support
933 key_buf_.set_data(pk = DbstlReAlloc(key_buf_.get_data(),
934 ulen = dbc.key_buf_.get_ulen()));
935 key_buf_.set_ulen(ulen);
936 key_buf_.set_size(dbc.key_buf_.get_size());
937 key_buf_.set_flags(DB_DBT_USERMEM);
938 memcpy(pk, dbc.key_buf_.get_data(), ulen);
940 data_buf_.set_data(pk = DbstlReAlloc(key_buf_.get_data(),
941 ulen = dbc.key_buf_.get_ulen()));
942 data_buf_.set_ulen(ulen);
943 data_buf_.set_size(dbc.data_buf_.get_size());
944 data_buf_.set_flags(DB_DBT_USERMEM);
945 memcpy(pk, dbc.key_buf_.get_data(), ulen);
947 if (dbc.recno_itr_) {
952 recno_itr_ = new DbstlMultipleRecnoDataIterator(
954 recno_itr_->set_pointer(dbc.recno_itr_->get_pointer());
955 } else if (recno_itr_) {
960 if (dbc.multi_itr_) {
965 multi_itr_ = new DbstlMultipleKeyDataIterator(
967 multi_itr_->set_pointer(dbc.multi_itr_->get_pointer());
969 } else if (multi_itr_) {
975 // Do not copy sduppers, they are private to each DbCursor<>
980 // Move Dbc*cursor to next position. If doing bulk read, read from
981 // the bulk buffer. If bulk buffer exhausted, do another bulk read
982 // from database, and then read from the bulk buffer. Quit if no
983 // more data in database.
985 int next(int flag = DB_NEXT)
991 retry: if (bulk_retrieval_) {
993 if (multi_itr_->next(k, d)) {
994 curr_key_.set_dbt(k, false);
995 curr_data_.set_dbt(d, false);
1003 if (recno_itr_->next(recno, d)) {
1004 curr_key_.set_dbt(k, false);
1005 curr_data_.set_dbt(d, false);
1013 ret = increment(flag);
1014 if (bulk_retrieval_ && ret == 0)
1019 inline int prev(int flag = DB_PREV)
1021 return increment(flag);
1024 // Move Dbc*cursor to first element. If doing bulk read, read data
1025 // from bulk buffer.
1032 ret = increment(DB_FIRST);
1033 if (bulk_retrieval_) {
1035 if (multi_itr_->next(k, d)) {
1036 curr_key_.set_dbt(k, false);
1037 curr_data_.set_dbt(d, false);
1045 if (recno_itr_->next(recno, d)) {
1046 curr_key_.set_dbt(k, false);
1047 curr_data_.set_dbt(d, false);
1061 return increment(DB_LAST);
1064 // Get current key/data pair, shallow copy. Return 0 on success,
1066 inline int get_current_key_data(key_dt&k, data_dt&d)
1069 update_current_key_data_from_db(
1070 DbCursorBase::SKIP_NONE);
1071 if (curr_key_.get_data(k) == 0 && curr_data_.get_data(d) == 0)
1074 return INVALID_KEY_DATA;
1077 // Get current data, shallow copy. Return 0 on success, -1 if no data.
1078 inline int get_current_data(data_dt&d)
1081 update_current_key_data_from_db(DbCursorBase::SKIP_KEY);
1082 if (curr_data_.get_data(d) == 0)
1085 return INVALID_KEY_DATA;
1088 // Get current key, shallow copy. Return 0 on success, -1 if no data.
1089 inline int get_current_key(key_dt&k)
1092 update_current_key_data_from_db(
1093 DbCursorBase::SKIP_DATA);
1094 if (curr_key_.get_data(k) == 0)
1097 return INVALID_KEY_DATA;
1104 ResourceManager::instance()->remove_cursor(this);
1109 // Parameter skipkd specifies skip retrieving key or data:
1110 // If 0, don't skip, retrieve both;
1111 // If 1, skip retrieving key;
1112 // If 2, skip retrieving data.
1113 // Do not poll from db again if doing bulk retrieval.
1114 void update_current_key_data_from_db(DbcGetSkipOptions skipkd) {
1116 u_int32_t sz, sz1, kflags = DB_DBT_USERMEM,
1117 dflags = DB_DBT_USERMEM;
1118 // Do not poll from db again if doing bulk retrieval.
1119 if (this->bulk_retrieval_)
1121 if (this->csr_status_ != 0) {
1127 // We will modify flags if skip key or data, so cache old
1128 // value and set it after get calls.
1129 if (skipkd != DbCursorBase::SKIP_NONE) {
1130 kflags = key_buf_.get_flags();
1131 dflags = data_buf_.get_flags();
1133 if (skipkd == DbCursorBase::SKIP_KEY) {
1134 key_buf_.set_dlen(0);
1135 key_buf_.set_flags(DB_DBT_PARTIAL | DB_DBT_USERMEM);
1138 if (skipkd == DbCursorBase::SKIP_DATA) {
1139 data_buf_.set_dlen(0);
1140 data_buf_.set_flags(DB_DBT_PARTIAL | DB_DBT_USERMEM);
1142 retry: ret = csr_->get(&key_buf_, &data_buf_, DB_CURRENT);
1144 if (skipkd != DbCursorBase::SKIP_KEY)
1145 curr_key_ = key_buf_;
1146 if (skipkd != DbCursorBase::SKIP_DATA)
1147 curr_data_ = data_buf_;
1148 limit_buf_size_after_use();
1149 } else if (ret == DB_BUFFER_SMALL) {
1150 if ((sz = key_buf_.get_size()) > 0)
1151 enlarge_dbt(key_buf_, sz);
1152 if ((sz1 = data_buf_.get_size()) > 0)
1153 enlarge_dbt(data_buf_, sz1);
1154 if (sz == 0 && sz1 == 0)
1155 THROW0(InvalidDbtException);
1158 if (skipkd != DbCursorBase::SKIP_NONE) {
1159 key_buf_.set_flags(kflags);
1160 data_buf_.set_flags(dflags);
1162 throw_bdb_exception(
1163 "DbCursor<>::update_current_key_data_from_db", ret);
1166 if (skipkd != DbCursorBase::SKIP_NONE) {
1167 key_buf_.set_flags(kflags);
1168 data_buf_.set_flags(dflags);
1173 ////////////////////////////////////////////////////////////////////////
1174 ////////////////////////////////////////////////////////////////////////
1176 // RandDbCursor class template definition
1178 // RandDbCursor is a random accessible cursor wrapper for use by
1179 // db_vector_iterator, it derives from DbCursor<> class. It has a fixed key
1180 // data type, which is index_type.
1182 typedef db_recno_t index_type;
1183 template<Typename data_dt>
1184 class RandDbCursor : public DbCursor<index_type, data_dt>
1187 friend class DataItem;
1188 typedef ssize_t difference_type;
1190 typedef RandDbCursor<data_dt> self;
1191 typedef DbCursor<index_type, data_dt> base;
1193 // Return current csr_ pointed element's index in recno database
1194 // (i.e. the index starting from 1). csr_ must be open and
1195 // point to an existing key/data pair.
1197 inline index_type get_current_index() const
1201 if (this->directdb_get_)
1202 ((self *)this)->update_current_key_data_from_db(
1203 DbCursorBase::SKIP_DATA);
1204 this->curr_key_.get_data(ndx);
1208 inline int compare(const self *csr2) const{
1211 i1 = this->get_current_index();
1212 i2 = csr2->get_current_index();
1216 // Insert data d before/after current position.
1217 int insert(const data_dt& d, int pos = DB_BEFORE){
1221 // Inserting into empty db, must set key to 1.
1222 if (pos == DB_KEYLAST)
1225 ret = base::insert(k, d, pos);
1227 // Inserting into a empty db using begin() itr, so flag is
1228 // DB_AFTER and surely failed, so change to use DB_KEYLAST
1230 if (ret == EINVAL) {
1233 ret = base::insert(k, d, pos);
1235 this->csr_status_ = ret;
1240 * Move the cursor n positions, if reaches the beginning or end,
1241 * returns DB_NOTFOUND.
1243 int advance(difference_type n)
1247 u_int32_t sz, flags = 0;
1249 indx = this->get_current_index();
1253 index_type i = (index_type)n;
1256 if (n < 0 && indx < 1) { // Index in recno db starts from 1.
1258 ret = INVALID_ITERATOR_POSITION;
1261 this->inform_duppers();
1263 // Do a search to determine whether new position is valid.
1264 Dbt k, &d = this->data_buf_;
1268 k.set_size(sizeof(indx));
1272 retry: if (this->csr_ &&
1273 ((ret = this->csr_->get(&k, &d, DB_SET)) == DB_NOTFOUND)) {
1274 this->csr_status_ = ret = INVALID_ITERATOR_POSITION;
1275 this->curr_key_.reset();
1276 this->curr_data_.reset();
1277 } else if (ret == DB_BUFFER_SMALL) {
1280 this->enlarge_dbt(d, sz);
1282 } else if (ret == 0) {
1283 this->curr_key_.set_dbt(k, false);
1284 this->curr_data_.set_dbt(d, false);
1285 this->limit_buf_size_after_use();
1287 throw_bdb_exception("RandDbCursor<>::advance", ret);
1288 this->csr_status_ = ret;
1292 // Return the last index of recno db (index starting from 1),
1293 // it will also move the underlying cursor to last key/data pair.
1295 inline index_type last_index()
1301 return 0;// Invalid position.
1303 return get_current_index();
1306 explicit RandDbCursor(u_int32_t b_bulk_retrieval = 0,
1307 bool b_rmw1 = false, bool directdbget = true)
1308 : base(b_bulk_retrieval, b_rmw1, directdbget)
1312 RandDbCursor(const RandDbCursor<data_dt>& rdbc) : base(rdbc)
1316 explicit RandDbCursor(Dbc* csr1, int posidx = 0) : base(csr1)
1320 virtual ~RandDbCursor()
1324 }; // RandDbCursor<>
1328 #endif // !_DB_STL_DBC_H