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