Index: chrome/test/data/indexeddb/perf_shared.js |
diff --git a/chrome/test/data/indexeddb/perf_shared.js b/chrome/test/data/indexeddb/perf_shared.js |
index e761813e22f401ceda3d01c4319cd2cd8a252617..6fc6e315b3c208f54c6eefdffe06be673556cc3a 100644 |
--- a/chrome/test/data/indexeddb/perf_shared.js |
+++ b/chrome/test/data/indexeddb/perf_shared.js |
@@ -4,6 +4,7 @@ |
window.indexedDB = window.indexedDB || window.webkitIndexedDB || |
window.mozIndexedDB || window.msIndexedDB; |
+window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange; |
var automation = { |
results: {} |
@@ -59,7 +60,7 @@ var curVersion; |
// indexIsMultiEntry: the "multiEntry" option for IDBIndexParameters |
// |
function createDatabase( |
- name, objectStoreNames, handler, errorHandler, options) { |
+ name, objectStoreNames, handler, errorHandler, optionSets) { |
var openRequest = indexedDB.open(name, baseVersion); |
openRequest.onblocked = errorHandler; |
function createObjectStores(db) { |
@@ -67,17 +68,21 @@ function createDatabase( |
var name = objectStoreNames[store]; |
assert(!db.objectStoreNames.contains(name)); |
var os = db.createObjectStore(name); |
- if (options && options.indexName) { |
- assert('indexKeyPath' in options); |
- os.createIndex(options.indexName, options.indexKeyPath, |
- { unique: options.indexIsUnique, |
- multiEntry: options.indexIsMultiEntry }); |
+ if (optionSets) { |
+ for (o in optionSets) { |
+ var options = optionSets[o]; |
+ assert(options.indexName); |
+ assert('indexKeyPath' in options); |
+ os.createIndex(options.indexName, options.indexKeyPath, |
+ { unique: options.indexIsUnique, |
+ multiEntry: options.indexIsMultiEntry }); |
+ } |
} |
} |
} |
openRequest.onupgradeneeded = function(ev) { |
- // TODO: This is the spec-compliant path, which doesn't yet work in Chrome, |
- // and isn't yet tested, as this function won't currently be called. |
+ // TODO(ericu): This is the spec-compliant path, which doesn't yet work in |
+ // Chrome, and isn't yet tested, as this function won't currently be called. |
assert(openRequest == ev.target); |
createObjectStores(openRequest.result); |
// onsuccess will get called after this exits. |
@@ -113,7 +118,7 @@ function alterObjectStores( |
var version = curVersion + 1; |
var openRequest = indexedDB.open(name, version); |
openRequest.onblocked = errorHandler; |
- // TODO: This won't work in Firefox yet; see above in createDatabase. |
+ // TODO(ericu): This won't work in Firefox yet; see above in createDatabase. |
openRequest.onsuccess = function(ev) { |
assert(openRequest == ev.target); |
var db = openRequest.result; |
@@ -170,7 +175,7 @@ function getCompletionFunc(testName, startTime, onTestComplete) { |
// Ignore the cleanup time for this test. |
automation.addResult(testName, duration); |
automation.setStatus("Deleting database."); |
- // TODO: Turn on actual deletion; for now it's way too slow. |
+ // TODO(ericu): Turn on actual deletion; for now it's way too slow. |
// deleteDatabase(testName, onDeleted); |
onTestComplete(); |
} |
@@ -178,16 +183,62 @@ function getCompletionFunc(testName, startTime, onTestComplete) { |
function getDisplayName(args) { |
// The last arg is the completion callback the test runner tacks on. |
+ // TODO(ericu): Make test errors delete the database automatically. |
return getDisplayName.caller.name + "_" + |
Array.prototype.slice.call(args, 0, args.length - 1).join("_"); |
} |
+// Pad a string [or object convertible to a string] to a fixed width; use this |
+// to have numeric strings sort properly. |
+function padToWidth(s, width) { |
+ s = String(s); |
+ assert(s.length <= width); |
+ while (s.length < width) { |
+ s = "0" + s; |
+ } |
+ return s; |
+} |
+ |
function getSimpleKey(i) { |
- return "key " + i; |
+ return "key " + padToWidth(i, 10); |
} |
function getSimpleValue(i) { |
- return "value " + i; |
+ return "value " + padToWidth(i, 10); |
+} |
+ |
+function getForwardIndexKey(i) { |
+ return i; |
+} |
+ |
+function getBackwardIndexKey(i) { |
+ return -i; |
+} |
+ |
+// This is useful for indexing by keypath; the two names should be ordered in |
+// opposite directions for all i in uint32 range. |
+function getObjectValue(i) { |
+ return { |
+ firstName: getForwardIndexKey(i), |
+ lastName: getBackwardIndexKey(i) |
+ }; |
+} |
+ |
+function getNFieldName(k) { |
+ return "field" + k; |
+} |
+ |
+function getNFieldObjectValue(i, n) { |
+ assert(Math.floor(n) == n); |
+ assert(n > 0); |
+ var o = {}; |
+ for (; n > 0; --n) { |
+ // The value varies per field, each object will tend to be unique, |
+ // and thanks to the modulus, indexing on different fields will give you |
+ // different ordering for large-enough data sets. |
+ o[getNFieldName(n - 1)] = Math.pow(i + 0.5, n + 0.5) % 65536; |
+ } |
+ return o; |
} |
function putLinearValues( |
@@ -238,6 +289,53 @@ function putRandomValues( |
} |
} |
+// getKey should be deterministic, as we assume that a cursor that starts at |
+// getKey(X) and runs through getKey(X + K) has exactly K values available. |
+// This is annoying to guarantee generally when using an index, so we avoid both |
+// ends of the key space just in case and use simple indices. |
+// TODO(ericu): Figure out if this can be simplified and we can remove uses of |
+// getObjectValue in favor of getNFieldObjectValue. |
+function getValuesFromCursor( |
+ transaction, inputObjectStoreName, numReads, numKeys, indexName, getKey, |
+ readKeysOnly, outputObjectStoreName) { |
+ assert(2 * numReads < numKeys); |
+ if (!getKey) |
+ getKey = getSimpleKey; |
+ var rand = Math.floor(Math.random() * (numKeys - 2 * numReads)) + numReads; |
+ var values = []; |
+ var queryObject = transaction.objectStore(inputObjectStoreName); |
+ assert(queryObject); |
+ if (indexName) |
+ queryObject = queryObject.index(indexName); |
+ var keyRange = IDBKeyRange.bound( |
+ getKey(rand), getKey(rand + numReads), false, true); |
+ var request; |
+ if (readKeysOnly) { |
+ request = queryObject.openKeyCursor(keyRange); |
+ } else { |
+ request = queryObject.openCursor(keyRange); |
+ } |
+ var oos; |
+ if (outputObjectStoreName) |
+ oos = transaction.objectStore(outputObjectStoreName); |
+ var numReadsLeft = numReads; |
+ request.onsuccess = function(event) { |
+ var cursor = event.target.result; |
+ if (cursor) { |
+ assert(numReadsLeft); |
+ --numReadsLeft; |
+ if (oos) // Put in random order for maximum difficulty. |
+ oos.put(cursor.value, Math.random()); |
+ values.push({key: cursor.key, value: cursor.value}); |
+ cursor.continue(); |
+ } else { |
+ assert(!numReadsLeft); |
+ } |
+ } |
+ request.onerror = onError; |
+} |
+ |
+ |
function stringOfLength(n) { |
assert(n > 0); |
assert(n == Math.floor(n)); |