1 // **********************************************************************
3 // Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved.
5 // This copy of Ice is licensed to you under the terms described in the
6 // ICE_LICENSE file included in this distribution.
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
;
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
);
28 return index
->secondaryKeyCreate(secondary
, key
, value
, result
);
32 Freeze::IndexI::IndexI(Index
& index
) :
39 Freeze::IndexI::untypedFindFirst(const Key
& bytes
, Int firstN
) const
41 DeactivateController::Guard
42 deactivateGuard(_store
->evictor()->deactivateController());
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
);
55 initializeOutDbt(pkey
, pdbKey
);
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
;
77 // Move to the first record
79 _db
->cursor(tx
, &dbc
, 0);
80 u_int32_t flags
= DB_SET
;
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);
99 pkey
.resize(pdbKey
.get_size());
102 ObjectStoreBase::unmarshal(ident
, pkey
, communicator
);
103 identities
.push_back(ident
);
108 catch(const DbDeadlockException
&)
112 catch(const DbException
& dx
)
114 handleDbException(dx
, pkey
, pdbKey
, __FILE__
, __LINE__
);
118 while((firstN
<= 0 || identities
.size() < static_cast<size_t>(firstN
)) && found
);
125 catch(const DbDeadlockException
&)
133 catch(const DbDeadlockException
&)
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 ...";
164 catch(const DbDeadlockException
&)
177 catch(const DbDeadlockException
& dx
)
179 throw DeadlockException(__FILE__
, __LINE__
, dx
.what(), transaction
);
181 catch(const DbException
& dx
)
183 handleDbException(dx
, __FILE__
, __LINE__
);
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());
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
);
211 dbValue
.set_flags(DB_DBT_USERMEM
| DB_DBT_PARTIAL
);
213 TransactionIPtr transaction
= _store
->evictor()->beforeQuery();
214 DbTxn
* tx
= transaction
== 0 ? 0 : transaction
->dbTxn();
227 // Move to the first record
229 _db
->cursor(tx
, &dbc
, 0);
230 bool found
= (dbc
->get(&dbKey
, &dbValue
, DB_SET
) == 0);
234 db_recno_t count
= 0;
235 dbc
->count(&count
, 0);
236 result
= static_cast<Int
>(count
);
244 catch(const DbDeadlockException
&)
252 catch(const DbDeadlockException
&)
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 ...";
284 catch(const DbDeadlockException
&)
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();
312 Freeze::IndexI::associate(ObjectStoreBase
* store
, DbTxn
* txn
,
313 bool createDb
, bool populateIndex
)
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");
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;
343 // No tracing on purpose
346 _db
->set_flags(DB_CHKSUM
);
350 // pagesize can't change
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
);
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();
383 Byte
* first
= static_cast<Byte
*>(dbValue
->get_data());
384 Value
value(first
, first
+ dbValue
->get_size());
385 ObjectStoreBase::unmarshal(rec
, value
, communicator
);
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()));
400 // Don't want to index this one
402 return DB_DONOTINDEX
;
407 Freeze::IndexI::close()
415 catch(const DbException
& dx
)
417 throw DatabaseException(__FILE__
, __LINE__
, dx
.what());