diff options
Diffstat (limited to 'cpp/src/Freeze/MapI.cpp')
-rw-r--r-- | cpp/src/Freeze/MapI.cpp | 352 |
1 files changed, 311 insertions, 41 deletions
diff --git a/cpp/src/Freeze/MapI.cpp b/cpp/src/Freeze/MapI.cpp index 7e39199f794..5470f27d9e0 100644 --- a/cpp/src/Freeze/MapI.cpp +++ b/cpp/src/Freeze/MapI.cpp @@ -19,16 +19,50 @@ using namespace Freeze; // +// MapIndexBase (from Map.h) +// + +Freeze::MapIndexBase::~MapIndexBase() +{ +} + +Freeze::MapIndexBase::MapIndexBase(const string& name) : + _name(name), + _impl(0), + _map(0) +{ +} + +const string& +MapIndexBase::name() const +{ + return _name; +} + +IteratorHelper* +Freeze::MapIndexBase::untypedFind(const Key& k, bool ro) const +{ + return _impl->untypedFind(k, ro, *_map); +} + +int +Freeze::MapIndexBase::untypedCount(const Key& k) const +{ + return _impl->untypedCount(k, _map->connection()); +} + +// // MapHelper (from Map.h) // Freeze::MapHelper* Freeze::MapHelper::create(const Freeze::ConnectionPtr& connection, const string& dbName, + const std::vector<MapIndexBasePtr>& indices, bool createDb) { Freeze::ConnectionIPtr connectionI = Freeze::ConnectionIPtr::dynamicCast(connection); - return new MapHelperI(connectionI, dbName, createDb); + return new MapHelperI(connectionI, dbName, indices, createDb); } Freeze::MapHelper::~MapHelper() @@ -45,8 +79,8 @@ Freeze::IteratorHelper::create(const MapHelper& m, bool readOnly) { const MapHelperI& actualMap = dynamic_cast<const MapHelperI&>(m); - auto_ptr<IteratorHelperI> r(new IteratorHelperI(actualMap, readOnly)); - if(r->findFirst()) + auto_ptr<IteratorHelperI> r(new IteratorHelperI(actualMap, readOnly, 0)); + if(r->next()) { return r.release(); } @@ -62,21 +96,25 @@ Freeze::IteratorHelper::~IteratorHelper() } - // // IteratorHelperI // - -Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly) : +Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly, + const MapIndexBasePtr& index) : _map(m), _dbc(0), + _indexed(index != 0), _tx(0) { if(_map._trace >= 2) { Trace out(_map._connection->communicator()->getLogger(), "Freeze.Map"); out << "opening iterator on Db \"" << _map._dbName << "\""; + if(index != 0) + { + out << " with index \"" << index->name() << "\""; + } } DbTxn* txn = _map._connection->dbTxn(); @@ -92,7 +130,14 @@ Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly) : try { - _map._db->cursor(txn, &_dbc, 0); + if(index != 0) + { + index->_impl->db()->cursor(txn, &_dbc, 0); + } + else + { + _map._db->cursor(txn, &_dbc, 0); + } } catch(const ::DbException& dx) { @@ -100,12 +145,15 @@ Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly) : ex.message = dx.what(); throw ex; } + _map._iteratorList.push_back(this); } + Freeze::IteratorHelperI::IteratorHelperI(const IteratorHelperI& it) : _map(it._map), _dbc(0), + _indexed(it._indexed), _tx(0) { if(_map._trace >= 2) @@ -134,11 +182,6 @@ Freeze::IteratorHelperI::~IteratorHelperI() close(); } -bool -Freeze::IteratorHelperI::findFirst() const -{ - return next(); -} bool Freeze::IteratorHelperI::find(const Key& key) const @@ -217,7 +260,22 @@ Freeze::IteratorHelperI::get(const Key*& key, const Value*& value) const { try { - int err = _dbc->get(&dbKey, &dbValue, DB_CURRENT); + int err; + + if(_indexed) + { + // + // Not interested in getting the index's key + // + Dbt iKey; + iKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); + + err = _dbc->pget(&iKey, &dbKey, &dbValue, DB_CURRENT); + } + else + { + err = _dbc->get(&dbKey, &dbValue, DB_CURRENT); + } if(err == 0) { @@ -314,7 +372,21 @@ Freeze::IteratorHelperI::get() const { try { - int err = _dbc->get(&dbKey, &dbValue, DB_CURRENT); + int err; + if(_indexed) + { + // + // Not interested in getting the index's key + // + Dbt iKey; + iKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); + + err = _dbc->pget(&iKey, &dbKey, &dbValue, DB_CURRENT); + } + else + { + err = _dbc->get(&dbKey, &dbValue, DB_CURRENT); + } if(err == 0) { @@ -377,6 +449,13 @@ Freeze::IteratorHelperI::get() const void Freeze::IteratorHelperI::set(const Value& value) { + if(_indexed) + { + DatabaseException ex(__FILE__, __LINE__); + ex.message = "Cannot set an iterator retrieved through an index"; + throw ex; + } + // // key ignored // @@ -463,9 +542,11 @@ Freeze::IteratorHelperI::next() const Dbt dbValue; dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); + int flags = _indexed ? DB_NEXT_DUP : DB_NEXT; + try { - if(_dbc->get(&dbKey, &dbValue, DB_NEXT) == 0) + if(_dbc->get(&dbKey, &dbValue, flags) == 0) { return true; } @@ -493,30 +574,6 @@ Freeze::IteratorHelperI::next() const } } -bool -Freeze::IteratorHelperI::equals(const IteratorHelper& rhs) const -{ - if(this == &rhs) - { - return true; - } - else - { - // - // Compare keys - // - try - { - Key rhsKey = *dynamic_cast<const IteratorHelperI&>(rhs).get(); - return *get() == rhsKey; - } - catch(const InvalidPositionException&) - { - return false; - } - } -} - void Freeze::IteratorHelperI::close() { @@ -654,12 +711,26 @@ Freeze::IteratorHelperI::Tx::dead() Freeze::MapHelperI::MapHelperI(const ConnectionIPtr& connection, const std::string& dbName, + const vector<MapIndexBasePtr>& indices, bool createDb) : _connection(connection), - _db(SharedDb::get(connection, dbName, createDb)), + _db(SharedDb::get(connection, dbName, indices, createDb)), _dbName(dbName), _trace(connection->trace()) { + for(vector<MapIndexBasePtr>::const_iterator p = indices.begin(); + p != indices.end(); ++p) + { + const MapIndexBasePtr& indexBase = *p; + assert(indexBase->_impl != 0); + assert(indexBase->_map == 0); + bool inserted = + _indices.insert(IndexMap::value_type(indexBase->name(), indexBase)).second; + assert(inserted); + indexBase->_map = this; + indexBase->_communicator = _connection->communicator(); + } + _connection->registerMap(this); } @@ -675,7 +746,7 @@ Freeze::MapHelperI::find(const Key& k, bool readOnly) const { try { - auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly)); + auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly, 0)); if(r->find(k)) { return r.release(); @@ -995,6 +1066,19 @@ Freeze::MapHelperI::closeAllIterators() } } +const MapIndexBasePtr& +Freeze::MapHelperI::index(const string& name) const +{ + IndexMap::const_iterator p = _indices.find(name); + if(p == _indices.end()) + { + DatabaseException ex(__FILE__, __LINE__); + ex.message = "Cannot find index \"" + name + "\""; + throw ex; + } + return p->second; +} + void Freeze::MapHelperI::close() { @@ -1003,6 +1087,15 @@ Freeze::MapHelperI::close() _connection->unregisterMap(this); } _db = 0; + + for(IndexMap::iterator p = _indices.begin(); p != _indices.end(); ++p) + { + MapIndexBasePtr& indexBase = p->second; + + indexBase->_impl = 0; + indexBase->_map = 0; + } + _indices.clear(); } void @@ -1026,6 +1119,183 @@ Freeze::MapHelperI::closeAllIteratorsExcept(const IteratorHelperI::TxPtr& tx) co } } + +// +// MapIndexI +// + +static int +callback(Db* secondary, const Dbt* key, const Dbt* value, Dbt* result) +{ + void* indexObj = secondary->get_app_private(); + MapIndexI* index = static_cast<MapIndexI*>(indexObj); + assert(index != 0); + return index->secondaryKeyCreate(secondary, key, value, result); +} + + +Freeze::MapIndexI::MapIndexI(const ConnectionIPtr& connection, SharedDb& db, + DbTxn* txn, bool createDb, const MapIndexBasePtr& index) : + _index(index) +{ + assert(txn != 0); + + _db.reset(new Db(connection->dbEnv(), 0)); + _db->set_flags(DB_DUP | DB_DUPSORT); + _db->set_app_private(this); + + u_int32_t flags = 0; + if(createDb) + { + flags = DB_CREATE; + } + + _dbName = db.dbName() + "." + _index->name(); + + _db->open(txn, _dbName.c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE); + + // + // To populate empty indices + // + flags = DB_CREATE; + db.associate(txn, _db.get(), callback, flags); + + // + // Note: caller catch and translates exceptions + // +} + +Freeze::MapIndexI::~MapIndexI() +{ + _db->close(0); +} + +IteratorHelper* +Freeze::MapIndexI::untypedFind(const Key& k, bool ro, const MapHelperI& map) const +{ + auto_ptr<IteratorHelperI> r(new IteratorHelperI(map, ro, _index)); + + if(r->find(k)) + { + return r.release(); + } + else + { + return 0; + } +} + +int +Freeze::MapIndexI::untypedCount(const Key& k, const ConnectionIPtr& connection) const +{ + Dbt dbKey; + initializeInDbt(k, dbKey); + + Dbt dbValue; + dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); + + int result = 0; + + try + { + for(;;) + { + Dbc* dbc = 0; + + try + { + // + // Move to the first record + // + _db->cursor(0, &dbc, 0); + bool found = (dbc->get(&dbKey, &dbValue, DB_SET) == 0); + + if(found) + { + db_recno_t count = 0; + dbc->count(&count, 0); + result = static_cast<int>(count); + } + + Dbc* toClose = dbc; + dbc = 0; + toClose->close(); + break; // for (;;) + } + catch(const DbDeadlockException&) + { + if(dbc != 0) + { + try + { + dbc->close(); + } + catch(const DbDeadlockException&) + { + // + // Ignored + // + } + } + + if(connection->deadlockWarning()) + { + Warning out(connection->communicator()->getLogger()); + out << "Deadlock in Freeze::MapIndexI::untypedCount while searching \"" + << _dbName << "\"; retrying ..."; + } + + // + // Retry + // + } + catch(...) + { + if(dbc != 0) + { + try + { + dbc->close(); + } + catch(const DbDeadlockException&) + { + // + // Ignored + // + } + } + throw; + } + } + } + catch(const DbException& dx) + { + DatabaseException ex(__FILE__, __LINE__); + ex.message = dx.what(); + throw ex; + } + + return result; +} + +int +Freeze::MapIndexI::secondaryKeyCreate(Db* secondary, const Dbt* dbKey, + const Dbt* dbValue, Dbt* result) +{ + Byte* first = static_cast<Byte*>(dbValue->get_data()); + Value value(first, first + dbValue->get_size()); + + Key bytes; + _index->marshalKey(value, bytes); + + result->set_flags(DB_DBT_APPMALLOC); + void* data = malloc(bytes.size()); + memcpy(data, &bytes[0], bytes.size()); + result->set_data(data); + result->set_size(static_cast<u_int32_t>(bytes.size())); + return 0; +} + // // Print for the various exception types. // |