ICE 3.4.2
[php5-ice-freebsdport.git] / cpp / src / Freeze / IndexI.cpp
blob1b6c5b9586d75b9c2b8e6da16fe60bec44b0ddcb
1 // **********************************************************************
2 //
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
4 //
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
7 //
8 // **********************************************************************
10 #include <Freeze/IndexI.h>
11 #include <Freeze/Util.h>
12 #include <Freeze/ObjectStore.h>
13 #include <Freeze/EvictorI.h>
15 #include <Ice/StringConverter.h>
17 using namespace Freeze;
18 using namespace Ice;
19 using namespace std;
22 static int
23 callback(Db* secondary, const Dbt* key, const Dbt* value, Dbt* result)
25 void* indexObj = secondary->get_app_private();
26 IndexI* index = static_cast<IndexI*>(indexObj);
27 assert(index != 0);
28 return index->secondaryKeyCreate(secondary, key, value, result);
32 Freeze::IndexI::IndexI(Index& index) :
33 _index(index),
34 _store(0)
38 vector<Identity>
39 Freeze::IndexI::untypedFindFirst(const Key& bytes, Int firstN) const
41 DeactivateController::Guard
42 deactivateGuard(_store->evictor()->deactivateController());
44 Dbt dbKey;
45 initializeInDbt(bytes, dbKey);
47 // When we have a custom-comparison function, Berkeley DB returns
48 // the key on-disk (when it finds one). We disable this behavior:
49 // (ref Oracle SR 5925672.992)
51 dbKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
53 Key pkey(1024);
54 Dbt pdbKey;
55 initializeOutDbt(pkey, pdbKey);
57 Dbt dbValue;
58 dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
60 Ice::CommunicatorPtr communicator = _store->communicator();
62 TransactionIPtr transaction = _store->evictor()->beforeQuery();
63 DbTxn* tx = transaction == 0 ? 0 : transaction->dbTxn();
65 vector<Identity> identities;
67 try
69 for(;;)
71 Dbc* dbc = 0;
72 identities.clear();
74 try
77 // Move to the first record
78 //
79 _db->cursor(tx, &dbc, 0);
80 u_int32_t flags = DB_SET;
82 bool found;
86 for(;;)
88 try
91 // It is critical to set key size to key capacity before the
92 // get, as a resize that increases the size inserts 0
94 pkey.resize(pkey.capacity());
96 found = (dbc->pget(&dbKey, &pdbKey, &dbValue, flags) == 0);
97 if(found)
99 pkey.resize(pdbKey.get_size());
101 Ice::Identity ident;
102 ObjectStoreBase::unmarshal(ident, pkey, communicator);
103 identities.push_back(ident);
104 flags = DB_NEXT_DUP;
106 break; // for(;;)
108 catch(const DbDeadlockException&)
110 throw;
112 catch(const DbException& dx)
114 handleDbException(dx, pkey, pdbKey, __FILE__, __LINE__);
118 while((firstN <= 0 || identities.size() < static_cast<size_t>(firstN)) && found);
120 Dbc* toClose = dbc;
121 dbc = 0;
122 toClose->close();
123 break; // for (;;)
125 catch(const DbDeadlockException&)
127 if(dbc != 0)
131 dbc->close();
133 catch(const DbDeadlockException&)
135 if(tx != 0)
137 throw;
139 // Else ignored
143 if(_store->evictor()->deadlockWarning())
145 Warning out(_store->communicator()->getLogger());
146 out << "Deadlock in Freeze::IndexI::untypedFindFirst while searching \""
147 << _store->evictor()->filename() + "/" + _dbName << "\"; retrying ...";
150 if(tx != 0)
152 throw;
154 // Else retry
156 catch(...)
158 if(dbc != 0)
162 dbc->close();
164 catch(const DbDeadlockException&)
166 if(tx != 0)
168 throw;
170 // Else ignored
173 throw;
177 catch(const DbDeadlockException& dx)
179 throw DeadlockException(__FILE__, __LINE__, dx.what(), transaction);
181 catch(const DbException& dx)
183 handleDbException(dx, __FILE__, __LINE__);
186 return identities;
189 vector<Identity>
190 Freeze::IndexI::untypedFind(const Key& bytes) const
192 return untypedFindFirst(bytes, 0);
196 Freeze::IndexI::untypedCount(const Key& bytes) const
198 DeactivateController::Guard
199 deactivateGuard(_store->evictor()->deactivateController());
201 Dbt dbKey;
202 initializeInDbt(bytes, dbKey);
204 // When we have a custom-comparison function, Berkeley DB returns
205 // the key on-disk (when it finds one). We disable this behavior:
206 // (ref Oracle SR 5925672.992)
208 dbKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
210 Dbt dbValue;
211 dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
213 TransactionIPtr transaction = _store->evictor()->beforeQuery();
214 DbTxn* tx = transaction == 0 ? 0 : transaction->dbTxn();
216 Int result = 0;
220 for(;;)
222 Dbc* dbc = 0;
227 // Move to the first record
229 _db->cursor(tx, &dbc, 0);
230 bool found = (dbc->get(&dbKey, &dbValue, DB_SET) == 0);
232 if(found)
234 db_recno_t count = 0;
235 dbc->count(&count, 0);
236 result = static_cast<Int>(count);
239 Dbc* toClose = dbc;
240 dbc = 0;
241 toClose->close();
242 break; // for (;;)
244 catch(const DbDeadlockException&)
246 if(dbc != 0)
250 dbc->close();
252 catch(const DbDeadlockException&)
254 if(tx != 0)
256 throw;
258 // Else ignored
262 if(_store->evictor()->deadlockWarning())
264 Warning out(_store->communicator()->getLogger());
265 out << "Deadlock in Freeze::IndexI::untypedCount while searching \""
266 << _store->evictor()->filename() + "/" + _dbName << "\"; retrying ...";
269 if(tx != 0)
271 throw;
273 // Else retry
276 catch(...)
278 if(dbc != 0)
282 dbc->close();
284 catch(const DbDeadlockException&)
286 if(tx != 0)
288 throw;
290 // Else ignored
293 throw;
297 catch(const DbDeadlockException& dx)
299 throw DeadlockException(__FILE__, __LINE__, dx.what(), transaction);
301 catch(const DbException& dx)
303 DatabaseException ex(__FILE__, __LINE__);
304 ex.message = dx.what();
305 throw ex;
308 return result;
311 void
312 Freeze::IndexI::associate(ObjectStoreBase* store, DbTxn* txn,
313 bool createDb, bool populateIndex)
315 assert(txn != 0);
316 _store = store;
317 _index._communicator = store->communicator();
319 _db.reset(new Db(store->evictor()->dbEnv()->getEnv(), 0));
320 _db->set_flags(DB_DUP | DB_DUPSORT);
321 _db->set_app_private(this);
323 _dbName = EvictorIBase::indexPrefix + store->dbName() + "." + _index.name();
325 Ice::PropertiesPtr properties = store->communicator()->getProperties();
326 string propPrefix = "Freeze.Evictor." + store->evictor()->filename() + ".";
328 int btreeMinKey = properties->getPropertyAsInt(propPrefix + _dbName + ".BtreeMinKey");
329 if(btreeMinKey > 2)
331 if(store->evictor()->trace() >= 1)
333 Trace out(store->evictor()->communicator()->getLogger(), "Freeze.Evictor");
334 out << "Setting \"" << store->evictor()->filename() + "." + _dbName << "\"'s btree minkey to " << btreeMinKey;
336 _db->set_bt_minkey(btreeMinKey);
339 bool checksum = properties->getPropertyAsInt(propPrefix + "Checksum") > 0;
340 if(checksum)
343 // No tracing on purpose
346 _db->set_flags(DB_CHKSUM);
350 // pagesize can't change
353 u_int32_t flags = 0;
354 if(createDb)
356 flags = DB_CREATE;
360 // We keep _dbName as a native string here, while it might have
361 // been better to convert it to UTF-8, changing this isn't
362 // possible without potentially breaking backward compatibility
363 // with deployed databases.
365 _db->open(txn, Ice::nativeToUTF8(store->communicator(), store->evictor()->filename()).c_str(), _dbName.c_str(),
366 DB_BTREE, flags, FREEZE_DB_MODE);
368 flags = 0;
369 if(populateIndex)
371 flags = DB_CREATE;
373 store->db()->associate(txn, _db.get(), callback, flags);
377 Freeze::IndexI::secondaryKeyCreate(Db* secondary, const Dbt* dbKey,
378 const Dbt* dbValue, Dbt* result)
380 Ice::CommunicatorPtr communicator = _store->communicator();
382 ObjectRecord rec;
383 Byte* first = static_cast<Byte*>(dbValue->get_data());
384 Value value(first, first + dbValue->get_size());
385 ObjectStoreBase::unmarshal(rec, value, communicator);
387 Key bytes;
388 if(_index.marshalKey(rec.servant, bytes))
390 result->set_flags(DB_DBT_APPMALLOC);
391 void* data = malloc(bytes.size());
392 memcpy(data, &bytes[0], bytes.size());
393 result->set_data(data);
394 result->set_size(static_cast<u_int32_t>(bytes.size()));
395 return 0;
397 else
400 // Don't want to index this one
402 return DB_DONOTINDEX;
406 void
407 Freeze::IndexI::close()
409 if(_db.get() != 0)
413 _db->close(0);
415 catch(const DbException& dx)
417 throw DatabaseException(__FILE__, __LINE__, dx.what());
419 _db.reset(0);