| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/leveldb_wrapper_impl.h" | 5 #include "content/browser/leveldb_wrapper_impl.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/threading/thread_task_runner_handle.h" | 8 #include "base/threading/thread_task_runner_handle.h" |
| 9 #include "content/public/browser/browser_thread.h" | 9 #include "content/public/browser/browser_thread.h" |
| 10 #include "mojo/common/common_type_converters.h" | 10 #include "mojo/common/common_type_converters.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 } | 32 } |
| 33 | 33 |
| 34 LevelDBWrapperImpl::CommitBatch::CommitBatch() : clear_all_first(false) {} | 34 LevelDBWrapperImpl::CommitBatch::CommitBatch() : clear_all_first(false) {} |
| 35 LevelDBWrapperImpl::CommitBatch::~CommitBatch() {} | 35 LevelDBWrapperImpl::CommitBatch::~CommitBatch() {} |
| 36 | 36 |
| 37 size_t LevelDBWrapperImpl::CommitBatch::GetDataSize() const { | 37 size_t LevelDBWrapperImpl::CommitBatch::GetDataSize() const { |
| 38 if (changed_values.empty()) | 38 if (changed_values.empty()) |
| 39 return 0; | 39 return 0; |
| 40 | 40 |
| 41 size_t count = 0; | 41 size_t count = 0; |
| 42 for (const auto& pair : changed_values) | 42 for (const auto& pair : changed_values) { |
| 43 count += (pair.first.size(), pair.second.size()); | 43 count += pair.first.size(); |
| 44 if (pair.second) |
| 45 count += pair.second->size(); |
| 46 } |
| 44 return count; | 47 return count; |
| 45 } | 48 } |
| 46 | 49 |
| 47 LevelDBWrapperImpl::LevelDBWrapperImpl( | 50 LevelDBWrapperImpl::LevelDBWrapperImpl( |
| 48 leveldb::mojom::LevelDBDatabase* database, | 51 leveldb::mojom::LevelDBDatabase* database, |
| 49 const std::string& prefix, | 52 const std::string& prefix, |
| 50 size_t max_size, | 53 size_t max_size, |
| 51 base::TimeDelta default_commit_delay, | 54 base::TimeDelta default_commit_delay, |
| 52 int max_bytes_per_hour, | 55 int max_bytes_per_hour, |
| 53 int max_commits_per_hour, | 56 int max_commits_per_hour, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 76 } | 79 } |
| 77 | 80 |
| 78 void LevelDBWrapperImpl::AddObserver(mojom::LevelDBObserverPtr observer) { | 81 void LevelDBWrapperImpl::AddObserver(mojom::LevelDBObserverPtr observer) { |
| 79 observers_.AddPtr(std::move(observer)); | 82 observers_.AddPtr(std::move(observer)); |
| 80 } | 83 } |
| 81 | 84 |
| 82 void LevelDBWrapperImpl::EnableAggressiveCommitDelay() { | 85 void LevelDBWrapperImpl::EnableAggressiveCommitDelay() { |
| 83 s_aggressive_flushing_enabled_ = true; | 86 s_aggressive_flushing_enabled_ = true; |
| 84 } | 87 } |
| 85 | 88 |
| 86 void LevelDBWrapperImpl::Put(mojo::Array<uint8_t> key, | 89 void LevelDBWrapperImpl::Put(const std::vector<uint8_t>& key, |
| 87 mojo::Array<uint8_t> value, | 90 const std::vector<uint8_t>& value, |
| 88 const mojo::String& source, | 91 const std::string& source, |
| 89 const PutCallback& callback) { | 92 const PutCallback& callback) { |
| 90 if (!map_) { | 93 if (!map_) { |
| 91 LoadMap( | 94 LoadMap(base::Bind(&LevelDBWrapperImpl::Put, base::Unretained(this), key, |
| 92 base::Bind(&LevelDBWrapperImpl::Put, base::Unretained(this), | 95 value, source, callback)); |
| 93 base::Passed(&key), base::Passed(&value), source, callback)); | |
| 94 return; | 96 return; |
| 95 } | 97 } |
| 96 | 98 |
| 97 bool has_old_item = false; | 99 bool has_old_item = false; |
| 98 mojo::Array<uint8_t> old_value; | |
| 99 size_t old_item_size = 0; | 100 size_t old_item_size = 0; |
| 100 auto found = map_->find(key); | 101 auto found = map_->find(key); |
| 101 if (found != map_->end()) { | 102 if (found != map_->end()) { |
| 102 if (found->second.Equals(value)) { | 103 if (found->second == value) { |
| 103 callback.Run(true); // Key already has this value. | 104 callback.Run(true); // Key already has this value. |
| 104 return; | 105 return; |
| 105 } | 106 } |
| 106 old_value = std::move(found->second); | 107 old_item_size = key.size() + found->second.size(); |
| 107 old_item_size = key.size() + old_value.size(); | |
| 108 has_old_item = true; | 108 has_old_item = true; |
| 109 } | 109 } |
| 110 size_t new_item_size = key.size() + value.size(); | 110 size_t new_item_size = key.size() + value.size(); |
| 111 size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size; | 111 size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size; |
| 112 | 112 |
| 113 // Only check quota if the size is increasing, this allows | 113 // Only check quota if the size is increasing, this allows |
| 114 // shrinking changes to pre-existing maps that are over budget. | 114 // shrinking changes to pre-existing maps that are over budget. |
| 115 if (new_item_size > old_item_size && new_bytes_used > max_size_) { | 115 if (new_item_size > old_item_size && new_bytes_used > max_size_) { |
| 116 callback.Run(false); | 116 callback.Run(false); |
| 117 return; | 117 return; |
| 118 } | 118 } |
| 119 | 119 |
| 120 if (database_) { | 120 if (database_) { |
| 121 CreateCommitBatchIfNeeded(); | 121 CreateCommitBatchIfNeeded(); |
| 122 commit_batch_->changed_values[key.Clone()] = value.Clone(); | 122 commit_batch_->changed_values[key] = value; |
| 123 } | 123 } |
| 124 | 124 |
| 125 (*map_)[key.Clone()] = value.Clone(); | 125 std::vector<uint8_t> old_value; |
| 126 if (has_old_item) { |
| 127 old_value.swap((*map_)[key]); |
| 128 } |
| 129 (*map_)[key] = value; |
| 126 bytes_used_ = new_bytes_used; | 130 bytes_used_ = new_bytes_used; |
| 127 if (!has_old_item) { | 131 if (!has_old_item) { |
| 128 // We added a new key/value pair. | 132 // We added a new key/value pair. |
| 129 observers_.ForAllPtrs( | 133 observers_.ForAllPtrs( |
| 130 [&key, &value, &source](mojom::LevelDBObserver* observer) { | 134 [&key, &value, &source](mojom::LevelDBObserver* observer) { |
| 131 observer->KeyAdded(key.Clone(), value.Clone(), source); | 135 observer->KeyAdded(key, value, source); |
| 132 }); | 136 }); |
| 133 } else { | 137 } else { |
| 134 // We changed the value for an existing key. | 138 // We changed the value for an existing key. |
| 135 observers_.ForAllPtrs( | 139 observers_.ForAllPtrs( |
| 136 [&key, &value, &source, &old_value](mojom::LevelDBObserver* observer) { | 140 [&key, &value, &source, &old_value](mojom::LevelDBObserver* observer) { |
| 137 observer->KeyChanged( | 141 observer->KeyChanged(key, value, old_value, source); |
| 138 key.Clone(), value.Clone(), old_value.Clone(), source); | |
| 139 }); | 142 }); |
| 140 } | 143 } |
| 141 callback.Run(true); | 144 callback.Run(true); |
| 142 } | 145 } |
| 143 | 146 |
| 144 void LevelDBWrapperImpl::Delete(mojo::Array<uint8_t> key, | 147 void LevelDBWrapperImpl::Delete(const std::vector<uint8_t>& key, |
| 145 const mojo::String& source, | 148 const std::string& source, |
| 146 const DeleteCallback& callback) { | 149 const DeleteCallback& callback) { |
| 147 if (!map_) { | 150 if (!map_) { |
| 148 LoadMap( | 151 LoadMap(base::Bind(&LevelDBWrapperImpl::Delete, base::Unretained(this), key, |
| 149 base::Bind(&LevelDBWrapperImpl::Delete, base::Unretained(this), | 152 source, callback)); |
| 150 base::Passed(&key), source, callback)); | |
| 151 return; | 153 return; |
| 152 } | 154 } |
| 153 | 155 |
| 154 auto found = map_->find(key); | 156 auto found = map_->find(key); |
| 155 if (found == map_->end()) { | 157 if (found == map_->end()) { |
| 156 callback.Run(true); | 158 callback.Run(true); |
| 157 return; | 159 return; |
| 158 } | 160 } |
| 159 | 161 |
| 160 if (database_) { | 162 if (database_) { |
| 161 CreateCommitBatchIfNeeded(); | 163 CreateCommitBatchIfNeeded(); |
| 162 commit_batch_->changed_values[key.Clone()] = mojo::Array<uint8_t>(nullptr); | 164 commit_batch_->changed_values[key] = base::nullopt; |
| 163 } | 165 } |
| 164 | 166 |
| 165 mojo::Array<uint8_t> old_value = std::move(found->second); | 167 std::vector<uint8_t> old_value(std::move(found->second)); |
| 166 map_->erase(found); | 168 map_->erase(found); |
| 167 bytes_used_ -= key.size() + old_value.size(); | 169 bytes_used_ -= key.size() + old_value.size(); |
| 168 observers_.ForAllPtrs( | 170 observers_.ForAllPtrs( |
| 169 [&key, &source, &old_value](mojom::LevelDBObserver* observer) { | 171 [&key, &source, &old_value](mojom::LevelDBObserver* observer) { |
| 170 observer->KeyDeleted( | 172 observer->KeyDeleted(key, old_value, source); |
| 171 key.Clone(), old_value.Clone(), source); | |
| 172 }); | 173 }); |
| 173 callback.Run(true); | 174 callback.Run(true); |
| 174 } | 175 } |
| 175 | 176 |
| 176 void LevelDBWrapperImpl::DeleteAll(const mojo::String& source, | 177 void LevelDBWrapperImpl::DeleteAll(const std::string& source, |
| 177 const DeleteAllCallback& callback) { | 178 const DeleteAllCallback& callback) { |
| 178 if (!map_) { | 179 if (!map_) { |
| 179 LoadMap( | 180 LoadMap( |
| 180 base::Bind(&LevelDBWrapperImpl::DeleteAll, base::Unretained(this), | 181 base::Bind(&LevelDBWrapperImpl::DeleteAll, base::Unretained(this), |
| 181 source, callback)); | 182 source, callback)); |
| 182 return; | 183 return; |
| 183 } | 184 } |
| 184 | 185 |
| 185 if (database_ && !map_->empty()) { | 186 if (database_ && !map_->empty()) { |
| 186 CreateCommitBatchIfNeeded(); | 187 CreateCommitBatchIfNeeded(); |
| 187 commit_batch_->clear_all_first = true; | 188 commit_batch_->clear_all_first = true; |
| 188 commit_batch_->changed_values.clear(); | 189 commit_batch_->changed_values.clear(); |
| 189 } | 190 } |
| 190 map_->clear(); | 191 map_->clear(); |
| 191 bytes_used_ = 0; | 192 bytes_used_ = 0; |
| 192 observers_.ForAllPtrs( | 193 observers_.ForAllPtrs( |
| 193 [&source](mojom::LevelDBObserver* observer) { | 194 [&source](mojom::LevelDBObserver* observer) { |
| 194 observer->AllDeleted(source); | 195 observer->AllDeleted(source); |
| 195 }); | 196 }); |
| 196 callback.Run(true); | 197 callback.Run(true); |
| 197 } | 198 } |
| 198 | 199 |
| 199 void LevelDBWrapperImpl::Get(mojo::Array<uint8_t> key, | 200 void LevelDBWrapperImpl::Get(const std::vector<uint8_t>& key, |
| 200 const GetCallback& callback) { | 201 const GetCallback& callback) { |
| 201 if (!map_) { | 202 if (!map_) { |
| 202 LoadMap( | 203 LoadMap(base::Bind(&LevelDBWrapperImpl::Get, base::Unretained(this), key, |
| 203 base::Bind(&LevelDBWrapperImpl::Get, base::Unretained(this), | 204 callback)); |
| 204 base::Passed(&key), callback)); | |
| 205 return; | 205 return; |
| 206 } | 206 } |
| 207 | 207 |
| 208 auto found = map_->find(key); | 208 auto found = map_->find(key); |
| 209 if (found == map_->end()) { | 209 if (found == map_->end()) { |
| 210 callback.Run(false, mojo::Array<uint8_t>()); | 210 callback.Run(false, std::vector<uint8_t>()); |
| 211 return; | 211 return; |
| 212 } | 212 } |
| 213 callback.Run(true, found->second.Clone()); | 213 callback.Run(true, found->second); |
| 214 } | 214 } |
| 215 | 215 |
| 216 void LevelDBWrapperImpl::GetAll(const mojo::String& source, | 216 void LevelDBWrapperImpl::GetAll(const std::string& source, |
| 217 const GetAllCallback& callback) { | 217 const GetAllCallback& callback) { |
| 218 if (!map_) { | 218 if (!map_) { |
| 219 LoadMap( | 219 LoadMap( |
| 220 base::Bind(&LevelDBWrapperImpl::GetAll, base::Unretained(this), | 220 base::Bind(&LevelDBWrapperImpl::GetAll, base::Unretained(this), |
| 221 source, callback)); | 221 source, callback)); |
| 222 return; | 222 return; |
| 223 } | 223 } |
| 224 | 224 |
| 225 mojo::Array<mojom::KeyValuePtr> all; | 225 std::vector<mojom::KeyValuePtr> all; |
| 226 for (const auto& it : (*map_)) { | 226 for (const auto& it : (*map_)) { |
| 227 mojom::KeyValuePtr kv = mojom::KeyValue::New(); | 227 mojom::KeyValuePtr kv = mojom::KeyValue::New(); |
| 228 kv->key = it.first.Clone(); | 228 kv->key = it.first; |
| 229 kv->value = it.second.Clone(); | 229 kv->value = it.second; |
| 230 all.push_back(std::move(kv)); | 230 all.push_back(std::move(kv)); |
| 231 } | 231 } |
| 232 callback.Run(leveldb::mojom::DatabaseError::OK, std::move(all)); | 232 callback.Run(leveldb::mojom::DatabaseError::OK, std::move(all)); |
| 233 observers_.ForAllPtrs( | 233 observers_.ForAllPtrs( |
| 234 [source](mojom::LevelDBObserver* observer) { | 234 [source](mojom::LevelDBObserver* observer) { |
| 235 observer->GetAllComplete(source); | 235 observer->GetAllComplete(source); |
| 236 }); | 236 }); |
| 237 } | 237 } |
| 238 | 238 |
| 239 void LevelDBWrapperImpl::OnConnectionError() { | 239 void LevelDBWrapperImpl::OnConnectionError() { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 253 base::Bind(&LevelDBWrapperImpl::OnLoadComplete, | 253 base::Bind(&LevelDBWrapperImpl::OnLoadComplete, |
| 254 weak_ptr_factory_.GetWeakPtr())); | 254 weak_ptr_factory_.GetWeakPtr())); |
| 255 } | 255 } |
| 256 | 256 |
| 257 void LevelDBWrapperImpl::OnLoadComplete( | 257 void LevelDBWrapperImpl::OnLoadComplete( |
| 258 leveldb::mojom::DatabaseError status, | 258 leveldb::mojom::DatabaseError status, |
| 259 mojo::Array<leveldb::mojom::KeyValuePtr> data) { | 259 mojo::Array<leveldb::mojom::KeyValuePtr> data) { |
| 260 DCHECK(!map_); | 260 DCHECK(!map_); |
| 261 map_.reset(new ValueMap); | 261 map_.reset(new ValueMap); |
| 262 for (auto& it : data) | 262 for (auto& it : data) |
| 263 (*map_)[std::move(it->key)] = std::move(it->value); | 263 (*map_)[it->key.PassStorage()] = it->value.PassStorage(); |
| 264 | 264 |
| 265 // We proceed without using a backing store, nothing will be persisted but the | 265 // We proceed without using a backing store, nothing will be persisted but the |
| 266 // class is functional for the lifetime of the object. | 266 // class is functional for the lifetime of the object. |
| 267 // TODO(michaeln): Uma here or in the DB file? | 267 // TODO(michaeln): Uma here or in the DB file? |
| 268 if (status != leveldb::mojom::DatabaseError::OK) | 268 if (status != leveldb::mojom::DatabaseError::OK) |
| 269 database_ = nullptr; | 269 database_ = nullptr; |
| 270 | 270 |
| 271 std::vector<base::Closure> tasks; | 271 std::vector<base::Closure> tasks; |
| 272 on_load_complete_tasks_.swap(tasks); | 272 on_load_complete_tasks_.swap(tasks); |
| 273 for (auto& task : tasks) | 273 for (auto& task : tasks) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 327 if (commit_batch_->clear_all_first) { | 327 if (commit_batch_->clear_all_first) { |
| 328 leveldb::mojom::BatchedOperationPtr item = | 328 leveldb::mojom::BatchedOperationPtr item = |
| 329 leveldb::mojom::BatchedOperation::New(); | 329 leveldb::mojom::BatchedOperation::New(); |
| 330 item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY; | 330 item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY; |
| 331 item->key = mojo::Array<uint8_t>::From(std::string(prefix_)); | 331 item->key = mojo::Array<uint8_t>::From(std::string(prefix_)); |
| 332 operations.push_back(std::move(item)); | 332 operations.push_back(std::move(item)); |
| 333 } | 333 } |
| 334 for (auto& it : commit_batch_->changed_values) { | 334 for (auto& it : commit_batch_->changed_values) { |
| 335 leveldb::mojom::BatchedOperationPtr item = | 335 leveldb::mojom::BatchedOperationPtr item = |
| 336 leveldb::mojom::BatchedOperation::New(); | 336 leveldb::mojom::BatchedOperation::New(); |
| 337 item->key = it.first.Clone(); | 337 item->key = std::vector<uint8_t>(it.first); |
| 338 if (it.second.is_null()) { | 338 if (!it.second) { |
| 339 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; | 339 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; |
| 340 } else { | 340 } else { |
| 341 item->type = leveldb::mojom::BatchOperationType::PUT_KEY; | 341 item->type = leveldb::mojom::BatchOperationType::PUT_KEY; |
| 342 item->value = std::move(it.second); | 342 item->value = std::move(*(it.second)); |
| 343 } | 343 } |
| 344 operations.push_back(std::move(item)); | 344 operations.push_back(std::move(item)); |
| 345 } | 345 } |
| 346 commit_batch_.reset(); | 346 commit_batch_.reset(); |
| 347 | 347 |
| 348 ++commit_batches_in_flight_; | 348 ++commit_batches_in_flight_; |
| 349 | 349 |
| 350 // TODO(michaeln): Currently there is no guarantee LevelDBDatabaseImp::Write | 350 // TODO(michaeln): Currently there is no guarantee LevelDBDatabaseImp::Write |
| 351 // will run during a clean shutdown. We need that to avoid dataloss. | 351 // will run during a clean shutdown. We need that to avoid dataloss. |
| 352 database_->Write(std::move(operations), | 352 database_->Write(std::move(operations), |
| 353 base::Bind(&LevelDBWrapperImpl::OnCommitComplete, | 353 base::Bind(&LevelDBWrapperImpl::OnCommitComplete, |
| 354 weak_ptr_factory_.GetWeakPtr())); | 354 weak_ptr_factory_.GetWeakPtr())); |
| 355 } | 355 } |
| 356 | 356 |
| 357 void LevelDBWrapperImpl::OnCommitComplete(leveldb::mojom::DatabaseError error) { | 357 void LevelDBWrapperImpl::OnCommitComplete(leveldb::mojom::DatabaseError error) { |
| 358 // TODO(michaeln): What if it fails, uma here or in the DB class? | 358 // TODO(michaeln): What if it fails, uma here or in the DB class? |
| 359 --commit_batches_in_flight_; | 359 --commit_batches_in_flight_; |
| 360 StartCommitTimer(); | 360 StartCommitTimer(); |
| 361 } | 361 } |
| 362 | 362 |
| 363 } // namespace content | 363 } // namespace content |
| OLD | NEW |