MojErr MojDbSandwichDatabase::get(MojDbSandwichItem& key, MojDbStorageTxn* txn, bool forUpdate, MojDbSandwichItem& valOut, bool& foundOut) { LOG_TRACE("Entering function %s", __FUNCTION__); //MojAssert(m_db); MojAssert( !txn || dynamic_cast<MojDbSandwichEnvTxn *> (txn) ); foundOut = false; std::string str; MojDbSandwichEnvTxn * leveldb_txn = static_cast<MojDbSandwichEnvTxn *> (txn); leveldb::Status s; if (leveldb_txn) s = leveldb_txn->ref(impl()).Get(*key.impl(), str); else s = m_db.Get(*key.impl(), str); if (s.IsNotFound()) return MojErrNone; // normal case MojLdbErrCheck(s, _T("db->get")); foundOut = true; valOut.fromBytes(reinterpret_cast<const MojByte*>(str.data()), str.size()); return MojErrNone; }
MojErr MojDbLevelTableTxn::commitImpl() { for(std::set<MojDbLevelTxnIterator*>::const_iterator i = m_iterators.begin(); i != m_iterators.end(); ++i) { (*i)->save(); } leveldb::WriteBatch writeBatch; for (PendingDeletes::iterator it = m_pendingDeletes.begin(); it != m_pendingDeletes.end(); ++it) { writeBatch.Delete(*it); } for (PendingValues::iterator it = m_pendingValues.begin(); it != m_pendingValues.end(); ++it) { writeBatch.Put(it->first, it->second); } leveldb::Status s = m_db->Write(m_writeOptions, &writeBatch); MojLdbErrCheck(s, _T("db->Write")); cleanup(); for(std::set<MojDbLevelTxnIterator*>::const_iterator i = m_iterators.begin(); i != m_iterators.end(); ++i) { (*i)->restore(); } return MojErrNone; }
MojErr MojDbSandwichEngine::open(const MojChar* path, MojDbEnv* env) { LOG_TRACE("Entering function %s", __FUNCTION__); MojDbSandwichEnv* bEnv = static_cast<MojDbSandwichEnv *> (env); MojAssert(bEnv); MojAssert(!m_env.get() && !m_isOpen); m_env.reset(bEnv); if (path) { MojErr err = m_path.assign(path); MojErrCheck(err); // create dir err = MojCreateDirIfNotPresent(path); MojErrCheck(err); } // TODO: consider moving to configure m_db->options = MojDbSandwichEngine::getOpenOptions(); m_db->writeOptions = MojDbSandwichEngine::getWriteOptions(); m_db->readOptions = MojDbSandwichEngine::getReadOptions(); leveldb::Status status = m_db->Open(path); if (status.IsCorruption()) { // database corrupted // try restore database // AHTUNG! After restore database can lost some data! status = leveldb::RepairDB(path, MojDbSandwichEngine::getOpenOptions()); MojLdbErrCheck(status, _T("db corrupted")); status = m_db->Open(path); // database restored, re-open } MojLdbErrCheck(status, _T("db_create/db_open")); // open seqence db m_seqDb.reset(new MojDbSandwichDatabase(m_db.use(MojEnvSeqDbName))); MojAllocCheck(m_seqDb.get()); MojErr err = m_seqDb->open(MojEnvSeqDbName, this); MojErrCheck(err); // open index db m_indexDb.reset(new MojDbSandwichDatabase(m_db.use(MojEnvIndexDbName))); MojAllocCheck(m_indexDb.get()); err = m_indexDb->open(MojEnvIndexDbName, this); MojErrCheck(err); m_isOpen = true; return MojErrNone; }
MojErr MojDbLevelDatabase::open(const MojChar* dbName, MojDbLevelEngine* eng, bool& createdOut, MojDbStorageTxn* txn) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(dbName && eng); MojAssert(!txn || txn->isValid()); // save eng, name and file createdOut = false; m_engine = eng; MojErr err = m_name.assign(dbName); MojErrCheck(err); const MojString& engPath = eng->path(); if (engPath.empty()) { err = m_file.assign(dbName); MojErrCheck(err); } else { err = m_file.format(_T("%s/%s"), engPath.data(), dbName); MojErrCheck(err); } // create and open db leveldb::Status status = leveldb::DB::Open(MojDbLevelEngine::getOpenOptions(), m_file.data(), &m_db); if (status.IsCorruption()) { // database corrupted // try restore database // AHTUNG! After restore database can lost some data! status = leveldb::RepairDB(m_file.data(), MojDbLevelEngine::getOpenOptions()); MojLdbErrCheck(status, _T("db corrupted")); status = leveldb::DB::Open(MojDbLevelEngine::getOpenOptions(), m_file.data(), &m_db); // database restored, re-open } MojLdbErrCheck(status, _T("db_create")); MojAssert(m_db); // set up prop-vec for primary key queries MojString idStr; err = idStr.assign(MojDb::IdKey); MojErrCheck(err); err = m_primaryProps.push(idStr); MojErrCheck(err); //keep a reference to this database err = eng->addDatabase(this); MojErrCheck(err); return MojErrNone; }
MojErr MojDbSandwichDatabase::put(MojDbSandwichItem& key, MojDbSandwichItem& val, MojDbStorageTxn* txn, bool updateIdQuota) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(m_db.Valid() ); MojAssert( !txn || dynamic_cast<MojDbSandwichEnvTxn *> (txn) ); MojErr err; if (txn) { MojInt64 quotaOffset = val.size(); if (updateIdQuota) quotaOffset += key.size(); err = txn->offsetQuota(quotaOffset); MojErrCheck(err); } MojDbSandwichEnvTxn * leveldb_txn = static_cast<MojDbSandwichEnvTxn *> (txn); leveldb::Status s; if(leveldb_txn) { s = leveldb_txn->ref(impl()).Put(*key.impl(), *val.impl()); } else s = m_db.Put(*key.impl(), *val.impl()); #if defined(MOJ_DEBUG) char str_buf[1024]; size_t size1 = key.size(); size_t size2 = val.size(); MojErr err2 = MojByteArrayToHex(key.data(), size1, str_buf); MojErrCheck(err2); if (size1 > 16) // if the object-id is in key strncat(str_buf, (char *)(key.data()) + (size1 - 17), 16); LOG_DEBUG("[db_ldb] ldb put: %s; keylen: %zu, key: %s ; vallen = %zu; err = %s\n", this->m_name.data(), size1, str_buf, size2, s.ToString().c_str()); #endif /* if(leveldb_txn) ;//MojLdbErrCheck(batch->status(), _T("db->put")); else */ MojLdbErrCheck(s, _T("db->put")); postUpdate(txn, key.size() + val.size()); return MojErrNone; }
MojErr MojDbSandwichEngine::openDatabase(const MojChar* name, MojDbStorageTxn* txn, MojRefCountedPtr<MojDbStorageDatabase>& dbOut) { MojAssert(name && !dbOut.get()); BackendDb::Cookie cookie; leveldb::Status status = m_db.cook(name, cookie); MojLdbErrCheck(status, "openDatabase"); MojRefCountedPtr<MojDbSandwichDatabase> db(new MojDbSandwichDatabase(m_db.use(cookie))); MojAllocCheck(db.get()); MojErr err = db->open(name, this); MojErrCheck(err); dbOut = db; return MojErrNone; }
MojErr MojDbSandwichDatabase::delPrefix(MojDbSandwichEnvTxn &txn, leveldb::Slice prefix) { auto part = txn.ref(m_db); auto it = part.NewIterator(); it->Seek(prefix); while (it->Valid() && it->key().starts_with(prefix)) { auto key = it->key(); size_t delSize = key.size() + it->value().size(); MojErr err = txn.offsetQuota(-(MojInt64) delSize); MojErrCheck(err); auto s = part.Delete(key); MojLdbErrCheck(s, _T("db->delPrefix")); it->Next(); // skip this ghost record } return MojErrNone; }
MojErr MojDbLevelDatabase::del(MojDbLevelItem& key, bool& foundOut, MojDbStorageTxn* txn) { LOG_TRACE("Entering function %s", __FUNCTION__); MojAssert(m_db); MojAssert( !txn || dynamic_cast<MojDbLevelAbstractTxn *> (txn) ); foundOut = false; MojErr err = txn->offsetQuota(-(MojInt64) key.size()); MojErrCheck(err); MojDbLevelAbstractTxn * leveldb_txn = static_cast<MojDbLevelAbstractTxn *> (txn); leveldb::Status st; if(leveldb_txn) { leveldb_txn->tableTxn(impl()).Delete(*key.impl()); } else st = m_db->Delete(MojDbLevelEngine::getWriteOptions(), *key.impl()); #if defined(MOJ_DEBUG) char str_buf[1024]; // big enough for any key size_t size = key.size(); MojErr err2 = MojByteArrayToHex(key.data(), size, str_buf); MojErrCheck(err2); if (size > 16) // if the object-id is in key strncat(str_buf, (char *)(key.data()) + (size - 17), 16); LOG_DEBUG("[db_ldb] ldbdel: %s; keylen: %zu, key= %s; err = %d \n", this->m_name.data(), size, str_buf, !st.ok()); #endif if (st.IsNotFound() == false) { MojLdbErrCheck(st, _T("db->del")); foundOut = true; } postUpdate(txn, key.size()); return MojErrNone; }
MojErr MojDbSandwichEngine::open(const MojChar* path) { MojAssert(path); MojAssert(m_env.get()); MojAssert(!m_isOpen); MojErr err; err = m_path.assign(path); MojErrCheck(err); // TODO: We should get this options from ENV m_db->options = MojDbSandwichEngine::getOpenOptions(); m_db->writeOptions = MojDbSandwichEngine::getWriteOptions(); m_db->readOptions = MojDbSandwichEngine::getReadOptions(); leveldb::Status status = m_db->Open(path); MojLdbErrCheck(status, _T("db_create/db_open")); // open seqence db m_seqDb.reset(new MojDbSandwichDatabase(m_db.use(MojEnvSeqDbName))); MojAllocCheck(m_seqDb.get()); err = m_seqDb->open(MojEnvSeqDbName, this); MojErrCheck(err); // open index db m_indexDb.reset(new MojDbSandwichDatabase(m_db.use(MojEnvIndexDbName))); MojAllocCheck(m_indexDb.get()); err = m_indexDb->open(MojEnvIndexDbName, this); MojErrCheck(err); m_isOpen = true; return MojErrNone; }