// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "components/leveldb/leveldb_database_impl.h" #include #include #include "base/rand_util.h" #include "components/leveldb/env_mojo.h" #include "components/leveldb/public/cpp/util.h" #include "mojo/common/common_type_converters.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" #include "third_party/leveldatabase/src/include/leveldb/write_batch.h" namespace leveldb { namespace { template uint64_t GetSafeRandomId(const std::map& m) { // Associate a random unsigned 64 bit handle to |s|, checking for the highly // improbable id duplication or castability to null. uint64_t new_id = base::RandUint64(); while ((new_id == 0) || (m.find(new_id) != m.end())) new_id = base::RandUint64(); return new_id; } } // namespace LevelDBDatabaseImpl::LevelDBDatabaseImpl( leveldb::LevelDBDatabaseRequest request, scoped_ptr environment, scoped_ptr db) : binding_(this, std::move(request)), environment_(std::move(environment)), db_(std::move(db)) {} LevelDBDatabaseImpl::~LevelDBDatabaseImpl() { for (auto& p : iterator_map_) delete p.second; for (auto& p : snapshot_map_) db_->ReleaseSnapshot(p.second); } void LevelDBDatabaseImpl::Put(mojo::Array key, mojo::Array value, const PutCallback& callback) { leveldb::Status status = db_->Put(leveldb::WriteOptions(), GetSliceFor(key), GetSliceFor(value)); callback.Run(LeveldbStatusToError(status)); } void LevelDBDatabaseImpl::Delete(mojo::Array key, const DeleteCallback& callback) { leveldb::Status status = db_->Delete(leveldb::WriteOptions(), GetSliceFor(key)); callback.Run(LeveldbStatusToError(status)); } void LevelDBDatabaseImpl::Write(mojo::Array operations, const WriteCallback& callback) { leveldb::WriteBatch batch; for (size_t i = 0; i < operations.size(); ++i) { switch (operations[i]->type) { case BatchOperationType::PUT_KEY: { batch.Put(GetSliceFor(operations[i]->key), GetSliceFor(operations[i]->value)); break; } case BatchOperationType::DELETE_KEY: { batch.Delete(GetSliceFor(operations[i]->key)); break; } } } leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); callback.Run(LeveldbStatusToError(status)); } void LevelDBDatabaseImpl::Get(mojo::Array key, const GetCallback& callback) { std::string value; leveldb::Status status = db_->Get(leveldb::ReadOptions(), GetSliceFor(key), &value); callback.Run(LeveldbStatusToError(status), mojo::Array::From(value)); } void LevelDBDatabaseImpl::GetSnapshot(const GetSnapshotCallback& callback) { const Snapshot* s = db_->GetSnapshot(); uint64_t new_id = GetSafeRandomId(snapshot_map_); snapshot_map_.insert(std::make_pair(new_id, s)); callback.Run(new_id); } void LevelDBDatabaseImpl::ReleaseSnapshot(uint64_t snapshot_id) { auto it = snapshot_map_.find(snapshot_id); if (it != snapshot_map_.end()) { db_->ReleaseSnapshot(it->second); snapshot_map_.erase(it); } } void LevelDBDatabaseImpl::GetFromSnapshot(uint64_t snapshot_id, mojo::Array key, const GetCallback& callback) { // If the snapshot id is invalid, send back invalid argument auto it = snapshot_map_.find(snapshot_id); if (it == snapshot_map_.end()) { callback.Run(DatabaseError::INVALID_ARGUMENT, mojo::Array()); return; } std::string value; leveldb::ReadOptions options; options.snapshot = it->second; leveldb::Status status = db_->Get(options, GetSliceFor(key), &value); callback.Run(LeveldbStatusToError(status), mojo::Array::From(value)); } void LevelDBDatabaseImpl::NewIterator(const NewIteratorCallback& callback) { Iterator* iterator = db_->NewIterator(leveldb::ReadOptions()); uint64_t new_id = GetSafeRandomId(iterator_map_); iterator_map_.insert(std::make_pair(new_id, iterator)); callback.Run(new_id); } void LevelDBDatabaseImpl::NewIteratorFromSnapshot( uint64_t snapshot_id, const NewIteratorCallback& callback) { // If the snapshot id is invalid, send back invalid argument auto it = snapshot_map_.find(snapshot_id); if (it == snapshot_map_.end()) { callback.Run(0); return; } leveldb::ReadOptions options; options.snapshot = it->second; Iterator* iterator = db_->NewIterator(options); uint64_t new_id = GetSafeRandomId(iterator_map_); iterator_map_.insert(std::make_pair(new_id, iterator)); callback.Run(new_id); } void LevelDBDatabaseImpl::ReleaseIterator(uint64_t iterator_id) { auto it = iterator_map_.find(iterator_id); if (it != iterator_map_.end()) { delete it->second; iterator_map_.erase(it); } } void LevelDBDatabaseImpl::IteratorSeekToFirst( uint64_t iterator_id, const IteratorSeekToFirstCallback& callback) { auto it = iterator_map_.find(iterator_id); if (it == iterator_map_.end()) { callback.Run(false, DatabaseError::INVALID_ARGUMENT, nullptr, nullptr); return; } it->second->SeekToFirst(); ReplyToIteratorMessage(it->second, callback); } void LevelDBDatabaseImpl::IteratorSeekToLast( uint64_t iterator_id, const IteratorSeekToLastCallback& callback) { auto it = iterator_map_.find(iterator_id); if (it == iterator_map_.end()) { callback.Run(false, DatabaseError::INVALID_ARGUMENT, nullptr, nullptr); return; } it->second->SeekToLast(); ReplyToIteratorMessage(it->second, callback); } void LevelDBDatabaseImpl::IteratorSeek( uint64_t iterator_id, mojo::Array target, const IteratorSeekToLastCallback& callback) { auto it = iterator_map_.find(iterator_id); if (it == iterator_map_.end()) { callback.Run(false, DatabaseError::INVALID_ARGUMENT, nullptr, nullptr); return; } it->second->Seek(GetSliceFor(target)); ReplyToIteratorMessage(it->second, callback); } void LevelDBDatabaseImpl::IteratorNext(uint64_t iterator_id, const IteratorNextCallback& callback) { auto it = iterator_map_.find(iterator_id); if (it == iterator_map_.end()) { callback.Run(false, DatabaseError::INVALID_ARGUMENT, nullptr, nullptr); return; } it->second->Next(); ReplyToIteratorMessage(it->second, callback); } void LevelDBDatabaseImpl::IteratorPrev(uint64_t iterator_id, const IteratorPrevCallback& callback) { auto it = iterator_map_.find(iterator_id); if (it == iterator_map_.end()) { callback.Run(false, DatabaseError::INVALID_ARGUMENT, nullptr, nullptr); return; } it->second->Prev(); ReplyToIteratorMessage(it->second, callback); } void LevelDBDatabaseImpl::ReplyToIteratorMessage( leveldb::Iterator* it, const IteratorSeekToFirstCallback& callback) { if (!it->Valid()) { callback.Run(false, LeveldbStatusToError(it->status()), nullptr, nullptr); return; } callback.Run(true, LeveldbStatusToError(it->status()), GetArrayFor(it->key()), GetArrayFor(it->value())); } } // namespace leveldb