Bug 1595172 [wpt PR 20182] - [TransactionalLevelDB] Fix iterating 'Prev' from evicted iterators, a=testonly
authorDaniel Murphy <dmurph@chromium.org>
Mon, 25 Nov 2019 16:59:36 +0000
changeset 504461 61f7826a9e88fbe609a64276cb3d60f0e49343b5
parent 504460 820c7e9047f4ba8d6ddc0ca1335bce2260607a4b
child 504462 9839ef573c437b6f4f2550b8514fd36964f525fe
push id101897
push userwptsync@mozilla.com
push dateFri, 29 Nov 2019 11:10:32 +0000
treeherderautoland@47be1b3fdda6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1595172, 20182, 1022594, 1897007, 713947
milestone72.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1595172 [wpt PR 20182] - [TransactionalLevelDB] Fix iterating 'Prev' from evicted iterators, a=testonly Automatic update from web-platform-tests [TransactionalLevelDB] Fix iterating 'Prev' from evicted iterators Iterators in TransactionalLevelDB are evicted when there are any changes to the database. There is an edge case where an iterator is evicted while on the 'last' key of the database, and that key is deleted. When reloaded, it Seek()s to the previous key, only to become 'Invalid' because it reaches the end of the database. Unfortunately leveldb doesn't allow 'Prev' to be called from the end of the database and instead just stays invalid. The fix checks for the state where 'the iterator was valid before eviction and is invalid after reloading' in the Prev() method. In this state, there must be no no keys at or after the previously loaded key. Thus calling SeekToLast() will correctly position the iterator at the first element 'Prev' the previously loaded key. Bug: 1022594 Change-Id: Ifa938b441683ea9f2cac5d926ff22b734ab4bb67 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1897007 Commit-Queue: Daniel Murphy <dmurph@chromium.org> Auto-Submit: Daniel Murphy <dmurph@chromium.org> Reviewed-by: Ken Rockot <rockot@google.com> Cr-Commit-Position: refs/heads/master@{#713947} -- wpt-commits: bee0426b8ea027aef92cc4d1915ec6086aa90ccc wpt-pr: 20182
testing/web-platform/tests/IndexedDB/idbindex_reverse_cursor.any.js
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/IndexedDB/idbindex_reverse_cursor.any.js
@@ -0,0 +1,60 @@
+// META: title=Reverse Cursor Validity
+// META: script=support-promises.js
+
+async function iterateAndReturnAllCursorResult(testCase, cursor) {
+  return new Promise((resolve, reject) => {
+    let results = [];
+    cursor.onsuccess = testCase.step_func(function(e) {
+      let cursor = e.target.result;
+      if (!cursor) {
+        resolve(results);
+        return;
+      }
+      results.push(cursor.value);
+      cursor.continue();
+    });
+    cursor.onerror = reject;
+  });
+}
+
+promise_test(async testCase => {
+  const db = await createDatabase(testCase, db => {
+    db.createObjectStore('objectStore', {keyPath: 'key'})
+              .createIndex('index', 'indexedOn');
+  });
+  const txn1 = db.transaction(['objectStore'], 'readwrite');
+  txn1.objectStore('objectStore').add({'key': 'firstItem', 'indexedOn': 3});
+  const txn2 = db.transaction(['objectStore'], 'readwrite');
+  txn2.objectStore('objectStore').put({'key': 'firstItem', 'indexedOn': -1});
+  const txn3= db.transaction(['objectStore'], 'readwrite');
+  txn3.objectStore('objectStore').add({'key': 'secondItem', 'indexedOn': 2});
+
+  const txn4 = db.transaction(['objectStore'], 'readonly');
+  cursor = txn4.objectStore('objectStore').index('index').openCursor(IDBKeyRange.bound(0, 10), "prev");
+  let results = await iterateAndReturnAllCursorResult(testCase, cursor);
+
+  assert_equals(results.length, 1);
+
+  await promiseForTransaction(testCase, txn4);
+  db.close();
+}, 'Reverse cursor sees update from separate transactions.');
+
+promise_test(async testCase => {
+  const db = await createDatabase(testCase, db => {
+    db.createObjectStore('objectStore', {keyPath: 'key'})
+              .createIndex('index', 'indexedOn');
+  });
+  const txn = db.transaction(['objectStore'], 'readwrite');
+  txn.objectStore('objectStore').add({'key': '1', 'indexedOn': 2});
+  txn.objectStore('objectStore').put({'key': '1', 'indexedOn': -1});
+  txn.objectStore('objectStore').add({'key': '2', 'indexedOn': 1});
+
+  const txn2 = db.transaction(['objectStore'], 'readonly');
+  cursor = txn2.objectStore('objectStore').index('index').openCursor(IDBKeyRange.bound(0, 10), "prev");
+  let results = await iterateAndReturnAllCursorResult(testCase, cursor);
+
+  assert_equals(1, results.length);
+
+  await promiseForTransaction(testCase, txn2);
+  db.close();
+}, 'Reverse cursor sees in-transaction update.');