blob: 3200b302366b4691d26c7741a93fb6deea69d4be [file] [log] [blame]
// Copyright 2014 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 "chrome/browser/sync_file_system/drive_backend/leveldb_wrapper.h"
#include <map>
#include <set>
#include <string>
#include "base/logging.h"
#include "third_party/leveldatabase/src/include/leveldb/db.h"
#include "third_party/leveldatabase/src/include/leveldb/iterator.h"
#include "third_party/leveldatabase/src/include/leveldb/slice.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
#include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
namespace sync_file_system {
namespace drive_backend {
LevelDBWrapper::Iterator::Iterator(LevelDBWrapper* db)
: db_(db),
db_iterator_(db->db_->NewIterator(leveldb::ReadOptions())),
map_iterator_(db->pending_.end()) {}
LevelDBWrapper::Iterator::~Iterator() {}
bool LevelDBWrapper::Iterator::Valid() {
return map_iterator_ != db_->pending_.end() ||
db_iterator_->Valid();
}
void LevelDBWrapper::Iterator::SeekToFirst() {
map_iterator_ = db_->pending_.begin();
db_iterator_->SeekToFirst();
AdvanceIterators();
}
void LevelDBWrapper::Iterator::SeekToLast() {
map_iterator_ = db_->pending_.end();
db_iterator_->SeekToLast();
}
void LevelDBWrapper::Iterator::Seek(const std::string& target) {
map_iterator_ = db_->pending_.lower_bound(target);
db_iterator_->Seek(target);
AdvanceIterators();
}
void LevelDBWrapper::Iterator::Next() {
if (map_iterator_ == db_->pending_.end()) {
if (db_iterator_->Valid())
db_iterator_->Next();
return;
}
if (db_iterator_->Valid()) {
int comp = db_iterator_->key().compare(map_iterator_->first);
if (comp <= 0)
db_iterator_->Next();
if (comp >= 0)
++map_iterator_;
} else {
++map_iterator_;
}
AdvanceIterators();
}
leveldb::Slice LevelDBWrapper::Iterator::key() {
DCHECK(Valid());
if (!db_iterator_->Valid())
return map_iterator_->first;
if (map_iterator_ == db_->pending_.end())
return db_iterator_->key();
const leveldb::Slice db_key = db_iterator_->key();
const leveldb::Slice map_key = map_iterator_->first;
return (db_key.compare(map_key) < 0) ? db_key : map_key;
}
leveldb::Slice LevelDBWrapper::Iterator::value() {
DCHECK(Valid());
if (!db_iterator_->Valid())
return map_iterator_->second.second;
if (map_iterator_ == db_->pending_.end())
return db_iterator_->value();
const leveldb::Slice db_key = db_iterator_->key();
const leveldb::Slice map_key = map_iterator_->first;
if (db_key.compare(map_key) < 0)
return db_iterator_->value();
DCHECK(map_iterator_->second.first == PUT_OPERATION);
return map_iterator_->second.second;
}
void LevelDBWrapper::Iterator::AdvanceIterators() {
// Iterator is valid iff any of below holds:
// - |db_itr.key| < |map_itr.key| OR |map_itr| == end()
// - (|db_itr.key| >= |map_itr.key| OR !|db_itr|->IsValid())
// AND |map_itr.operation| == PUT_OPERATION
if (map_iterator_ == db_->pending_.end())
return;
while (map_iterator_ != db_->pending_.end() && db_iterator_->Valid()) {
int cmp_key = db_iterator_->key().compare(map_iterator_->first);
if (cmp_key < 0 || map_iterator_->second.first == PUT_OPERATION)
return;
// |db_itr.key| >= |map_itr.key| && |map_itr.operation| != PUT_OPERATION
if (cmp_key == 0)
db_iterator_->Next();
++map_iterator_;
}
if (db_iterator_->Valid())
return;
while (map_iterator_ != db_->pending_.end() &&
map_iterator_->second.first == DELETE_OPERATION)
++map_iterator_;
}
// ---------------------------------------------------------------------------
// LevelDBWrapper class
// ---------------------------------------------------------------------------
LevelDBWrapper::LevelDBWrapper(scoped_ptr<leveldb::DB> db)
: db_(db.Pass()) {
DCHECK(db_);
}
LevelDBWrapper::~LevelDBWrapper() {}
void LevelDBWrapper::Put(const std::string& key,
const std::string& value) {
pending_[key] = Transaction(PUT_OPERATION, value);
}
void LevelDBWrapper::Delete(const std::string& key) {
pending_[key] = Transaction(DELETE_OPERATION, std::string());
}
leveldb::Status LevelDBWrapper::Get(const std::string& key,
std::string* value) {
PendingOperationMap::iterator itr = pending_.find(key);
if (itr == pending_.end())
return db_->Get(leveldb::ReadOptions(), key, value);
const Transaction& transaction = itr->second;
switch (transaction.first) {
case PUT_OPERATION:
*value = transaction.second;
return leveldb::Status();
case DELETE_OPERATION:
return leveldb::Status::NotFound(leveldb::Slice());
}
NOTREACHED();
return leveldb::Status::NotSupported("Not supported operation.");
}
scoped_ptr<LevelDBWrapper::Iterator> LevelDBWrapper::NewIterator() {
return make_scoped_ptr(new Iterator(this));
}
leveldb::Status LevelDBWrapper::Commit() {
leveldb::WriteBatch batch;
for (PendingOperationMap::iterator itr = pending_.begin();
itr != pending_.end(); ++itr) {
const leveldb::Slice key(itr->first);
const Transaction& transaction = itr->second;
switch (transaction.first) {
case PUT_OPERATION:
batch.Put(key, transaction.second);
break;
case DELETE_OPERATION:
batch.Delete(key);
break;
}
}
leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch);
// TODO(peria): Decide what to do depending on |status|.
if (status.ok())
Clear();
return status;
}
void LevelDBWrapper::Clear() {
pending_.clear();
}
leveldb::DB* LevelDBWrapper::GetLevelDB() {
return db_.get();
}
} // namespace drive_backend
} // namespace sync_file_system