blob: 7b7deb5a68b2478aaec0d568e5c44d38ad2c9c53 [file] [log] [blame]
// 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 "content/browser/leveldb_wrapper_impl.h"
#include "base/bind.h"
#include "mojo/common/common_type_converters.h"
namespace content {
LevelDBWrapperImpl::LevelDBWrapperImpl(
leveldb::LevelDBDatabase* database,
const std::string& prefix,
size_t max_size,
const base::Closure& no_bindings_callback)
: prefix_(prefix),
no_bindings_callback_(no_bindings_callback),
database_(database),
bytes_used_(0),
max_size_(max_size) {
bindings_.set_connection_error_handler(base::Bind(
&LevelDBWrapperImpl::OnConnectionError, base::Unretained(this)));
}
void LevelDBWrapperImpl::Bind(mojom::LevelDBWrapperRequest request) {
bindings_.AddBinding(this, std::move(request));
}
void LevelDBWrapperImpl::AddObserver(mojom::LevelDBObserverPtr observer) {
observers_.AddPtr(std::move(observer));
}
LevelDBWrapperImpl::~LevelDBWrapperImpl() {}
void LevelDBWrapperImpl::Put(mojo::Array<uint8_t> key,
mojo::Array<uint8_t> value,
const mojo::String& source,
const PutCallback& callback) {
bool has_old_item = false;
mojo::Array<uint8_t> old_value;
size_t old_item_size = 0;
auto found = map_.find(key);
if (found != map_.end()) {
old_value = std::move(found->second);
old_item_size = key.size() + old_value.size();
has_old_item = true;
}
size_t new_item_size = key.size() + value.size();
size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size;
// Only check quota if the size is increasing, this allows
// shrinking changes to pre-existing maps that are over budget.
if (new_item_size > old_item_size && new_bytes_used > max_size_) {
callback.Run(false);
return;
}
map_[key.Clone()] = value.Clone();
bytes_used_ = new_bytes_used;
if (!has_old_item) {
// We added a new key/value pair.
observers_.ForAllPtrs(
[&key, &value, &source](mojom::LevelDBObserver* observer) {
observer->KeyAdded(key.Clone(), value.Clone(), source);
});
} else {
// We changed the value for an existing key.
observers_.ForAllPtrs(
[&key, &value, &source, &old_value](mojom::LevelDBObserver* observer) {
observer->KeyChanged(
key.Clone(), value.Clone(), old_value.Clone(), source);
});
}
callback.Run(true);
}
void LevelDBWrapperImpl::Delete(mojo::Array<uint8_t> key,
const mojo::String& source,
const DeleteCallback& callback) {
auto found = map_.find(key);
if (found == map_.end()) {
callback.Run(true);
return;
}
mojo::Array<uint8_t> old_value = std::move(found->second);
map_.erase(found);
bytes_used_ -= key.size() + old_value.size();
observers_.ForAllPtrs(
[&key, &source, &old_value](mojom::LevelDBObserver* observer) {
observer->KeyDeleted(
key.Clone(), old_value.Clone(), source);
});
callback.Run(true);
}
void LevelDBWrapperImpl::DeleteAll(const mojo::String& source,
const DeleteAllCallback& callback) {
map_.clear();
bytes_used_ = 0;
observers_.ForAllPtrs(
[&source](mojom::LevelDBObserver* observer) {
observer->AllDeleted(source);
});
callback.Run(true);
}
void LevelDBWrapperImpl::Get(mojo::Array<uint8_t> key,
const GetCallback& callback) {
auto found = map_.find(key);
if (found == map_.end()) {
callback.Run(false, mojo::Array<uint8_t>());
return;
}
callback.Run(true, found->second.Clone());
}
void LevelDBWrapperImpl::GetAll(const mojo::String& source,
const GetAllCallback& callback) {
mojo::Array<mojom::KeyValuePtr> all(map_.size());
for (const auto& it : map_) {
mojom::KeyValuePtr kv = mojom::KeyValue::New();
kv->key = it.first.Clone();
kv->value = it.second.Clone();
all.push_back(std::move(kv));
}
callback.Run(leveldb::DatabaseError::OK, std::move(all));
observers_.ForAllPtrs(
[source](mojom::LevelDBObserver* observer) {
observer->GetAllComplete(source);
});
}
void LevelDBWrapperImpl::OnConnectionError() {
if (!bindings_.empty())
return;
no_bindings_callback_.Run();
}
} // namespace content