summaryrefslogtreecommitdiff
path: root/cpp/src/Freeze/IndexI.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Freeze/IndexI.cpp')
-rw-r--r--cpp/src/Freeze/IndexI.cpp352
1 files changed, 352 insertions, 0 deletions
diff --git a/cpp/src/Freeze/IndexI.cpp b/cpp/src/Freeze/IndexI.cpp
new file mode 100644
index 00000000000..42d4e2115e3
--- /dev/null
+++ b/cpp/src/Freeze/IndexI.cpp
@@ -0,0 +1,352 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Freeze/IndexI.h>
+#include <Freeze/Util.h>
+
+using namespace Freeze;
+using namespace Ice;
+using namespace std;
+
+
+static int
+callback(Db* secondary, const Dbt* key, const Dbt* value, Dbt* result)
+{
+ void* indexObj = secondary->get_app_private();
+ IndexI* index = static_cast<IndexI*>(indexObj);
+ assert(index != 0);
+ return index->secondaryKeyCreate(secondary, key, value, result);
+}
+
+
+Freeze::IndexI::IndexI(Index& index, const string& name) :
+ _index(index),
+ _name(name),
+ _evictor(0)
+{
+}
+
+vector<Identity>
+Freeze::IndexI::untypedFindFirst(const Key& bytes, Int firstN) const
+{
+ Dbt dbKey;
+ initializeInDbt(bytes, dbKey);
+
+ //
+ // Berkeley DB 4.1.25 bug: it should not write into dbKey
+ //
+ dbKey.set_ulen(bytes.size());
+
+ Key pkey(1024);
+ Dbt pdbKey;
+ initializeOutDbt(pkey, pdbKey);
+
+ Dbt dbValue;
+ dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+
+
+ Ice::CommunicatorPtr communicator = _evictor->communicator();
+ _evictor->saveNow();
+
+ vector<Identity> identities;
+
+ try
+ {
+ for(;;)
+ {
+ Dbc* dbc = 0;
+ identities.clear();
+
+ try
+ {
+ //
+ // Move to the first record
+ //
+ _db->cursor(0, &dbc, 0);
+ bool more;
+
+ for(;;)
+ {
+ try
+ {
+ more = (dbc->pget(&dbKey, &pdbKey, &dbValue, DB_SET) == 0);
+ if(more)
+ {
+ pkey.resize(pdbKey.get_size());
+ }
+ break; // for(;;)
+ }
+ catch(const DbMemoryException& dx)
+ {
+ handleMemoryException(dx, pkey, pdbKey);
+ }
+ }
+
+ while((firstN <= 0 || identities.size() < static_cast<size_t>(firstN)) && more)
+ {
+ EvictorStorageKey esk;
+ EvictorI::unmarshal(esk, pkey, communicator);
+
+ if(esk.facet.size() == 0)
+ {
+ identities.push_back(esk.identity);
+ }
+ //
+ // Else skip "orphan" facet (could be just a temporary inconsistency
+ // on disk)
+ //
+ for(;;)
+ {
+ try
+ {
+ more = (dbc->pget(&dbKey, &pdbKey, &dbValue, DB_NEXT_DUP) == 0);
+ if(more)
+ {
+ pkey.resize(pdbKey.get_size());
+ }
+ break; // for(;;)
+ }
+ catch(const DbMemoryException& dx)
+ {
+ handleMemoryException(dx, pkey, pdbKey);
+ }
+ }
+ }
+ Dbc* toClose = dbc;
+ dbc = 0;
+ toClose->close();
+ break; // for (;;)
+ }
+ catch(const DbDeadlockException& dx)
+ {
+ if(dbc != 0)
+ {
+ try
+ {
+ dbc->close();
+ }
+ catch(const DbDeadlockException&)
+ {
+ //
+ // Ignored
+ //
+ }
+ }
+ //
+ // 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 identities;
+}
+
+vector<Identity>
+Freeze::IndexI::untypedFind(const Key& bytes) const
+{
+ return untypedFindFirst(bytes, 0);
+}
+
+Int
+Freeze::IndexI::untypedCount(const Key& bytes) const
+{
+
+ Dbt dbKey;
+ initializeInDbt(bytes, dbKey);
+
+ Dbt dbValue;
+ dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+
+ _evictor->saveNow();
+ 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& dx)
+ {
+ if(dbc != 0)
+ {
+ try
+ {
+ dbc->close();
+ }
+ catch(const DbDeadlockException&)
+ {
+ //
+ // Ignored
+ //
+ }
+ }
+ //
+ // 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;
+}
+
+void
+Freeze::IndexI::associate(EvictorI* evictor, DbTxn* txn,
+ bool createDb, bool populateIndex)
+{
+ assert(txn != 0);
+ _evictor = evictor;
+ _index._communicator = evictor->communicator();
+
+ _db.reset(new Db(evictor->dbEnv(), 0));
+ _db->set_flags(DB_DUP | DB_DUPSORT);
+ _db->set_app_private(this);
+
+ u_int32_t flags = 0;
+ if(createDb)
+ {
+ flags = DB_CREATE;
+ }
+ _db->open(txn, (evictor->dbName() + "." + _name).c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE);
+
+ flags = 0;
+ if(populateIndex)
+ {
+ flags = DB_CREATE;
+ }
+ evictor->db()->associate(txn, _db.get(), callback, flags);
+}
+
+int
+Freeze::IndexI::secondaryKeyCreate(Db* secondary, const Dbt* dbKey,
+ const Dbt* dbValue, Dbt* result)
+{
+ Ice::CommunicatorPtr communicator = _evictor->communicator();
+
+ EvictorStorageKey esk;
+ Byte* first = static_cast<Byte*>(dbKey->get_data());
+ Key key(first, first + dbKey->get_size());
+ EvictorI::unmarshal(esk, key, communicator);
+
+ if(esk.facet.size() == 0)
+ {
+ ObjectRecord rec;
+ first = static_cast<Byte*>(dbValue->get_data());
+ Value value(first, first + dbValue->get_size());
+ EvictorI::unmarshal(rec, value, communicator);
+
+ Key bytes;
+ if(_index.marshalKey(rec.servant, 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(bytes.size());
+ return 0;
+ }
+ }
+
+ //
+ // Don't want to index this one
+ //
+ return DB_DONOTINDEX;
+}
+
+void
+Freeze::IndexI::close()
+{
+ if(_db.get() != 0)
+ {
+ try
+ {
+ _db->close(0);
+ }
+ catch(const DbException& dx)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = dx.what();
+ throw ex;
+ }
+ _db.reset(0);
+ }
+}