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()); |
|
yzshen1
2016/08/02 16:20:09
pair.second may be null, right? (e.g., see line 16
michaeln
2016/08/02 20:31:54
also, this line looks weird, can you fix this to c
leonhsl(Using Gerrit)
2016/08/03 03:38:48
Done. And also confirmed there has no similar prob
| |
| 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; | |
| 99 size_t old_item_size = 0; | 97 size_t old_item_size = 0; |
| 100 auto found = map_->find(key); | 98 auto found = map_->find(key); |
| 101 if (found != map_->end()) { | 99 if (found != map_->end()) { |
| 102 if (found->second.Equals(value)) { | 100 if (*(found->second) == value) { |
|
yzshen1
2016/08/02 16:20:09
It seems here we also assume that found->second is
michaeln
2016/08/02 20:31:54
Values in this map_ may not be null, it might be g
leonhsl(Using Gerrit)
2016/08/03 03:38:48
Yeah I think DCHECK() is proper here, as map_ is s
yzshen1
2016/08/03 17:23:05
If map_ is not supposed to have null value, it wou
leonhsl(Using Gerrit)
2016/08/09 07:56:51
Sorry for late response. Agree and addressed this
| |
| 103 callback.Run(true); // Key already has this value. | 101 callback.Run(true); // Key already has this value. |
| 104 return; | 102 return; |
| 105 } | 103 } |
| 106 old_value = std::move(found->second); | 104 old_item_size = key.size() + found->second->size(); |
|
yzshen1
2016/08/02 16:20:09
Previously the old value was removed from the map,
michaeln
2016/08/02 20:31:54
yes, this fixes a bug
| |
| 107 old_item_size = key.size() + old_value.size(); | |
| 108 has_old_item = true; | 105 has_old_item = true; |
| 109 } | 106 } |
| 110 size_t new_item_size = key.size() + value.size(); | 107 size_t new_item_size = key.size() + value.size(); |
| 111 size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size; | 108 size_t new_bytes_used = bytes_used_ - old_item_size + new_item_size; |
| 112 | 109 |
| 113 // Only check quota if the size is increasing, this allows | 110 // Only check quota if the size is increasing, this allows |
| 114 // shrinking changes to pre-existing maps that are over budget. | 111 // shrinking changes to pre-existing maps that are over budget. |
| 115 if (new_item_size > old_item_size && new_bytes_used > max_size_) { | 112 if (new_item_size > old_item_size && new_bytes_used > max_size_) { |
| 116 callback.Run(false); | 113 callback.Run(false); |
| 117 return; | 114 return; |
| 118 } | 115 } |
| 119 | 116 |
| 120 if (database_) { | 117 if (database_) { |
| 121 CreateCommitBatchIfNeeded(); | 118 CreateCommitBatchIfNeeded(); |
| 122 commit_batch_->changed_values[key.Clone()] = value.Clone(); | 119 commit_batch_->changed_values[key] = value; |
| 123 } | 120 } |
| 124 | 121 |
| 125 (*map_)[key.Clone()] = value.Clone(); | 122 std::vector<uint8_t> old_value; |
| 123 if (has_old_item) { | |
| 124 old_value.swap(*((*map_)[key])); | |
| 125 } | |
| 126 (*map_)[key] = value; | |
| 126 bytes_used_ = new_bytes_used; | 127 bytes_used_ = new_bytes_used; |
| 127 if (!has_old_item) { | 128 if (!has_old_item) { |
| 128 // We added a new key/value pair. | 129 // We added a new key/value pair. |
| 129 observers_.ForAllPtrs( | 130 observers_.ForAllPtrs( |
| 130 [&key, &value, &source](mojom::LevelDBObserver* observer) { | 131 [&key, &value, &source](mojom::LevelDBObserver* observer) { |
| 131 observer->KeyAdded(key.Clone(), value.Clone(), source); | 132 observer->KeyAdded(key, value, source); |
| 132 }); | 133 }); |
| 133 } else { | 134 } else { |
| 134 // We changed the value for an existing key. | 135 // We changed the value for an existing key. |
| 135 observers_.ForAllPtrs( | 136 observers_.ForAllPtrs( |
| 136 [&key, &value, &source, &old_value](mojom::LevelDBObserver* observer) { | 137 [&key, &value, &source, &old_value](mojom::LevelDBObserver* observer) { |
| 137 observer->KeyChanged( | 138 observer->KeyChanged(key, value, old_value, source); |
| 138 key.Clone(), value.Clone(), old_value.Clone(), source); | |
| 139 }); | 139 }); |
| 140 } | 140 } |
| 141 callback.Run(true); | 141 callback.Run(true); |
| 142 } | 142 } |
| 143 | 143 |
| 144 void LevelDBWrapperImpl::Delete(mojo::Array<uint8_t> key, | 144 void LevelDBWrapperImpl::Delete(const std::vector<uint8_t>& key, |
| 145 const mojo::String& source, | 145 const std::string& source, |
| 146 const DeleteCallback& callback) { | 146 const DeleteCallback& callback) { |
| 147 if (!map_) { | 147 if (!map_) { |
| 148 LoadMap( | 148 LoadMap(base::Bind(&LevelDBWrapperImpl::Delete, base::Unretained(this), key, |
| 149 base::Bind(&LevelDBWrapperImpl::Delete, base::Unretained(this), | 149 source, callback)); |
| 150 base::Passed(&key), source, callback)); | |
| 151 return; | 150 return; |
| 152 } | 151 } |
| 153 | 152 |
| 154 auto found = map_->find(key); | 153 auto found = map_->find(key); |
| 155 if (found == map_->end()) { | 154 if (found == map_->end()) { |
| 156 callback.Run(true); | 155 callback.Run(true); |
| 157 return; | 156 return; |
| 158 } | 157 } |
| 159 | 158 |
| 160 if (database_) { | 159 if (database_) { |
| 161 CreateCommitBatchIfNeeded(); | 160 CreateCommitBatchIfNeeded(); |
| 162 commit_batch_->changed_values[key.Clone()] = mojo::Array<uint8_t>(nullptr); | 161 commit_batch_->changed_values[key] = base::nullopt; |
| 163 } | 162 } |
| 164 | 163 |
| 165 mojo::Array<uint8_t> old_value = std::move(found->second); | 164 std::vector<uint8_t> old_value(std::move(*(found->second))); |
| 166 map_->erase(found); | 165 map_->erase(found); |
| 167 bytes_used_ -= key.size() + old_value.size(); | 166 bytes_used_ -= key.size() + old_value.size(); |
| 168 observers_.ForAllPtrs( | 167 observers_.ForAllPtrs( |
| 169 [&key, &source, &old_value](mojom::LevelDBObserver* observer) { | 168 [&key, &source, &old_value](mojom::LevelDBObserver* observer) { |
| 170 observer->KeyDeleted( | 169 observer->KeyDeleted(key, old_value, source); |
| 171 key.Clone(), old_value.Clone(), source); | |
| 172 }); | 170 }); |
| 173 callback.Run(true); | 171 callback.Run(true); |
| 174 } | 172 } |
| 175 | 173 |
| 176 void LevelDBWrapperImpl::DeleteAll(const mojo::String& source, | 174 void LevelDBWrapperImpl::DeleteAll(const std::string& source, |
| 177 const DeleteAllCallback& callback) { | 175 const DeleteAllCallback& callback) { |
| 178 if (!map_) { | 176 if (!map_) { |
| 179 LoadMap( | 177 LoadMap( |
| 180 base::Bind(&LevelDBWrapperImpl::DeleteAll, base::Unretained(this), | 178 base::Bind(&LevelDBWrapperImpl::DeleteAll, base::Unretained(this), |
| 181 source, callback)); | 179 source, callback)); |
| 182 return; | 180 return; |
| 183 } | 181 } |
| 184 | 182 |
| 185 if (database_ && !map_->empty()) { | 183 if (database_ && !map_->empty()) { |
| 186 CreateCommitBatchIfNeeded(); | 184 CreateCommitBatchIfNeeded(); |
| 187 commit_batch_->clear_all_first = true; | 185 commit_batch_->clear_all_first = true; |
| 188 commit_batch_->changed_values.clear(); | 186 commit_batch_->changed_values.clear(); |
| 189 } | 187 } |
| 190 map_->clear(); | 188 map_->clear(); |
| 191 bytes_used_ = 0; | 189 bytes_used_ = 0; |
| 192 observers_.ForAllPtrs( | 190 observers_.ForAllPtrs( |
| 193 [&source](mojom::LevelDBObserver* observer) { | 191 [&source](mojom::LevelDBObserver* observer) { |
| 194 observer->AllDeleted(source); | 192 observer->AllDeleted(source); |
| 195 }); | 193 }); |
| 196 callback.Run(true); | 194 callback.Run(true); |
| 197 } | 195 } |
| 198 | 196 |
| 199 void LevelDBWrapperImpl::Get(mojo::Array<uint8_t> key, | 197 void LevelDBWrapperImpl::Get(const std::vector<uint8_t>& key, |
| 200 const GetCallback& callback) { | 198 const GetCallback& callback) { |
| 201 if (!map_) { | 199 if (!map_) { |
| 202 LoadMap( | 200 LoadMap(base::Bind(&LevelDBWrapperImpl::Get, base::Unretained(this), key, |
| 203 base::Bind(&LevelDBWrapperImpl::Get, base::Unretained(this), | 201 callback)); |
| 204 base::Passed(&key), callback)); | |
| 205 return; | 202 return; |
| 206 } | 203 } |
| 207 | 204 |
| 208 auto found = map_->find(key); | 205 auto found = map_->find(key); |
| 209 if (found == map_->end()) { | 206 if (found == map_->end()) { |
| 210 callback.Run(false, mojo::Array<uint8_t>()); | 207 callback.Run(false, std::vector<uint8_t>()); |
| 211 return; | 208 return; |
| 212 } | 209 } |
| 213 callback.Run(true, found->second.Clone()); | 210 callback.Run(true, *(found->second)); |
| 214 } | 211 } |
| 215 | 212 |
| 216 void LevelDBWrapperImpl::GetAll(const mojo::String& source, | 213 void LevelDBWrapperImpl::GetAll(const std::string& source, |
| 217 const GetAllCallback& callback) { | 214 const GetAllCallback& callback) { |
| 218 if (!map_) { | 215 if (!map_) { |
| 219 LoadMap( | 216 LoadMap( |
| 220 base::Bind(&LevelDBWrapperImpl::GetAll, base::Unretained(this), | 217 base::Bind(&LevelDBWrapperImpl::GetAll, base::Unretained(this), |
| 221 source, callback)); | 218 source, callback)); |
| 222 return; | 219 return; |
| 223 } | 220 } |
| 224 | 221 |
| 225 mojo::Array<mojom::KeyValuePtr> all; | 222 std::vector<mojom::KeyValuePtr> all; |
| 226 for (const auto& it : (*map_)) { | 223 for (const auto& it : (*map_)) { |
| 227 mojom::KeyValuePtr kv = mojom::KeyValue::New(); | 224 mojom::KeyValuePtr kv = mojom::KeyValue::New(); |
| 228 kv->key = it.first.Clone(); | 225 kv->key = it.first; |
| 229 kv->value = it.second.Clone(); | 226 kv->value = *(it.second); |
| 230 all.push_back(std::move(kv)); | 227 all.push_back(std::move(kv)); |
| 231 } | 228 } |
| 232 callback.Run(leveldb::mojom::DatabaseError::OK, std::move(all)); | 229 callback.Run(leveldb::mojom::DatabaseError::OK, std::move(all)); |
| 233 observers_.ForAllPtrs( | 230 observers_.ForAllPtrs( |
| 234 [source](mojom::LevelDBObserver* observer) { | 231 [source](mojom::LevelDBObserver* observer) { |
| 235 observer->GetAllComplete(source); | 232 observer->GetAllComplete(source); |
| 236 }); | 233 }); |
| 237 } | 234 } |
| 238 | 235 |
| 239 void LevelDBWrapperImpl::OnConnectionError() { | 236 void LevelDBWrapperImpl::OnConnectionError() { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 253 base::Bind(&LevelDBWrapperImpl::OnLoadComplete, | 250 base::Bind(&LevelDBWrapperImpl::OnLoadComplete, |
| 254 weak_ptr_factory_.GetWeakPtr())); | 251 weak_ptr_factory_.GetWeakPtr())); |
| 255 } | 252 } |
| 256 | 253 |
| 257 void LevelDBWrapperImpl::OnLoadComplete( | 254 void LevelDBWrapperImpl::OnLoadComplete( |
| 258 leveldb::mojom::DatabaseError status, | 255 leveldb::mojom::DatabaseError status, |
| 259 mojo::Array<leveldb::mojom::KeyValuePtr> data) { | 256 mojo::Array<leveldb::mojom::KeyValuePtr> data) { |
| 260 DCHECK(!map_); | 257 DCHECK(!map_); |
| 261 map_.reset(new ValueMap); | 258 map_.reset(new ValueMap); |
| 262 for (auto& it : data) | 259 for (auto& it : data) |
| 263 (*map_)[std::move(it->key)] = std::move(it->value); | 260 (*map_)[it->key.PassStorage()] = it->value.PassStorage(); |
| 264 | 261 |
| 265 // We proceed without using a backing store, nothing will be persisted but the | 262 // We proceed without using a backing store, nothing will be persisted but the |
| 266 // class is functional for the lifetime of the object. | 263 // class is functional for the lifetime of the object. |
| 267 // TODO(michaeln): Uma here or in the DB file? | 264 // TODO(michaeln): Uma here or in the DB file? |
| 268 if (status != leveldb::mojom::DatabaseError::OK) | 265 if (status != leveldb::mojom::DatabaseError::OK) |
| 269 database_ = nullptr; | 266 database_ = nullptr; |
| 270 | 267 |
| 271 std::vector<base::Closure> tasks; | 268 std::vector<base::Closure> tasks; |
| 272 on_load_complete_tasks_.swap(tasks); | 269 on_load_complete_tasks_.swap(tasks); |
| 273 for (auto& task : tasks) | 270 for (auto& task : tasks) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 if (commit_batch_->clear_all_first) { | 324 if (commit_batch_->clear_all_first) { |
| 328 leveldb::mojom::BatchedOperationPtr item = | 325 leveldb::mojom::BatchedOperationPtr item = |
| 329 leveldb::mojom::BatchedOperation::New(); | 326 leveldb::mojom::BatchedOperation::New(); |
| 330 item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY; | 327 item->type = leveldb::mojom::BatchOperationType::DELETE_PREFIXED_KEY; |
| 331 item->key = mojo::Array<uint8_t>::From(std::string(prefix_)); | 328 item->key = mojo::Array<uint8_t>::From(std::string(prefix_)); |
| 332 operations.push_back(std::move(item)); | 329 operations.push_back(std::move(item)); |
| 333 } | 330 } |
| 334 for (auto& it : commit_batch_->changed_values) { | 331 for (auto& it : commit_batch_->changed_values) { |
| 335 leveldb::mojom::BatchedOperationPtr item = | 332 leveldb::mojom::BatchedOperationPtr item = |
| 336 leveldb::mojom::BatchedOperation::New(); | 333 leveldb::mojom::BatchedOperation::New(); |
| 337 item->key = it.first.Clone(); | 334 item->key = std::vector<uint8_t>(it.first); |
| 338 if (it.second.is_null()) { | 335 if (!it.second) { |
| 339 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; | 336 item->type = leveldb::mojom::BatchOperationType::DELETE_KEY; |
| 340 } else { | 337 } else { |
| 341 item->type = leveldb::mojom::BatchOperationType::PUT_KEY; | 338 item->type = leveldb::mojom::BatchOperationType::PUT_KEY; |
| 342 item->value = std::move(it.second); | 339 item->value = std::move(*(it.second)); |
| 343 } | 340 } |
| 344 operations.push_back(std::move(item)); | 341 operations.push_back(std::move(item)); |
| 345 } | 342 } |
| 346 commit_batch_.reset(); | 343 commit_batch_.reset(); |
| 347 | 344 |
| 348 ++commit_batches_in_flight_; | 345 ++commit_batches_in_flight_; |
| 349 | 346 |
| 350 // TODO(michaeln): Currently there is no guarantee LevelDBDatabaseImp::Write | 347 // TODO(michaeln): Currently there is no guarantee LevelDBDatabaseImp::Write |
| 351 // will run during a clean shutdown. We need that to avoid dataloss. | 348 // will run during a clean shutdown. We need that to avoid dataloss. |
| 352 database_->Write(std::move(operations), | 349 database_->Write(std::move(operations), |
| 353 base::Bind(&LevelDBWrapperImpl::OnCommitComplete, | 350 base::Bind(&LevelDBWrapperImpl::OnCommitComplete, |
| 354 weak_ptr_factory_.GetWeakPtr())); | 351 weak_ptr_factory_.GetWeakPtr())); |
| 355 } | 352 } |
| 356 | 353 |
| 357 void LevelDBWrapperImpl::OnCommitComplete(leveldb::mojom::DatabaseError error) { | 354 void LevelDBWrapperImpl::OnCommitComplete(leveldb::mojom::DatabaseError error) { |
| 358 // TODO(michaeln): What if it fails, uma here or in the DB class? | 355 // TODO(michaeln): What if it fails, uma here or in the DB class? |
| 359 --commit_batches_in_flight_; | 356 --commit_batches_in_flight_; |
| 360 StartCommitTimer(); | 357 StartCommitTimer(); |
| 361 } | 358 } |
| 362 | 359 |
| 363 } // namespace content | 360 } // namespace content |
| OLD | NEW |