Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: content/browser/indexed_db/leveldb/leveldb_iterator_impl.cc

Issue 2760163002: [IndexedDB] Pool and evict leveldb iterators, to save memory (Closed)
Patch Set: comments & lifetime fix Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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/indexed_db/leveldb/leveldb_iterator_impl.h" 5 #include "content/browser/indexed_db/leveldb/leveldb_iterator_impl.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "content/browser/indexed_db/leveldb/leveldb_iterator_pool_controller.h"
11 12
12 static leveldb::Slice MakeSlice(const base::StringPiece& s) { 13 static leveldb::Slice MakeSlice(const base::StringPiece& s) {
13 return leveldb::Slice(s.begin(), s.size()); 14 return leveldb::Slice(s.begin(), s.size());
14 } 15 }
15 16
16 static base::StringPiece MakeStringPiece(const leveldb::Slice& s) { 17 static base::StringPiece MakeStringPiece(const leveldb::Slice& s) {
17 return base::StringPiece(s.data(), s.size()); 18 return base::StringPiece(s.data(), s.size());
18 } 19 }
19 20
20 namespace content { 21 namespace content {
21 22
22 LevelDBIteratorImpl::~LevelDBIteratorImpl() { 23 LevelDBIteratorImpl::~LevelDBIteratorImpl() {
24 pool_controller_->NotifyIteratorDestroyed(this);
23 } 25 }
24 26
25 LevelDBIteratorImpl::LevelDBIteratorImpl(std::unique_ptr<leveldb::Iterator> it) 27 LevelDBIteratorImpl::LevelDBIteratorImpl(
26 : iterator_(std::move(it)) {} 28 std::unique_ptr<leveldb::Iterator> it,
29 LevelDBIteratorPoolController* pool_controller,
30 const leveldb::Snapshot* snapshot)
31 : iterator_(std::move(it)),
32 pool_controller_(pool_controller),
33 snapshot_(snapshot) {}
27 34
28 void LevelDBIteratorImpl::CheckStatus() { 35 void LevelDBIteratorImpl::CheckStatus() {
36 DCHECK_EQ(iterator_state_, IteratorState::ACTIVE);
29 const leveldb::Status& s = iterator_->status(); 37 const leveldb::Status& s = iterator_->status();
30 if (!s.ok()) 38 if (!s.ok())
31 LOG(ERROR) << "LevelDB iterator error: " << s.ToString(); 39 LOG(ERROR) << "LevelDB iterator error: " << s.ToString();
32 } 40 }
33 41
34 bool LevelDBIteratorImpl::IsValid() const { 42 bool LevelDBIteratorImpl::IsValid() const {
35 return iterator_->Valid(); 43 return iterator_state_ == IteratorState::EVICTED_AND_VALID ||
44 iterator_->Valid();
36 } 45 }
37 46
38 leveldb::Status LevelDBIteratorImpl::SeekToLast() { 47 leveldb::Status LevelDBIteratorImpl::SeekToLast() {
48 RecordUsage();
49 RestoreDBIteratorIfEvicted();
pwnall 2017/03/24 09:16:03 I see these two methods together everywhere. Would
dmurph 2017/03/24 23:33:39 Done.
50 DCHECK(iterator_);
39 iterator_->SeekToLast(); 51 iterator_->SeekToLast();
40 CheckStatus(); 52 CheckStatus();
41 return iterator_->status(); 53 return iterator_->status();
42 } 54 }
43 55
44 leveldb::Status LevelDBIteratorImpl::Seek(const base::StringPiece& target) { 56 leveldb::Status LevelDBIteratorImpl::Seek(const base::StringPiece& target) {
57 RecordUsage();
58 RestoreDBIteratorIfEvicted();
59 DCHECK(iterator_);
45 iterator_->Seek(MakeSlice(target)); 60 iterator_->Seek(MakeSlice(target));
46 CheckStatus(); 61 CheckStatus();
47 return iterator_->status(); 62 return iterator_->status();
48 } 63 }
49 64
50 leveldb::Status LevelDBIteratorImpl::Next() { 65 leveldb::Status LevelDBIteratorImpl::Next() {
51 DCHECK(IsValid()); 66 DCHECK(IsValid());
67 RecordUsage();
68 RestoreDBIteratorIfEvicted();
69 DCHECK(iterator_);
52 iterator_->Next(); 70 iterator_->Next();
53 CheckStatus(); 71 CheckStatus();
54 return iterator_->status(); 72 return iterator_->status();
55 } 73 }
56 74
57 leveldb::Status LevelDBIteratorImpl::Prev() { 75 leveldb::Status LevelDBIteratorImpl::Prev() {
58 DCHECK(IsValid()); 76 DCHECK(IsValid());
77 RecordUsage();
78 RestoreDBIteratorIfEvicted();
79 DCHECK(iterator_);
59 iterator_->Prev(); 80 iterator_->Prev();
60 CheckStatus(); 81 CheckStatus();
61 return iterator_->status(); 82 return iterator_->status();
62 } 83 }
63 84
64 base::StringPiece LevelDBIteratorImpl::Key() const { 85 base::StringPiece LevelDBIteratorImpl::Key() const {
65 DCHECK(IsValid()); 86 DCHECK(IsValid());
66 return MakeStringPiece(iterator_->key()); 87 if (iterator_state_ == IteratorState::ACTIVE)
88 return MakeStringPiece(iterator_->key());
89 return key_before_eviction_;
67 } 90 }
68 91
69 base::StringPiece LevelDBIteratorImpl::Value() const { 92 base::StringPiece LevelDBIteratorImpl::Value() const {
70 DCHECK(IsValid()); 93 DCHECK(IsValid());
94 // Always need to update the LRU, so we always call this. Const-cast needed,
95 // as we're dealing with a caching layer.
96 LevelDBIteratorImpl* non_const = const_cast<LevelDBIteratorImpl*>(this);
97 non_const->RecordUsage();
98 non_const->RestoreDBIteratorIfEvicted();
71 return MakeStringPiece(iterator_->value()); 99 return MakeStringPiece(iterator_->value());
72 } 100 }
73 101
102 void LevelDBIteratorImpl::PurgeMemory() {
103 DCHECK_EQ(iterator_state_, IteratorState::ACTIVE);
104 if (iterator_->Valid()) {
105 iterator_state_ = IteratorState::EVICTED_AND_VALID;
106 key_before_eviction_ = iterator_->key().ToString();
107 } else {
108 iterator_state_ = IteratorState::EVICTED_AND_INVALID;
109 }
110 iterator_.reset();
111 }
112
113 bool LevelDBIteratorImpl::IsEvicted() const {
pwnall 2017/03/24 09:16:03 It's surprising to me that you sometimes call this
dmurph 2017/03/24 23:33:39 Done.
114 return iterator_state_ != IteratorState::ACTIVE;
115 }
116
117 void LevelDBIteratorImpl::RecordUsage() {
118 pool_controller_->NotifyIteratorUsed(this);
119 }
120
121 void LevelDBIteratorImpl::RestoreDBIteratorIfEvicted() {
122 if (iterator_state_ == IteratorState::ACTIVE)
123 return;
124
125 iterator_ = pool_controller_->CreateLevelDBIterator(snapshot_);
126 if (iterator_state_ == IteratorState::EVICTED_AND_VALID) {
127 iterator_->Seek(key_before_eviction_);
128 key_before_eviction_.clear();
129 DCHECK(IsValid());
130 } else {
131 DCHECK(!iterator_->Valid());
132 }
133 iterator_state_ = IteratorState::ACTIVE;
134 }
135
74 } // namespace content 136 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698