Records Database::children(const RecordID& idParent) const { Records result; Dbc* pCursor = nullptr; dbParentId_.cursor(NULL, &pCursor, 0); assert(pCursor); BOOST_SCOPE_EXIT(&pCursor) { pCursor->close(); } BOOST_SCOPE_EXIT_END Dbt keyParent(idParent.data(), idParent.size()); Dbt keyChild; Dbt record; int res = pCursor->pget(&keyParent, &keyChild, &record, DB_SET); while (res == 0) { result.push_back(make_Record(RecordID(keyChild), RecordData(record))); res = pCursor->pget(&keyParent, &keyChild, &record, DB_NEXT_DUP); } return result; }
void Database::del(const RecordID& id) { Dbt key(id.data(), id.size()); // fetch children std::vector<RecordID> childrenIds; Dbc* pCursor = nullptr; dbParentId_.cursor(NULL, &pCursor, 0); assert(pCursor); BOOST_SCOPE_EXIT(&pCursor) { if(pCursor) pCursor->close(); } BOOST_SCOPE_EXIT_END Dbt keyChild; Dbt record; record.set_flags(DB_DBT_PARTIAL); record.set_doff(0); record.set_dlen(0); int res = pCursor->pget(&key, &keyChild, &record, DB_SET); while (res == 0) { childrenIds.push_back(RecordID(keyChild)); res = pCursor->pget(&key, &keyChild, &record, DB_NEXT_DUP); } if (res != DB_NOTFOUND) { throw DbException("Failed to obtain children ids", res); } pCursor->close(); pCursor = nullptr; // delete children for (const RecordID& childId : childrenIds) { del(childId); } // delete the record itself const int err = dbMain_.del(nullptr, &key, /*flags*/0); if (err && err != DB_NOTFOUND) { std::ostringstream ss; ss << "Failed to delete record id='" << id << '\''; throw DbException(ss.str().c_str(), err); } }
vector<Identity> Freeze::IndexI::untypedFindFirst(const Key& bytes, Int firstN) const { DeactivateController::Guard deactivateGuard(_store->evictor()->deactivateController()); Dbt dbKey; initializeInDbt(bytes, dbKey); // // When we have a custom-comparison function, Berkeley DB returns // the key on-disk (when it finds one). We disable this behavior: // (ref Oracle SR 5925672.992) // dbKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); Key pkey(1024); Dbt pdbKey; initializeOutDbt(pkey, pdbKey); Dbt dbValue; dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); Ice::CommunicatorPtr communicator = _store->communicator(); _store->evictor()->saveNow(); vector<Identity> identities; try { for(;;) { Dbc* dbc = 0; identities.clear(); try { // // Move to the first record // _db->cursor(0, &dbc, 0); u_int32_t flags = DB_SET; bool found; do { for(;;) { try { // // It is critical to set key size to key capacity before the // get, as a resize that increases the size inserts 0 // pkey.resize(pkey.capacity()); found = (dbc->pget(&dbKey, &pdbKey, &dbValue, flags) == 0); if(found) { pkey.resize(pdbKey.get_size()); Ice::Identity ident; ObjectStore::unmarshal(ident, pkey, communicator); identities.push_back(ident); flags = DB_NEXT_DUP; } break; // for(;;) } catch(const DbDeadlockException&) { throw; } catch(const DbException& dx) { handleDbException(dx, pkey, pdbKey, __FILE__, __LINE__); } } } while((firstN <= 0 || identities.size() < static_cast<size_t>(firstN)) && found); Dbc* toClose = dbc; dbc = 0; toClose->close(); break; // for (;;) } catch(const DbDeadlockException&) { if(dbc != 0) { try { dbc->close(); } catch(const DbDeadlockException&) { // // Ignored // } } if(_store->evictor()->deadlockWarning()) { Warning out(_store->communicator()->getLogger()); out << "Deadlock in Freeze::IndexI::untypedFindFirst while searching \"" << _store->evictor()->filename() + "/" + _dbName << "\"; retrying ..."; } // // Retry // } catch(...) { if(dbc != 0) { try { dbc->close(); } catch(const DbDeadlockException&) { // // Ignored // } } throw; } } } catch(const DbException& dx) { handleDbException(dx, __FILE__, __LINE__); } return identities; }
vector<Identity> Freeze::IndexI::untypedFindFirst(const Key& bytes, Int firstN) const { DeactivateController::Guard deactivateGuard(_store->evictor()->deactivateController()); Dbt dbKey; initializeInDbt(bytes, dbKey); #if (DB_VERSION_MAJOR <= 4) || (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR <= 1) // // When we have a custom-comparison function, Berkeley DB returns // the key on-disk (when it finds one). We disable this behavior: // (ref Oracle SR 5925672.992) // dbKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); #else // // In DB > 5.1 we can not set DB_DBT_PARTIAL in the key Dbt, // when using DB_SET, we must resize the Dbt key param to hold enought // space or Dbc::get fails with DB_BUFFER_SMALL. // dbKey.set_flags(DB_DBT_USERMEM); dbKey.set_ulen(static_cast<u_int32_t>(bytes.size())); #endif Key pkey(1024); Dbt pdbKey; initializeOutDbt(pkey, pdbKey); Dbt dbValue; dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); const Ice::CommunicatorPtr& communicator = _store->communicator(); const Ice::EncodingVersion& encoding = _store->encoding(); TransactionIPtr transaction = _store->evictor()->beforeQuery(); DbTxn* tx = transaction == 0 ? 0 : transaction->dbTxn(); vector<Identity> identities; try { for(;;) { Dbc* dbc = 0; identities.clear(); try { // // Move to the first record // _db->cursor(tx, &dbc, 0); u_int32_t flags = DB_SET; bool found; do { for(;;) { try { // // It is critical to set key size to key capacity before the // get, as a resize that increases the size inserts 0 // pkey.resize(pkey.capacity()); found = (dbc->pget(&dbKey, &pdbKey, &dbValue, flags) == 0); if(found) { pkey.resize(pdbKey.get_size()); Ice::Identity ident; ObjectStoreBase::unmarshal(ident, pkey, communicator, encoding); identities.push_back(ident); flags = DB_NEXT_DUP; } break; // for(;;) } catch(const DbDeadlockException&) { throw; } catch(const DbException& dx) { handleDbException(dx, pkey, pdbKey, __FILE__, __LINE__); } } } while((firstN <= 0 || identities.size() < static_cast<size_t>(firstN)) && found); Dbc* toClose = dbc; dbc = 0; toClose->close(); break; // for (;;) } catch(const DbDeadlockException&) { if(dbc != 0) { try { dbc->close(); } catch(const DbDeadlockException&) { if(tx != 0) { throw; } // Else ignored } } if(_store->evictor()->deadlockWarning()) { Warning out(_store->communicator()->getLogger()); out << "Deadlock in Freeze::IndexI::untypedFindFirst while searching \"" << _store->evictor()->filename() + "/" + _dbName << "\"; retrying ..."; } if(tx != 0) { throw; } // Else retry } catch(...) { if(dbc != 0) { try { dbc->close(); } catch(const DbDeadlockException&) { if(tx != 0) { throw; } // Else ignored } } throw; } } } catch(const DbDeadlockException& dx) { throw DeadlockException(__FILE__, __LINE__, dx.what(), transaction); } catch(const DbException& dx) { handleDbException(dx, __FILE__, __LINE__); } return identities; }