diff --git a/packages/node_modules/pouchdb-adapter-idb/src/allDocs.js b/packages/node_modules/pouchdb-adapter-idb/src/allDocs.js index b7bca86a74..482aef0acd 100644 --- a/packages/node_modules/pouchdb-adapter-idb/src/allDocs.js +++ b/packages/node_modules/pouchdb-adapter-idb/src/allDocs.js @@ -3,7 +3,8 @@ import { collectConflicts } from 'pouchdb-merge'; import { ATTACH_STORE, BY_SEQ_STORE, - DOC_STORE + DOC_STORE, + META_STORE } from './constants'; import { decodeDoc, @@ -15,7 +16,6 @@ import { } from './utils'; import runBatchedCursor from './runBatchedCursor'; import getAll from './getAll'; -import countDocs from './countDocs'; function createKeyRange(start, end, inclusiveEnd, key, descending) { try { @@ -64,7 +64,7 @@ function idbAllDocs(opts, idb, callback) { keyRangeError.name, keyRangeError.message)); } - var stores = [DOC_STORE, BY_SEQ_STORE]; + var stores = [DOC_STORE, BY_SEQ_STORE, META_STORE]; if (opts.attachments) { stores.push(ATTACH_STORE); @@ -78,13 +78,14 @@ function idbAllDocs(opts, idb, callback) { txn.onabort = idbError(callback); var docStore = txn.objectStore(DOC_STORE); var seqStore = txn.objectStore(BY_SEQ_STORE); + var metaStore = txn.objectStore(META_STORE); var docIdRevIndex = seqStore.index('_doc_id_rev'); var results = []; var docCount; - countDocs(txn, function (thisDocCount) { - docCount = thisDocCount; - }); + metaStore.get(META_STORE).onsuccess = function (e) { + docCount = e.target.result.docCount; + }; // if the user specifies include_docs=true, then we don't // want to block the main cursor while we're fetching the doc diff --git a/packages/node_modules/pouchdb-adapter-idb/src/blobSupport.js b/packages/node_modules/pouchdb-adapter-idb/src/blobSupport.js index 249324b971..7e46ae2210 100644 --- a/packages/node_modules/pouchdb-adapter-idb/src/blobSupport.js +++ b/packages/node_modules/pouchdb-adapter-idb/src/blobSupport.js @@ -17,17 +17,9 @@ import { DETECT_BLOB_SUPPORT_STORE } from './constants'; function checkBlobSupport(txn) { return new Promise(function (resolve) { var blob = createBlob(['']); - txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key'); + var req = txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key'); - txn.onabort = function (e) { - // If the transaction aborts now its due to not being able to - // write to the database, likely due to the disk being full - e.preventDefault(); - e.stopPropagation(); - resolve(false); - }; - - txn.oncomplete = function () { + req.onsuccess = function () { var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/); var matchedEdge = navigator.userAgent.match(/Edge\//); // MS Edge pretends to be Chrome 42: @@ -35,6 +27,14 @@ function checkBlobSupport(txn) { resolve(matchedEdge || !matchedChrome || parseInt(matchedChrome[1], 10) >= 43); }; + + txn.onabort = function (e) { + // If the transaction aborts now its due to not being able to + // write to the database, likely due to the disk being full + e.preventDefault(); + e.stopPropagation(); + resolve(false); + }; }).catch(function () { return false; // error, so assume unsupported }); diff --git a/packages/node_modules/pouchdb-adapter-idb/src/bulkDocs.js b/packages/node_modules/pouchdb-adapter-idb/src/bulkDocs.js index fc09db0ffb..372846ffdd 100644 --- a/packages/node_modules/pouchdb-adapter-idb/src/bulkDocs.js +++ b/packages/node_modules/pouchdb-adapter-idb/src/bulkDocs.js @@ -16,7 +16,8 @@ import { ATTACH_STORE, BY_SEQ_STORE, DOC_STORE, - LOCAL_STORE + LOCAL_STORE, + META_STORE } from './constants'; import { @@ -36,7 +37,9 @@ function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { var bySeqStore; var attachStore; var attachAndSeqStore; + var metaStore; var docInfoError; + var metaDoc; for (var i = 0, len = docInfos.length; i < len; i++) { var doc = docInfos[i]; @@ -53,6 +56,8 @@ function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { return callback(docInfoError); } + var allDocsProcessed = false; + var docCountDelta = 0; var results = new Array(docInfos.length); var fetchedDocs = new Map(); var preconditionErrored = false; @@ -70,7 +75,8 @@ function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { var stores = [ DOC_STORE, BY_SEQ_STORE, ATTACH_STORE, - LOCAL_STORE, ATTACH_AND_SEQ_STORE + LOCAL_STORE, ATTACH_AND_SEQ_STORE, + META_STORE ]; var txnResult = openTransactionSafely(idb, stores, 'readwrite'); if (txnResult.error) { @@ -84,6 +90,12 @@ function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { bySeqStore = txn.objectStore(BY_SEQ_STORE); attachStore = txn.objectStore(ATTACH_STORE); attachAndSeqStore = txn.objectStore(ATTACH_AND_SEQ_STORE); + metaStore = txn.objectStore(META_STORE); + + metaStore.get(META_STORE).onsuccess = function (e) { + metaDoc = e.target.result; + updateDocCountIfReady(); + }; verifyAttachments(function (err) { if (err) { @@ -94,9 +106,24 @@ function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { }); } + function onAllDocsProcessed() { + allDocsProcessed = true; + updateDocCountIfReady(); + } + function idbProcessDocs() { processDocs(dbOpts.revs_limit, docInfos, api, fetchedDocs, - txn, results, writeDoc, opts); + txn, results, writeDoc, opts, onAllDocsProcessed); + } + + function updateDocCountIfReady() { + if (!metaDoc || !allDocsProcessed) { + return; + } + // caching the docCount saves a lot of time in allDocs() and + // info(), which is why we go to all the trouble of doing this + metaDoc.docCount += docCountDelta; + metaStore.put(metaDoc); } function fetchExistingDocs() { @@ -214,6 +241,9 @@ function idbBulkDocs(dbOpts, req, opts, api, idb, callback) { isUpdate, resultsIdx, callback); } + docCountDelta += delta; + updateDocCountIfReady(); + finishDoc(docInfo, winningRev, winningRevIsDeleted, isUpdate, resultsIdx, callback); } diff --git a/packages/node_modules/pouchdb-adapter-idb/src/index.js b/packages/node_modules/pouchdb-adapter-idb/src/index.js index b68c395108..e162f74854 100644 --- a/packages/node_modules/pouchdb-adapter-idb/src/index.js +++ b/packages/node_modules/pouchdb-adapter-idb/src/index.js @@ -390,17 +390,16 @@ function init(api, opts, callback) { var updateSeq; var docCount; - var txnResult = openTransactionSafely(idb, [DOC_STORE, BY_SEQ_STORE], 'readonly'); + var txnResult = openTransactionSafely(idb, [META_STORE, BY_SEQ_STORE], 'readonly'); if (txnResult.error) { return callback(txnResult.error); } var txn = txnResult.txn; - countDocs(txn, function (thisDocCount) { - docCount = thisDocCount; - }); - var cursor = txn.objectStore(BY_SEQ_STORE).openCursor(null, 'prev'); - cursor.onsuccess = function (event) { - var cursor = event.target.result; + txn.objectStore(META_STORE).get(META_STORE).onsuccess = function (e) { + docCount = e.target.result.docCount; + }; + txn.objectStore(BY_SEQ_STORE).openCursor(null, 'prev').onsuccess = function (e) { + var cursor = e.target.result; updateSeq = cursor ? cursor.key : 0; }; @@ -705,65 +704,90 @@ function init(api, opts, callback) { cachedDBs.delete(dbName); }; + // Do a few setup operations (in parallel as much as possible): + // 1. Fetch meta doc + // 2. Check blob support + // 3. Calculate docCount + // 4. Generate an instanceId if necessary + // 5. Store docCount and instanceId on meta doc + var txn = idb.transaction([ META_STORE, DETECT_BLOB_SUPPORT_STORE, DOC_STORE ], 'readwrite'); - var getMetaReq = txn.objectStore(META_STORE).get(META_STORE); - - var blobSupport = null; - var instanceId = null; - - getMetaReq.onsuccess = function (e) { - var complete = false; - function checkSetupComplete() { - if (blobSupport !== null && instanceId !== null && !complete) { - complete = true; - api._meta = { - name: dbName, - instanceId: instanceId, - blobSupport: blobSupport - }; + var storedMetaDoc = false; + var metaDoc; + var docCount; + var blobSupport; + var instanceId; - cachedDBs.set(dbName, { - idb: idb, - global: api._meta - }); - callback(null, api); - } + function completeSetup() { + if (typeof blobSupport === 'undefined' || !storedMetaDoc) { + return; } + api._meta = { + name: dbName, + instanceId: instanceId, + blobSupport: blobSupport + }; - // - // fetch/store the id - // + cachedDBs.set(dbName, { + idb: idb, + global: api._meta + }); + callback(null, api); + } - var meta = e.target.result || {id: META_STORE}; - if (dbName + '_id' in meta) { - instanceId = meta[dbName + '_id']; - checkSetupComplete(); + function storeMetaDocIfReady() { + if (typeof docCount === 'undefined' || typeof metaDoc === 'undefined') { + return; + } + var instanceKey = dbName + '_id'; + if (instanceKey in metaDoc) { + instanceId = metaDoc[instanceKey]; } else { - instanceId = uuid(); - meta[dbName + '_id'] = instanceId; - txn.objectStore(META_STORE).put(meta).onsuccess = function () { - checkSetupComplete(); - }; + metaDoc[instanceKey] = instanceId = uuid(); } + metaDoc.docCount = docCount; + txn.objectStore(META_STORE).put(metaDoc); + } - // - // check blob support - // + // + // fetch or generate the instanceId + // + txn.objectStore(META_STORE).get(META_STORE).onsuccess = function (e) { + metaDoc = e.target.result || { id: META_STORE }; + storeMetaDocIfReady(); + }; - if (!blobSupportPromise) { - // make sure blob support is only checked once - blobSupportPromise = checkBlobSupport(txn); - } + // + // countDocs + // + countDocs(txn, function (count) { + docCount = count; + storeMetaDocIfReady(); + }); - blobSupportPromise.then(function (val) { - blobSupport = val; - checkSetupComplete(); - }); + // + // check blob support + // + if (!blobSupportPromise) { + // make sure blob support is only checked once + blobSupportPromise = checkBlobSupport(txn); + } + + blobSupportPromise.then(function (val) { + blobSupport = val; + completeSetup(); + }); + + // only when the metadata put transaction has completed, + // consider the setup done + txn.oncomplete = function () { + storedMetaDoc = true; + completeSetup(); }; };