Beispiel #1
0
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");
}
Beispiel #2
0
 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));
 }
Beispiel #3
0
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);
    }
}
Beispiel #5
0
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");
}
Beispiel #6
0
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;
    }
}
Beispiel #8
0
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;
        }
    }
}
Beispiel #9
0
/*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;
    }
}
Beispiel #10
0
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;
}