void TxnListTestCase::testLoadInvalidCrc() { copyFiles("txnbackup_invalidcrc"); TxnManager txnManager; txnManager.loadFromFile(); Assert(txnManager.size() == 1); txnManager.toJson(); TransactionPtr txnPtr = txnManager.getTransaction(1); Assert(txnPtr != NULL); Assert(txnPtr->getTimestamp() == 1441002400); Assert(txnPtr->getPaymentType() == "cash"); Assert(txnPtr->getCartItem(1)->getType() == "ThirdParty"); Assert(txnPtr->getCartItem(2)->getType() == "LLSC"); }
AsyncHttp(RequestPtr request, bp::runloop::RunLoop *rl) : m_request(request), m_connecting(false), m_connected(false), m_redirectUrl(), m_requestSent(false), m_status(), m_headers(), m_body(), m_complete(false), m_closed(false), m_percentSent(0.0), m_percentReceived(0.0), m_timedOut(false), m_cancelled(false), m_errorMsg(), m_zeroSendProgressReported(false), m_hundredSendProgressReported(false), m_zeroRecvProgressReported(false), m_hundredRecvProgressReported(false), m_rl(rl) { m_transaction.reset(new Transaction(m_request)); }
void TxnBackupManager::load(TxnManager &txnManager) { const string data = m_fileBackupManager.load(); // read file into json object Json::Value json; Json::Reader reader; // ensure valid JSON if (!data.empty() && !reader.parse(data, json)) { throw runtime_error("Error parsing JSON"); } txnManager.clear(); // populate txnManager for (Json::Value::iterator transactionIter = json.begin(); transactionIter != json.end(); ++transactionIter) { TransactionPtr txnPtr = transactionFromJson(txnManager, *transactionIter); // using txnManager.addTransaction ensures JSON transactions are checked txnManager.addTransaction((*transactionIter)["saleseqno"].asInt(), txnPtr); const Json::Value &cartItemsJson = (*transactionIter)["cartitems"]; for (Json::Value::iterator itemIter = cartItemsJson.begin(); itemIter != cartItemsJson.end(); ++itemIter) { CartItemNumber itemNumber = (*itemIter)["itemnumber"].asInt(); txnPtr->addCartItem(itemNumber, cartItemFromJson(*itemIter)); } } }
/** * Merge \trans into this transaction * Internally, transactions are kept in a sorted vector, what allows to * easily access merged transaction properties on demand. * \param trans transaction to be merged with */ void MergedTransaction::merge(TransactionPtr trans) { bool inserted = false; for (auto it = transactions.begin(); it < transactions.end(); ++it) { if ((*it)->getId() > trans->getId()) { transactions.insert(it, trans); inserted = true; break; } } if (!inserted) { transactions.push_back(trans); } }
void TxnListTestCase::testSave() { TxnManager txnManager; TransactionPtr txnPtr(new CashTransaction(txnManager, CURRENT_TIME)); txnManager.addTransaction(1, txnPtr); txnPtr->addCartItem(1, CartItemPtr(new TopupCartItem("tpurseload", 3, 300, "TPurse Load", false, 4, "123456789"))); txnPtr->addCartItem(2, CartItemPtr(new TopupCartItem("tpurseload", 3, 300, "TPurse Load", false, 4, "12345678"))); txnPtr->addCartItem(3, CartItemPtr(new TopupCartItem("tpurseload", 3, 300, "TPurse Load", false, 4, "1234567"))); CURRENT_TIME += 1; txnPtr.reset(new CashTransaction(txnManager, CURRENT_TIME)); txnManager.addTransaction(2, txnPtr); txnPtr->addCartItem(1, CartItemPtr(new CartItem("ThirdParty", 50, 46, "GTS Timetable short", true))); txnManager.saveToFile(); // make sure our transactions are definitely there! Assert(txnManager.size() == 2); // constructor automatically loads from file TxnManager newTxnManager; newTxnManager.loadFromFile(); Assert(newTxnManager.size() == 2); TransactionPtr newTxnPtr = newTxnManager.getTransaction(1); Assert(newTxnPtr->getTimestamp() == CURRENT_TIME - 1); Assert(newTxnPtr->getPaymentType() == "cash"); Assert(newTxnPtr->getCartItem(1)->getType() == "tpurseload"); Assert(newTxnPtr->getCartItem(2)->getType() == "tpurseload"); Assert(newTxnPtr->getCartItem(3)->getType() == "tpurseload"); newTxnPtr = newTxnManager.getTransaction(2); Assert(newTxnPtr->getTimestamp() == CURRENT_TIME); Assert(newTxnPtr->getPaymentType() == "cash"); Assert(newTxnPtr->getCartItem(1)->getType() == "ThirdParty"); }
void TxnListTestCase::testLoad() { copyFiles("txnbackup_ok"); TxnManager txnManager; txnManager.loadFromFile(); PRINT_DEBUG(txnManager.toJson()); Assert(txnManager.size() == 2); TransactionPtr txnPtr = txnManager.getTransaction(1); Assert(txnPtr != NULL); Assert(txnPtr->getTimestamp() == 1441002600); PRINT_DEBUG(txnPtr->getPaymentType()); Assert(txnPtr->getPaymentType() == "cash"); Assert(txnPtr->getCartItem(1)->getType() == "LLSC"); Assert(txnPtr->getCartItem(2)->getType() == "LLSC"); txnPtr = txnManager.getTransaction(2); Assert(txnPtr->getTimestamp() == 1441002601); Assert(txnPtr->getCartItem(1)->getType() == "ThirdParty"); }
Freeze::ObjectStoreBase::ObjectStoreBase(const string& facet, const string& facetType, bool createDb, EvictorIBase* evictor, const vector<IndexPtr>& indices, bool populateEmptyIndices) : _facet(facet), _evictor(evictor), _indices(indices), _communicator(evictor->communicator()), _encoding(evictor->encoding()), _keepStats(false) { if(facet == "") { _dbName = EvictorIBase::defaultDb; } else { _dbName = facet; } if(!facetType.empty()) { // // Create a sample servant with this type // ValueFactoryPtr factory = _communicator->getValueFactoryManager()->find(facetType); if(factory == 0) { throw DatabaseException(__FILE__, __LINE__, "No object factory registered for type-id '" + facetType + "'"); } _sampleServant = factory->create(facetType); } ConnectionPtr catalogConnection = createConnection(_communicator, evictor->dbEnv()->getEnvName()); Catalog catalog(catalogConnection, catalogName()); Catalog::iterator p = catalog.find(evictor->filename()); if(p != catalog.end()) { if(p->second.evictor) { // // empty means the value is ::Freeze::ObjectRecord // _keepStats = p->second.value.empty(); } else { DatabaseException ex(__FILE__, __LINE__); ex.message = evictor->filename() + " is not an evictor database"; throw ex; } } DbEnv* dbEnv = evictor->dbEnv()->getEnv(); try { _db.reset(new Db(dbEnv, 0)); Ice::PropertiesPtr properties = evictor->communicator()->getProperties(); string propPrefix = "Freeze.Evictor." + evictor->filename() + "."; int btreeMinKey = properties->getPropertyAsInt(propPrefix + _dbName + ".BtreeMinKey"); if(btreeMinKey > 2) { if(evictor->trace() >= 1) { Trace out(evictor->communicator()->getLogger(), "Freeze.Evictor"); out << "Setting \"" << evictor->filename() + "." + _dbName << "\"'s btree minkey to " << btreeMinKey; } _db->set_bt_minkey(btreeMinKey); } bool checksum = properties->getPropertyAsInt(propPrefix + "Checksum") > 0; if(checksum) { if(evictor->trace() >= 1) { Trace out(evictor->communicator()->getLogger(), "Freeze.Evictor"); out << "Turning checksum on for \"" << evictor->filename() << "\""; } _db->set_flags(DB_CHKSUM); } int pageSize = properties->getPropertyAsInt(propPrefix + "PageSize"); if(pageSize > 0) { if(evictor->trace() >= 1) { Trace out(evictor->communicator()->getLogger(), "Freeze.Evictor"); out << "Setting \"" << evictor->filename() << "\"'s pagesize to " << pageSize; } _db->set_pagesize(pageSize); } TransactionPtr tx = catalogConnection->beginTransaction(); DbTxn* txn = getTxn(tx); u_int32_t flags = DB_THREAD; if(createDb) { flags |= DB_CREATE; } // // Berkeley DB expects file paths to be UTF8 encoded. We keep // _dbName as a native string here, while it might have // been better to convert it to UTF-8, changing this isn't // possible without potentially breaking backward compatibility // with deployed databases. // _db->open(txn, nativeToUTF8(evictor->filename(), getProcessStringConverter()).c_str(), _dbName.c_str(), DB_BTREE, flags, FREEZE_DB_MODE); for(size_t i = 0; i < _indices.size(); ++i) { _indices[i]->_impl->associate(this, txn, createDb, populateEmptyIndices); } if(p == catalog.end()) { CatalogData catalogData; catalogData.evictor = true; catalogData.key = "Ice::Identity"; catalogData.value = "Object"; catalog.put(Catalog::value_type(evictor->filename(), catalogData)); } tx->commit(); } catch(const DbException& dx) { TransactionPtr tx = catalogConnection->currentTransaction(); if(tx != 0) { try { tx->rollback(); } catch(...) { } } if(dx.get_errno() == ENOENT) { NotFoundException ex(__FILE__, __LINE__); ex.message = dx.what(); throw ex; } else { DatabaseException ex(__FILE__, __LINE__); ex.message = dx.what(); throw ex; } } catch(...) { TransactionPtr tx = catalogConnection->currentTransaction(); if(tx != 0) { try { tx->rollback(); } catch(...) { } } throw; } }
Freeze::MapDb::MapDb(const ConnectionIPtr& connection, const string& dbName, const string& key, const string& value, const KeyCompareBasePtr& keyCompare, const vector<MapIndexBasePtr>& indices, bool createDb) : Db(connection->dbEnv()->getEnv(), 0), _communicator(connection->communicator()), _dbName(dbName), _trace(connection->trace()), _keyCompare(keyCompare) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "opening Db \"" << _dbName << "\""; } Catalog catalog(connection, _catalogName); TransactionPtr tx = connection->currentTransaction(); bool ownTx = (tx == 0); for(;;) { try { if(ownTx) { tx = 0; tx = connection->beginTransaction(); } Catalog::iterator ci = catalog.find(_dbName); if(ci != catalog.end()) { if(ci->second.evictor) { throw DatabaseException(__FILE__, __LINE__, _dbName + " is an evictor database"); } _key = ci->second.key; _value = ci->second.value; checkTypes(key, value); } else { _key = key; _value = value; } set_app_private(this); if(_keyCompare->compareEnabled()) { set_bt_compare(&customCompare); } PropertiesPtr properties = _communicator->getProperties(); string propPrefix = "Freeze.Map." + _dbName + "."; int btreeMinKey = properties->getPropertyAsInt(propPrefix + "BtreeMinKey"); if(btreeMinKey > 2) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Setting \"" << _dbName << "\"'s btree minkey to " << btreeMinKey; } set_bt_minkey(btreeMinKey); } bool checksum = properties->getPropertyAsInt(propPrefix + "Checksum") > 0; if(checksum) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Turning checksum on for \"" << _dbName << "\""; } set_flags(DB_CHKSUM); } int pageSize = properties->getPropertyAsInt(propPrefix + "PageSize"); if(pageSize > 0) { if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Setting \"" << _dbName << "\"'s pagesize to " << pageSize; } set_pagesize(pageSize); } DbTxn* txn = getTxn(tx); u_int32_t flags = DB_THREAD; if(createDb) { flags |= DB_CREATE; } open(txn, Ice::nativeToUTF8(_communicator, _dbName).c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE); StringSeq oldIndices; StringSeq newIndices; size_t oldSize = 0; CatalogIndexList catalogIndexList(connection, _catalogIndexListName); if(createDb) { CatalogIndexList::iterator cil = catalogIndexList.find(_dbName); if(cil != catalogIndexList.end()) { oldIndices = cil->second; oldSize = oldIndices.size(); } } for(vector<MapIndexBasePtr>::const_iterator p = indices.begin(); p != indices.end(); ++p) { const MapIndexBasePtr& indexBase = *p; assert(indexBase->_impl == 0); assert(indexBase->_communicator == 0); indexBase->_communicator = connection->communicator(); auto_ptr<MapIndexI> indexI; try { indexI.reset(new MapIndexI(connection, *this, txn, createDb, indexBase)); } catch(const DbDeadlockException&) { throw; } catch(const DbException& dx) { string message = "Error while opening index \"" + _dbName + "." + indexBase->name() + "\": " + dx.what(); throw DatabaseException(__FILE__, __LINE__, message); } #ifndef NDEBUG bool inserted = #endif _indices.insert(IndexMap::value_type(indexBase->name(), indexI.get())).second; assert(inserted); indexBase->_impl = indexI.release(); if(createDb) { newIndices.push_back(indexBase->name()); oldIndices.erase(std::remove(oldIndices.begin(), oldIndices.end(), indexBase->name()), oldIndices.end()); } } if(ci == catalog.end()) { CatalogData catalogData; catalogData.evictor = false; catalogData.key = key; catalogData.value = value; catalog.put(Catalog::value_type(_dbName, catalogData)); } if(createDb) { // // Remove old indices and write the new ones // bool indexRemoved = false; for(StringSeq::const_iterator q = oldIndices.begin(); q != oldIndices.end(); ++q) { const string& index = *q; if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "removing old index \"" << index << "\" on Db \"" << _dbName << "\""; } try { connection->removeMapIndex(_dbName, *q); indexRemoved = true; } catch(const IndexNotFoundException&) { // Ignored if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "index \"" << index << "\" on Db \"" << _dbName << "\" does not exist"; } } } if(indexRemoved || oldSize != newIndices.size()) { if(newIndices.size() == 0) { catalogIndexList.erase(_dbName); if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Removed catalogIndexList entry for Db \"" << _dbName << "\""; } } else { catalogIndexList.put(CatalogIndexList::value_type(_dbName, newIndices)); if(_trace >= 1) { Trace out(_communicator->getLogger(), "Freeze.Map"); out << "Updated catalogIndexList entry for Db \"" << _dbName << "\""; } } } } if(ownTx) { tx->commit(); } break; // for(;;) } catch(const DbDeadlockException& dx) { if(ownTx) { if(connection->deadlockWarning()) { Warning out(connection->communicator()->getLogger()); out << "Deadlock in Freeze::MapDb::MapDb on Map \"" << _dbName << "\"; retrying ..."; } // // Ignored, try again // } else { throw DeadlockException(__FILE__, __LINE__, dx.what(), tx); } } catch(const DbException& dx) { if(ownTx) { try { tx->rollback(); } catch(...) { } } string message = "Error while opening Db \"" + _dbName + "\": " + dx.what(); throw DatabaseException(__FILE__, __LINE__, message); } catch(...) { if(ownTx && tx != 0) { try { tx->rollback(); } catch(...) { } } throw; } } }
/*static*/ void Freeze::MapHelper::recreate(const Freeze::ConnectionPtr& connection, const string& dbName, const string& key, const string& value, const Freeze::KeyCompareBasePtr& keyCompare, const std::vector<MapIndexBasePtr>& indices) { Freeze::ConnectionIPtr connectionI = Freeze::ConnectionIPtr::dynamicCast(connection.get()); if(connectionI == 0) { throw DatabaseException(__FILE__, __LINE__, "Invalid connection"); } if(dbName == catalogName() || dbName == catalogIndexListName()) { throw DatabaseException(__FILE__, __LINE__, "You cannot destroy recreate the \"" + dbName + "\" database"); } if(connectionI->trace() >= 1) { Trace out(connectionI->communicator()->getLogger(), "Freeze.Map"); out << "Recreating \"" << dbName << "\""; } TransactionPtr tx = connectionI->currentTransaction(); bool ownTx = (tx == 0); Dbt keyDbt; keyDbt.set_flags(DB_DBT_REALLOC); Dbt valueDbt; valueDbt.set_flags(DB_DBT_REALLOC); try { for(;;) { try { if(ownTx) { tx = 0; tx = connectionI->beginTransaction(); } DbTxn* txn = connectionI->dbTxn(); if(connectionI->trace() >= 2) { Trace out(connectionI->communicator()->getLogger(), "Freeze.Map"); out << "Removing all existing indices for \"" << dbName << "\""; } CatalogIndexList catalogIndexList(connection, catalogIndexListName()); CatalogIndexList::iterator p = catalogIndexList.find(dbName); if(p != catalogIndexList.end()) { const StringSeq& idxs = p->second; for(size_t i = 0; i < idxs.size(); ++i) { try { connection->removeMapIndex(dbName, idxs[i]); } catch(const IndexNotFoundException&) { // // Ignored // } } catalogIndexList.erase(p); } // // Rename existing database // string oldDbName = dbName + ".old-" + generateUUID(); if(connectionI->trace() >= 2) { Trace out(connectionI->communicator()->getLogger(), "Freeze.Map"); out << "Renaming \"" << dbName << "\" to \"" << oldDbName << "\""; } connectionI->dbEnv()->getEnv()->dbrename(txn, dbName.c_str(), 0, oldDbName.c_str(), 0); // // Fortunately, DB closes oldDb automatically when it goes out of scope // Db oldDb(connectionI->dbEnv()->getEnv(), 0); // // Berkeley DB expects file paths to be UTF8 encoded. // oldDb.open(txn, nativeToUTF8(oldDbName, getProcessStringConverter()).c_str(), 0, DB_BTREE, DB_THREAD, FREEZE_DB_MODE); IceInternal::UniquePtr<MapDb> newDb(new MapDb(connectionI, dbName, key, value, keyCompare, indices, true)); if(connectionI->trace() >= 2) { Trace out(connectionI->communicator()->getLogger(), "Freeze.Map"); out << "Writing contents of \"" << oldDbName << "\" to fresh \"" << dbName << "\""; } // // Now simply write all of oldDb into newDb // Dbc* dbc = 0; oldDb.cursor(txn, &dbc, 0); try { while(dbc->get(&keyDbt, &valueDbt, DB_NEXT) == 0) { newDb->put(txn, &keyDbt, &valueDbt, 0); } } catch(...) { dbc->close(); throw; } dbc->close(); if(connectionI->trace() >= 2) { Trace out(connectionI->communicator()->getLogger(), "Freeze.Map"); out << "Transfer complete; removing \"" << oldDbName << "\""; } connectionI->dbEnv()->getEnv()->dbremove(txn, oldDbName.c_str(), 0, 0); if(ownTx) { tx->commit(); } break; // for (;;) } catch(const DbDeadlockException& dx) { if(ownTx) { if(connectionI->deadlockWarning()) { Warning out(connectionI->communicator()->getLogger()); out << "Deadlock in Freeze::MapHelperI::recreate on Db \"" << dbName << "\"; retrying ..."; } // // Ignored, try again // } else { throw DeadlockException(__FILE__, __LINE__, dx.what(), tx); } } catch(const DbException& dx) { if(ownTx) { try { tx->rollback(); } catch(...) { } } throw DatabaseException(__FILE__, __LINE__, dx.what()); } catch(...) { if(ownTx && tx != 0) { try { tx->rollback(); } catch(...) { } } throw; } } free(keyDbt.get_data()); free(valueDbt.get_data()); } catch(...) { free(keyDbt.get_data()); free(valueDbt.get_data()); throw; } }
int run(const CommunicatorPtr& communicator, const string& envName) { Freeze::ConnectionPtr connection = createConnection(communicator, envName); const string dbName = "binary"; // // Open/close db within transaction // { TransactionHolder txHolder(connection); ByteIntMap m1(connection, dbName); m1.put((ByteIntMap::value_type('a', 1))); // rollback in dtor of txHolder } { ByteIntMap m1(connection, dbName); // // Populate the database with the alphabet // populateDB(connection, m1); alphabet.assign(alphabetChars, alphabetChars + sizeof(alphabetChars) - 1); // // Test ==, swap and communicator() // ByteIntMap m(connection, dbName + "-tmp"); test(!(m == m1)); test(m != m1); m.swap(m1); test(!(m == m1)); test(m != m1); test(m1.size() == 0); test(m.communicator() == (m1.communicator() == communicator)); vector<Byte>::const_iterator j; ByteIntMap::iterator p; ByteIntMap::const_iterator cp; cout << "testing populate... " << flush; // // First try non-const iterator // for(j = alphabet.begin(); j != alphabet.end(); ++j) { p = m.find(*j); test(p != m.end()); test(p->first == *j && p->second == j - alphabet.begin()); } // // Next try const iterator // for(j = alphabet.begin(); j != alphabet.end(); ++j) { cp = m.find(*j); test(cp != m.end()); test(cp->first == *j && cp->second == j - alphabet.begin()); } test(!m.empty()); test(m.size() == alphabet.size()); cout << "ok" << endl; cout << "testing map::find... " << flush; j = find(alphabet.begin(), alphabet.end(), 'n'); cp = m.find(*j); test(cp != m.end()); test(cp->first == 'n' && cp->second == j - alphabet.begin()); cout << "ok" << endl; cout << "testing erase... " << flush; // // erase first offset characters (first offset characters is // important for later verification of the correct second value in // the map). // int offset = 3; vector<Byte> bytes; bytes.push_back('a'); bytes.push_back('b'); bytes.push_back('c'); for(j = bytes.begin(); j != bytes.end(); ++j) { p = m.find(*j); test(p != m.end()); m.erase(p); // // Release locks to avoid self deadlock // p = m.end(); p = m.find(*j); test(p == m.end()); vector<Byte>::iterator r = find(alphabet.begin(), alphabet.end(), *j); test(r != alphabet.end()); alphabet.erase(r); } for(j = alphabet.begin(); j != alphabet.end(); ++j) { cp = m.find(*j); test(cp != m.end()); test(cp->first == *j && cp->second == (j - alphabet.begin()) + offset); } cout << "ok" << endl; // // Get an iterator for the deleted element - this should fail. // cout << "testing map::find (again)... " << flush; cp = m.find('a'); test(cp == m.end()); cout << "ok" << endl; cout << "testing iterators... " << flush; p = m.begin(); ByteIntMap::iterator p2 = p; // // Verify both iterators point at the same element, and that // element is in the map. // test(p == p2); test(p->first == p2->first && p->second == p2->second); test(find(alphabet.begin(), alphabet.end(), p->first) != alphabet.end()); // // Create iterator that points at 'n' // p = m.find('n'); p2 = p; // // Verify both iterators point at 'n' // test(p == p2); test(p->first == 'n' && p->second == 13); test(p2->first == 'n' && p2->second == 13); // // Create cursor that points at 'n' // p = m.find('n'); test(p->first == 'n' && p->second == 13); ++p; p2 = p; // // Verify cloned cursors are independent // test(p->first != 'n' && p->second != 13); pair<const Byte, const Int> data = *p; ++p; test(p->first != data.first && p->second != data.second); ++p; test(p2->first == data.first && p2->second == data.second); p = m.find('n'); p2 = ++p; test(p2->first == p->first); char c = p2->first; p2 = p++; test(c == p2->first); // p2 should still be the same test(p2->first != p->first && (++p2)->first == p->first); cout << "ok" << endl; // // Test writing into an iterator. // cout << "testing iterator.set... " << flush; p = m.find('d'); test(p != m.end() && p->second == 3); test(m.find('a') == m.end()); m.put(ByteIntMap::value_type('a', 1)); p = m.find('a'); test(p != m.end() && p->second == 1); m.put(ByteIntMap::value_type('a', 0)); p = m.find('a'); test(p != m.end() && p->second == 0); // // Test inserts // ByteIntMap::value_type i3('a', 7); pair<ByteIntMap::iterator, bool> insertResult = m.insert(i3); test(insertResult.first == m.find('a')); test(insertResult.first->second == 0); test(insertResult.second == false); insertResult.first = m.end(); p = m.insert(m.end(), i3); test(p == m.find('a')); test(p->second == 0); ByteIntMap::value_type i4('b', 7); insertResult = m.insert(i4); test(insertResult.first == m.find('b')); test(insertResult.first->second == 7); test(insertResult.second == true); insertResult.first = m.end(); ByteIntMap::value_type i5('c', 8); p = m.insert(m.end(), i5); test(p == m.find('c')); test(p->second == 8); p = m.find('a'); test(p != m.end() && p->second == 0); p.set(1); test(p != m.end() && p->second == 1); // // This is necessary to release the locks held // by p and avoid a self-deadlock // p = m.end(); p = m.find('a'); test(p != m.end() && p->second == 1); cout << "ok" << endl; // // Re-populate // populateDB(connection, m); alphabet.assign(alphabetChars, alphabetChars + sizeof(alphabetChars) - 1); cout << "testing algorithms... " << flush; for_each(m.begin(), m.end(), ForEachTest); // // Inefficient, but this is just a test. Ensure that both forms of // operator== & != are tested. // ByteIntMap::value_type toFind('n', 13); p = find(m.begin(), m.end(), toFind); test(p != m.end()); test(*p == toFind); test(toFind == *p); test(!(*p != toFind)); test(!(toFind != *p)); p = find_if(m.begin(), m.end(), FindIfTest); test(p->first == 'b'); // // find_first_of. First construct a map with keys n, o, p, // q. The test must find one of the types (it doesn't matter // which since the container doesn't have to maintain sorted // order). // j = find(alphabet.begin(), alphabet.end(), 'n'); map<Byte, const Int> pairs; pairs.insert(pair<const Byte, const Int>(*j, static_cast<Int>(j - alphabet.begin()))); ++j; pairs.insert(pair<const Byte, const Int>(*j, static_cast<Int>(j - alphabet.begin()))); ++j; pairs.insert(pair<const Byte, const Int>(*j, static_cast<Int>(j - alphabet.begin()))); ++j; pairs.insert(pair<const Byte, const Int>(*j, static_cast<Int>(j - alphabet.begin()))); p = find_first_of(m.begin(), m.end(), pairs.begin(), pairs.end()); test(p != m.end()); test(p->first == 'n' || p->first == 'o' || p->first == 'p' || p->first == 'q'); j = find(alphabet.begin(), alphabet.end(), 'n'); p = find_first_of(m.begin(), m.end(), j, j + 4, FindFirstOfTest); test(p != m.end()); test(p->first == 'n' || p->first == 'o' || p->first == 'p' || p->first == 'q'); pairs.clear(); for(p = m.begin(); p != m.end(); ++p) { pairs.insert(pair<const Byte, const Int>(p->first, p->second)); } test(pairs.size() == m.size()); map<Byte, const Int>::const_iterator pit; for(pit = pairs.begin(); pit != pairs.end(); ++pit) { p = m.find(pit->first); test(p != m.end()); } cout << "ok" << endl; cout << "testing clear... " << flush; test(m.size() > 0); m.clear(); test(m.size() == 0); cout << "ok" << endl; cout << "testing index ... " << flush; m.clear(); populateDB(connection, m); // // Exact match // size_t length = alphabet.size(); for(size_t k = 0; k < length; ++k) { p = m.findByValue(static_cast<Int>(k)); test(p != m.end()); test(p->first == alphabet[k]); test(++p == m.end()); } // // 2 items at 17 // m.put(ByteIntMap::value_type(alphabet[21], static_cast<Int>(17))); p = m.findByValue(17); test(p != m.end()); test(p->first == alphabet[17] || p->first == alphabet[21]); test(++p != m.end()); test(p->first == alphabet[17] || p->first == alphabet[21]); test(++p == m.end()); test(m.valueCount(17) == 2); p = m.findByValue(17); test(p != m.end()); m.erase(p); test(++p != m.end()); test(p->first == alphabet[17] || p->first == alphabet[21]); test(++p == m.end()); test(m.valueCount(17) == 1); p = m.findByValue(17); test(p != m.end()); test(p->first == alphabet[17] || p->first == alphabet[21]); try { p.set(18); test(false); } catch(const DatabaseException&) { // Expected } test(p->first == alphabet[17] || p->first == alphabet[21]); test(++p == m.end()); test(m.valueCount(17) == 1); m.put(ByteIntMap::value_type(alphabet[21], static_cast<Int>(17))); // // Non-exact match // p = m.findByValue(21); test(p == m.end()); test(m.valueCount(21) == 0); p = m.findByValue(21, false); test(p == m.end()); p = m.findByValue(22, false); int previous = 21; int count = 0; while(p != m.end()) { test(p->second > previous); previous = p->second; ++p; count++; } test(count == 4); cout << "ok " << endl; cout << "testing unreferenced connection+transaction... " << flush; { Freeze::ConnectionPtr c2 = createConnection(communicator, envName); ByteIntMap m2(c2, dbName); TransactionPtr tx = c2->beginTransaction(); p = m2.findByValue(17); test(p != m2.end()); m2.put(ByteIntMap::value_type(alphabet[21], static_cast<Int>(99))); p = m2.findByValue(17); test(p == m2.end()); test(c2->currentTransaction() != 0); test(tx->getConnection() != 0); } // // Should roll back here // p = m.findByValue(17); test(p != m.end()); cout << "ok " << endl; cout << "testing concurrent access... " << flush; m.clear(); populateDB(connection, m); vector<IceUtil::ThreadControl> controls; vector<ReadThreadPtr> readThreads; vector<WriteThreadPtr> writeThreads; for(int i = 0; i < 5; ++i) { ReadThreadPtr rt = new ReadThread(communicator, envName, dbName); controls.push_back(rt->start()); readThreads.push_back(rt); WriteThreadPtr wt = new WriteThread(communicator, envName, dbName); controls.push_back(wt->start()); writeThreads.push_back(wt); } IceUtil::ThreadControl::sleep(IceUtil::Time::seconds(CONCURRENT_TIME)); for(vector<WriteThreadPtr>::iterator q = writeThreads.begin(); q != writeThreads.end(); ++q) { (*q)->stop(); } for(vector<ReadThreadPtr>::iterator q = readThreads.begin(); q != readThreads.end(); ++q) { (*q)->stop(); } for(vector<IceUtil::ThreadControl>::iterator q = controls.begin(); q != controls.end(); ++q) { q->join(); } cout << "ok" << endl; } cout << "testing index creation... " << flush; { IntIdentityMap iim(connection, "intIdentity"); Ice::Identity odd; odd.name = "foo"; odd.category = "odd"; Ice::Identity even; even.name = "bar"; even.category = "even"; TransactionHolder txHolder(connection); for(int i = 0; i < 1000; i++) { if(i % 2 == 0) { iim.put(IntIdentityMap::value_type(i, even)); } else { iim.put(IntIdentityMap::value_type(i, odd)); } } txHolder.commit(); iim.closeDb(); } { IntIdentityMapWithIndex iim(connection, "intIdentity"); test(iim.categoryCount("even") == 500); test(iim.categoryCount("odd") == 500); { int count = 0; IntIdentityMapWithIndex::iterator p = iim.findByCategory("even"); while(p != iim.end()) { test(p->first % 2 == 0); ++p; ++count; } test(count == 500); } { int count = 0; IntIdentityMapWithIndex::iterator p = iim.findByCategory("odd"); while(p != iim.end()) { test(p->first % 2 == 1); ++p; ++count; } test(count == 500); } iim.destroy(); } cout << "ok" << endl; cout << "testing sorting... " << flush; { SortedMap sm(connection, "sortedMap"); TransactionHolder txHolder(connection); for(int i = 0; i < 1000; i++) { int k = rand() % 1000; Ice::Identity id; id.name = "foo"; id.category = 'a' + static_cast<char>(k % 26); sm.put(SortedMap::value_type(k, id)); } txHolder.commit(); } { SortedMap sm(connection, "sortedMap"); { for(int i = 0; i < 100; ++i) { int k = rand() % 1000; SortedMap::iterator p = sm.lower_bound(k); if(p != sm.end()) { test(p->first >= k); SortedMap::iterator q = sm.upper_bound(k); if(q == sm.end()) { test(p->first == k); } else { test((p->first == k && q->first > k) || (p->first > k && q->first == p->first)); } } } } { for(int i = 0; i < 100; ++i) { string category; category = static_cast<char>('a' + rand() % 26); SortedMap::iterator p = sm.findByCategory(category); if(p != sm.end()) { SortedMap::iterator q = sm.lowerBoundForCategory(category); test(p == q); do { q++; } while(q != sm.end() && q->second.category == category); if(q != sm.end()) { test(q == sm.upperBoundForCategory(category)); } } else { SortedMap::iterator q = sm.lowerBoundForCategory(category); if(q != sm.end()) { test(p != q); test(q->second.category < category); category = q->second.category; do { q++; } while(q != sm.end() && q->second.category == category); if(q != sm.end()) { test(q == sm.upperBoundForCategory(category)); } } } } } { string category = "z"; SortedMap::iterator p = sm.lowerBoundForCategory(category); while(p != sm.end()) { test(p->second.category <= category); category = p->second.category; // cerr << category << ":" << p->first << endl; ++p; } } sm.clear(); } cout << "ok" << endl; cout << "testing wstring... " << flush; { WstringWstringMap wsm(connection, "wstringMap"); TransactionHolder txHolder(connection); wsm.put(WstringWstringMap::value_type(L"AAAAA", L"aaaaa")); wsm.put(WstringWstringMap::value_type(L"BBBBB", L"bbbbb")); wsm.put(WstringWstringMap::value_type(L"CCCCC", L"ccccc")); wsm.put(WstringWstringMap::value_type(L"DDDDD", L"ddddd")); wsm.put(WstringWstringMap::value_type(L"EEEEE", L"eeeee")); txHolder.commit(); } { WstringWstringMap wsm(connection, "wstringMap"); { WstringWstringMap::iterator p = wsm.find(L"BBBBB"); test(p != wsm.end()); test(p->second == L"bbbbb"); p = wsm.findByValue(L"ddddd"); test(p != wsm.end()); test(p->first == L"DDDDD"); } wsm.clear(); } cout << "ok" << endl; return EXIT_SUCCESS; }