//############################################################################## //############################################################################## boost::shared_ptr<BerkeleyDB> BerkeleyDB::get(const boost::shared_ptr<db::ConfigIface> db_config) { std::lock_guard<std::mutex> guard { inst_lock_ }; if(terminated_) { THROW_STACK(range::db::Exception("Cannot acquire instance of BerkeleyDB after terminal shutdown")); } if(!inst_) { inst_ = boost::shared_ptr<BerkeleyDB>(new BerkeleyDB(db_config)); } return inst_; }
//############################################################################## //############################################################################## BerkeleyDBCXXDb::BerkeleyDBCXXDb(const std::string &name, boost::shared_ptr<BerkeleyDB> backend, const boost::shared_ptr<db::ConfigIface> db_config, boost::shared_ptr<BerkeleyDBCXXEnv> env) : name_(name), backend_(backend), env_(env), db_config_(db_config), log(BerkeleyDBCXXDbLogModule) { RANGE_LOG_FUNCTION(); inst_ = boost::make_shared<Db>(env_->getEnv(), 0); int rval = 0; DbTxn * txn; try { rval = env_->getEnv()->txn_begin(NULL, &txn, DB_TXN_SYNC | DB_TXN_WAIT | DB_TXN_SNAPSHOT); } catch(DbException &e) { THROW_STACK(UnknownTransactionException(e.what())); } try { inst_->open(txn, name.c_str(), name.c_str(), DB_HASH, DB_CREATE | DB_MULTIVERSION | DB_THREAD, 0); } catch(DbException &e) { txn->abort(); THROW_STACK(DatabaseEnvironmentException(e.what())); } catch(std::exception &e) { txn->abort(); THROW_STACK(DatabaseEnvironmentException(e.what())); } switch(rval) { case 0: break; case ENOMEM: THROW_STACK(DatabaseEnvironmentException("The maximum number of concurrent transactions has been reached.")); } txn->commit(0); }
//############################################################################## //############################################################################## ChangeList BerkeleyDBCXXDb::read_changelist() const { RANGE_LOG_FUNCTION(); std::string buf = this->get_record(record_type::GRAPH_META, "changelist"); ChangeList changes; if(!buf.empty()) { changes.ParseFromString(buf); if(!changes.IsInitialized()) { THROW_STACK(DatabaseVersioningError("Changelist cannot be initialized")); } return changes; } changes.set_current_version(0); changes.mutable_change(); changes.mutable_unknown_fields(); return changes; //THROW_STACK(DatabaseVersioningError("Changelist cannot be read")); }
bool STACK_check(int need) { static VALUE *old = NULL; fprintf(stderr, "STACK_check: SP = %d need = %d limit = %d\n", (int)(((char *)SP - STACK_base) / sizeof(VALUE)), need, (int)((STACK_limit - STACK_base) / sizeof(VALUE))); if (SP > old) { fprintf(stderr, "**** STACK_check: -> %ld bytes\n", ((char *)SP - STACK_base)); old = SP; } if (((char *)(SP + need) + sizeof(STACK_CONTEXT)) >= STACK_limit) { THROW_STACK(); return TRUE; } else return FALSE; }
//############################################################################## //############################################################################## bool BerkeleyDBCXXDb::commit_record(change_t change) { RANGE_LOG_TIMED_FUNCTION(); std::string key, data; record_type type; uint64_t object_version; std::tie(type, key, object_version, data) = change; std::string fullkey = key_name(type, key); auto lck = boost::dynamic_pointer_cast<BerkeleyDBCXXLock>(this->write_lock(type, key)); DbTxn * dbtxn = BerkeleyDBCXXLockTxnGetter(lck).txn(); Dbt dbkey { (void*) fullkey.c_str(), (uint32_t) fullkey.size() }; Dbt dbdata { (void*) data.c_str(), (uint32_t) data.size() }; int dbrval = 0; try { dbrval = inst_->put(dbtxn, &dbkey, &dbdata, 0); } catch (DbException &e) { THROW_STACK(DatabaseEnvironmentException(std::string("Unable to read record") + e.what())); } catch (std::exception &e) { THROW_STACK(DatabaseEnvironmentException(std::string("Unable to read record") + e.what())); } switch(dbrval) { case 0: return true; break; case DB_LOCK_DEADLOCK: THROW_STACK(DatabaseEnvironmentException("A transactional database environment operation was selected to resolve a deadlock.")); break; case DB_LOCK_NOTGRANTED: THROW_STACK(DatabaseEnvironmentException("unable to grant a lock in the allowed time.")); break; case DB_REP_HANDLE_DEAD: THROW_STACK(DatabaseEnvironmentException("Dead handle")); break; case EACCES: THROW_STACK(DatabaseEnvironmentException("Database read-only")); break; default: LOG(error, "unknown_rval_from_Db_put") << dbrval; return false; } }
//############################################################################## //############################################################################## std::string BerkeleyDBCXXDb::get_record(record_type type, const std::string& key) const { RANGE_LOG_TIMED_FUNCTION(); std::string fullkey = key_name(type, key); auto txn = current_txn_.lock(); if(txn) { std::string data; if(txn->get_record(type, key, data)) { return data; } } auto lck = boost::dynamic_pointer_cast<BerkeleyDBCXXLock>(this->read_lock(type, key)); DbTxn * dbtxn = BerkeleyDBCXXLockTxnGetter(lck).txn(); Dbt dbkey { (void*) fullkey.c_str(), (uint32_t) fullkey.size() }; size_t bufsize = 131072; std::unique_ptr<char[]> buf { nullptr }; Dbt dbdata; int dbrval = 0; do { if(buf) { LOG(debug0, "resizing_record_buffer") << bufsize; } buf = std::unique_ptr<char[]>(new char[bufsize]); if(!buf) { std::stringstream s; s << "Unable to allocate buffer of size: " << bufsize; THROW_STACK(DatabaseEnvironmentException(s.str())); } dbdata = Dbt(buf.get(), bufsize); dbdata.set_ulen(bufsize); dbdata.set_flags(DB_DBT_USERMEM); bufsize *= 2; int flags = lck->readonly() ? 0 : DB_RMW; try { dbrval = inst_->get(dbtxn, &dbkey, &dbdata, flags); } catch (DbException &e) { if(e.get_errno() == DB_BUFFER_SMALL) { continue; } THROW_STACK(DatabaseEnvironmentException(std::string("Unable to read record") + e.what())); } catch (std::exception &e) { THROW_STACK(DatabaseEnvironmentException(std::string("Unable to read record") + e.what())); } } while(dbrval == DB_BUFFER_SMALL); switch(dbrval) { case 0: break; case DB_NOTFOUND: return std::string(); case DB_BUFFER_SMALL: THROW_STACK(DatabaseEnvironmentException("The requested item could not be returned due to undersized buffer.")); break; case DB_LOCK_DEADLOCK: THROW_STACK(DatabaseEnvironmentException("A transactional database environment operation was selected to resolve a deadlock.")); break; case DB_LOCK_NOTGRANTED: THROW_STACK(DatabaseEnvironmentException("unable to grant a lock in the allowed time.")); break; case DB_REP_HANDLE_DEAD: THROW_STACK(DatabaseEnvironmentException("Dead handle")); break; default: LOG(error, "unknown dbrval") << dbrval; } std::string rval { (char *) dbdata.get_data(), dbdata.get_size() }; return rval; }