Skip to content
This repository was archived by the owner on Mar 23, 2023. It is now read-only.

Commit 71d6804

Browse files
committed
fix: benchmarks and perf tweaks
1 parent e929b4a commit 71d6804

File tree

3 files changed

+181
-28
lines changed

3 files changed

+181
-28
lines changed

bench.js

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/* eslint-disable no-console */
2+
'use strict'
3+
const Benchmark = require('benchmark')
4+
const randomBytes = require('iso-random-stream/src/random')
5+
const IDBStore = require('./src')
6+
const LevelStore = require('datastore-level')
7+
const { Key } = require('interface-datastore')
8+
9+
// add tests
10+
// new Benchmark.Suite('simple')
11+
// .add('simple put idb', {
12+
// defer: true,
13+
// fn: async (d) => {
14+
// const store = new IDBStore('hello1')
15+
// await store.open()
16+
// await store.put(new Key('/z/one'), Buffer.from('one'))
17+
// await store.close()
18+
// d.resolve()
19+
// }
20+
// })
21+
// .add('simple put level', {
22+
// defer: true,
23+
// fn: async (d) => {
24+
// const store = new LevelStore('hello2')
25+
// await store.open()
26+
// await store.put(new Key('/z/one'), Buffer.from('one'))
27+
// await store.close()
28+
// d.resolve()
29+
// }
30+
// })
31+
// // add listeners
32+
// .on('cycle', function (event) {
33+
// console.log(String(event.target))
34+
// })
35+
// .on('complete', function () {
36+
// console.log('Fastest is ' + this.filter('fastest').map('name'))
37+
// })
38+
// // run async
39+
// .run({ async: true })
40+
41+
// new Benchmark.Suite('parallel')
42+
// .add('parallel idb', {
43+
// defer: true,
44+
// fn: async (d) => {
45+
// const store = new IDBStore('parallel idb')
46+
// await store.open()
47+
// const data = []
48+
// for (let i = 0; i < 100; i++) {
49+
// data.push([new Key(`/z/key${i}`), Buffer.from(`data${i}`)])
50+
// }
51+
52+
// await Promise.all(data.map(d => store.put(d[0], d[1])))
53+
// await Promise.all(data.map(d => store.get(d[0])))
54+
// await store.close()
55+
// d.resolve()
56+
// }
57+
// })
58+
// .add('parallel level', {
59+
// defer: true,
60+
// fn: async (d) => {
61+
// const store = new LevelStore('parallel level')
62+
// await store.open()
63+
// const data = []
64+
// for (let i = 0; i < 100; i++) {
65+
// data.push([new Key(`/z/key${i}`), Buffer.from(`data${i}`)])
66+
// }
67+
68+
// await Promise.all(data.map(d => store.put(d[0], d[1])))
69+
// await Promise.all(data.map(d => store.get(d[0])))
70+
// await store.close()
71+
// d.resolve()
72+
// }
73+
// })
74+
// // add listeners
75+
// .on('cycle', function (event) {
76+
// console.log(String(event.target))
77+
// })
78+
// .on('complete', function () {
79+
// console.log('Fastest is ' + this.filter('fastest').map('name'))
80+
// })
81+
// // run async
82+
// .run({ async: true })
83+
84+
new Benchmark.Suite('batch')
85+
.add('batch idb', {
86+
defer: true,
87+
fn: async (d) => {
88+
const store = new IDBStore('batch idb')
89+
await store.open()
90+
const b = store.batch()
91+
const count = 400
92+
for (let i = 0; i < count; i++) {
93+
b.put(new Key(`/a/hello${i}`), randomBytes(32))
94+
b.put(new Key(`/q/hello${i}`), randomBytes(64))
95+
b.put(new Key(`/z/hello${i}`), randomBytes(128))
96+
}
97+
98+
await b.commit()
99+
100+
const total = async iterable => {
101+
let count = 0
102+
for await (const _ of iterable) count++ // eslint-disable-line
103+
return count
104+
}
105+
106+
await total(store.query({ prefix: '/a' }))
107+
await total(store.query({ prefix: '/z' }))
108+
await total(store.query({ prefix: '/q' }))
109+
await store.close()
110+
d.resolve()
111+
}
112+
})
113+
.add('batch level', {
114+
defer: true,
115+
fn: async (d) => {
116+
const store = new LevelStore('batch level')
117+
await store.open()
118+
const b = store.batch()
119+
const count = 400
120+
for (let i = 0; i < count; i++) {
121+
b.put(new Key(`/a/hello${i}`), randomBytes(32))
122+
b.put(new Key(`/q/hello${i}`), randomBytes(64))
123+
b.put(new Key(`/z/hello${i}`), randomBytes(128))
124+
}
125+
126+
await b.commit()
127+
128+
const total = async iterable => {
129+
let count = 0
130+
for await (const _ of iterable) count++ // eslint-disable-line
131+
return count
132+
}
133+
134+
await total(store.query({ prefix: '/a' }))
135+
await total(store.query({ prefix: '/z' }))
136+
await total(store.query({ prefix: '/q' }))
137+
await store.close()
138+
d.resolve()
139+
}
140+
})
141+
// add listeners
142+
.on('cycle', function (event) {
143+
console.log(String(event.target))
144+
})
145+
.on('complete', function () {
146+
console.log('Fastest is ' + this.filter('fastest').map('name'))
147+
})
148+
// run async
149+
.run({ async: true })

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
"aegir": "^21.4.5",
3939
"chai": "^4.2.0",
4040
"datastore-core": "ipfs/js-datastore-core#fix/add-buffer",
41-
"dirty-chai": "^2.0.1"
41+
"datastore-level": "^0.14.1",
42+
"dirty-chai": "^2.0.1",
43+
"iso-random-stream": "^1.1.1"
4244
}
4345
}

