Index: content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc |
diff --git a/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc b/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc |
index 2052d1ab9b4388b9c6ee9b322975b779db053507..43a9ba056cbc1e2325e13b3595455113b80dca42 100644 |
--- a/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc |
+++ b/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc |
@@ -24,6 +24,7 @@ |
namespace content { |
namespace { |
+static const size_t kTestingMaxOpenCursors = 3; |
class SimpleComparator : public LevelDBComparator { |
public: |
@@ -35,12 +36,17 @@ class SimpleComparator : public LevelDBComparator { |
const char* Name() const override { return "temp_comparator"; } |
}; |
+} // namespace |
+ |
class LevelDBTransactionTest : public testing::Test { |
public: |
LevelDBTransactionTest() {} |
void SetUp() override { |
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); |
- LevelDBDatabase::Open(temp_directory_.GetPath(), &comparator_, &leveldb_); |
+ leveldb::Status s = |
+ LevelDBDatabase::Open(temp_directory_.GetPath(), &comparator_, |
+ kTestingMaxOpenCursors, &leveldb_); |
+ ASSERT_TRUE(s.ok()); |
ASSERT_TRUE(leveldb_); |
} |
void TearDown() override {} |
@@ -96,6 +102,10 @@ class LevelDBTransactionTest : public testing::Test { |
LevelDBDatabase* db() { return leveldb_.get(); } |
+ scoped_refptr<LevelDBTransaction> CreateTransaction() { |
+ return new LevelDBTransaction(db()); |
+ } |
+ |
private: |
base::ScopedTempDir temp_directory_; |
SimpleComparator comparator_; |
@@ -104,8 +114,6 @@ class LevelDBTransactionTest : public testing::Test { |
DISALLOW_COPY_AND_ASSIGN(LevelDBTransactionTest); |
}; |
-} // namespace |
- |
TEST_F(LevelDBTransactionTest, GetAndPut) { |
leveldb::Status status; |
@@ -210,6 +218,65 @@ TEST_F(LevelDBTransactionTest, Commit) { |
EXPECT_EQ(value3, got_value); |
} |
+TEST_F(LevelDBTransactionTest, IterationWithEvictedCursors) { |
+ leveldb::Status status; |
+ |
+ Put("key1", "value1"); |
+ Put("key2", "value2"); |
+ Put("key3", "value3"); |
+ |
+ scoped_refptr<LevelDBTransaction> transaction = CreateTransaction(); |
+ |
+ std::unique_ptr<LevelDBIterator> evicted_normal_location = |
+ transaction->CreateIterator(); |
+ |
+ std::unique_ptr<LevelDBIterator> evicted_before_start = |
+ transaction->CreateIterator(); |
+ |
+ std::unique_ptr<LevelDBIterator> evicted_after_end = |
+ transaction->CreateIterator(); |
+ |
+ std::unique_ptr<LevelDBIterator> it1 = transaction->CreateIterator(); |
+ std::unique_ptr<LevelDBIterator> it2 = transaction->CreateIterator(); |
+ std::unique_ptr<LevelDBIterator> it3 = transaction->CreateIterator(); |
+ |
+ evicted_normal_location->Seek("key1"); |
+ evicted_before_start->Seek("key1"); |
+ evicted_before_start->Prev(); |
+ evicted_after_end->SeekToLast(); |
+ evicted_after_end->Next(); |
+ |
+ // Nothing is purged, as we just have 3 iterators used. |
+ EXPECT_FALSE(evicted_normal_location->IsDetached()); |
+ EXPECT_FALSE(evicted_before_start->IsDetached()); |
+ EXPECT_FALSE(evicted_after_end->IsDetached()); |
+ EXPECT_FALSE(evicted_before_start->IsValid()); |
+ EXPECT_FALSE(evicted_after_end->IsValid()); |
+ |
+ // Should purge all of our earlier iterators. |
+ it1->Seek("key1"); |
+ it2->Seek("key2"); |
+ it3->Seek("key3"); |
+ |
+ EXPECT_TRUE(evicted_normal_location->IsDetached()); |
+ EXPECT_TRUE(evicted_before_start->IsDetached()); |
+ EXPECT_TRUE(evicted_after_end->IsDetached()); |
+ |
+ // Check we don't need to reload for just the key. |
+ EXPECT_EQ("key1", evicted_normal_location->Key()); |
+ EXPECT_TRUE(evicted_normal_location->IsDetached()); |
+ |
+ // Make sure iterators are reloaded correctly. |
+ EXPECT_TRUE(evicted_normal_location->IsValid()); |
+ EXPECT_EQ("value1", evicted_normal_location->Value()); |
+ EXPECT_FALSE(evicted_normal_location->IsDetached()); |
+ EXPECT_FALSE(evicted_before_start->IsValid()); |
+ EXPECT_FALSE(evicted_after_end->IsValid()); |
+ |
+ // And our |Value()| call purged the earlier iterator. |
+ EXPECT_TRUE(it1->IsDetached()); |
+} |
+ |
namespace { |
enum RangePrepareMode { |
DataInMemory, |