Skip to content

Commit b0f2e57

Browse files
authored
indexeddb.getAttachments(): reduce selects from N+1 (#8771)
Also add new perf tests in `perf.attachments.js` for doc with many attachments.
1 parent eafc0f1 commit b0f2e57

File tree

4 files changed

+59
-34
lines changed

4 files changed

+59
-34
lines changed

packages/node_modules/pouchdb-adapter-indexeddb/src/getAttachment.js

Lines changed: 9 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,19 @@
22

33
import { btoa, readAsBinaryString } from 'pouchdb-binary-utils';
44

5-
import { DOC_STORE } from './util';
5+
export default function getAttachment(txn, docId, attachId, attachment, opts, cb) {
6+
if (txn.error) {
7+
return cb(txn.error);
8+
}
9+
10+
const doc = opts.metadata;
11+
const data = doc.attachments[attachment.digest].data;
612

7-
function parseAttachment(attachment, opts, cb) {
813
if (opts.binary) {
9-
return cb(null, attachment);
14+
return cb(null, data);
1015
} else {
11-
readAsBinaryString(attachment, function (binString) {
16+
readAsBinaryString(data, function (binString) {
1217
cb(null, btoa(binString));
1318
});
1419
}
1520
}
16-
17-
function getAttachment(txn, docId, attachId, _, opts, cb) {
18-
if (txn.error) {
19-
return cb(txn.error);
20-
}
21-
22-
var attachment;
23-
24-
txn.txn.objectStore(DOC_STORE).get(docId).onsuccess = function (e) {
25-
var doc = e.target.result;
26-
var rev = doc.revs[opts.rev || doc.rev].data;
27-
var digest = rev._attachments[attachId].digest;
28-
attachment = doc.attachments[digest].data;
29-
};
30-
31-
txn.txn.oncomplete = function () {
32-
parseAttachment(attachment, opts, cb);
33-
};
34-
35-
txn.txn.onabort = cb;
36-
}
37-
38-
export {
39-
getAttachment,
40-
parseAttachment
41-
};

packages/node_modules/pouchdb-adapter-indexeddb/src/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import setup from './setup';
66
// API implementations
77
import info from './info';
88
import get from './get';
9-
import { getAttachment } from './getAttachment';
9+
import getAttachment from './getAttachment';
1010
import bulkDocs from './bulkDocs';
1111
import allDocs from './allDocs';
1212
import changes from './changes';

packages/node_modules/pouchdb-core/src/adapter.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ class AbstractPouchDB extends EventEmitter {
658658
// pass the rev through
659659
rev: doc._rev,
660660
binary: opts.binary,
661+
metadata: metadata,
661662
ctx: ctx
662663
}, function (err, data) {
663664
var att = doc._attachments[key];
@@ -698,6 +699,7 @@ class AbstractPouchDB extends EventEmitter {
698699
if (res.doc._attachments && res.doc._attachments[attachmentId]) {
699700
opts.ctx = res.ctx;
700701
opts.binary = true;
702+
opts.metadata = res.metadata;
701703
this._getAttachment(docId, attachmentId,
702704
res.doc._attachments[attachmentId], opts, callback);
703705
} else {

tests/performance/perf.attachments.js

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
'use strict';
22

3+
const MIME_OCTET = 'application/octet-stream';
4+
35
function randomBrowserBlob(size) {
46
var buff = new ArrayBuffer(size);
57
var arr = new Uint8Array(buff);
68
for (var i = 0; i < size; i++) {
79
arr[i] = Math.floor(65535 * Math.random());
810
}
9-
return new Blob([buff], {type: 'application/octet-stream'});
11+
return new Blob([buff], {type: MIME_OCTET});
1012
}
1113

1214
function randomBuffer(size) {
@@ -45,11 +47,53 @@ module.exports = function (PouchDB, callback) {
4547
},
4648
test: function (db, itr, doc, done) {
4749
db.putAttachment(Math.random().toString(), 'foo.txt', db._blob,
48-
'application/octet-stream').then(function () {
50+
MIME_OCTET).then(function () {
4951
done();
5052
}, done);
5153
}
52-
}
54+
},
55+
{
56+
name: 'many-attachments-base64',
57+
assertions: 1,
58+
iterations: 100,
59+
setup: function (db, callback) {
60+
const doc = {
61+
_id: 'doc1',
62+
_attachments: {},
63+
};
64+
for (let i=0; i<100; ++i) {
65+
doc._attachments['att-' + i] = {
66+
content_type: MIME_OCTET,
67+
data: randomBlob(50000),
68+
};
69+
}
70+
db.put(doc).then(() => callback()).catch(callback);
71+
},
72+
test: function (db, itr, doc, done) {
73+
db.get('doc1', {attachments: true}).then(() => done()).catch(done);
74+
}
75+
},
76+
{
77+
name: 'many-attachments-binary',
78+
assertions: 1,
79+
iterations: 100,
80+
setup: function (db, callback) {
81+
const doc = {
82+
_id: 'doc1',
83+
_attachments: {},
84+
};
85+
for (let i=0; i<100; ++i) {
86+
doc._attachments['att-' + i] = {
87+
content_type: MIME_OCTET,
88+
data: randomBlob(50000),
89+
};
90+
}
91+
db.put(doc).then(() => callback()).catch(callback);
92+
},
93+
test: function (db, itr, doc, done) {
94+
db.get('doc1', {attachments: true, binary: true}).then(() => done()).catch(done);
95+
}
96+
},
5397
];
5498

5599
utils.runTests(PouchDB, 'attachments', testCases, callback);

0 commit comments

Comments
 (0)