src/index.js

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,34 @@ function typedarrayToBuffer (arr) {
3535
}
3636
}
3737

38+
const queryIt = async function * (q, store, location) {
39+
let cursor = await store.transaction(location).store.openCursor()
40+
let limit = 0
41+
42+
if (cursor && q.offset && q.offset > 0) {
43+
cursor = await cursor.advance(q.offset)
44+
}
45+
46+
while (cursor) {
47+
// limit
48+
if (q.limit !== undefined && q.limit === limit) {
49+
return
50+
}
51+
limit++
52+
53+
const key = new Key(Buffer.from(cursor.key))
54+
const value = Buffer.from(cursor.value)
55+
if (!q.prefix || (q.prefix && key.toString().startsWith(q.prefix))) {
56+
if (q.keysOnly) {
57+
yield { key }
58+
} else {
59+
yield { key, value }
60+
}
61+
}
62+
cursor = await cursor.continue()
63+
}
64+
}
65+
3866
class IdbDatastore {
3967
constructor (location) {
4068
this.location = location
@@ -135,34 +163,8 @@ class IdbDatastore {
135163
if (this.store === null) {
136164
throw new Error('Datastore needs to be opened.')
137165
}
138-
let limit = 0
139-
140-
let it = (async function * (store, location) {
141-
let cursor = await store.transaction(location).store.openCursor()
142-
143-
if (cursor && q.offset && q.offset > 0) {
144-
cursor = await cursor.advance(q.offset)
145-
}
146166

147-
while (cursor) {
148-
// limit
149-
if (q.limit !== undefined && q.limit === limit) {
150-
return
151-
}
152-
limit++
153-
154-
const key = new Key(Buffer.from(cursor.key))
155-
const value = Buffer.from(cursor.value)
156-
if (!q.prefix || (q.prefix && key.toString().startsWith(q.prefix))) {
157-
if (q.keysOnly) {
158-
yield { key }
159-
} else {
160-
yield { key, value }
161-
}
162-
}
163-
cursor = await cursor.continue()
164-
}
165-
})(this.store, this.location)
167+
let it = queryIt(q, this.store, this.location)
166168

167169
if (Array.isArray(q.filters)) {
168170
it = q.filters.reduce((it, f) => filter(it, f), it)

0 commit comments

Comments
 (0)