The JavaScript Database, for Node.js, nw.js, electron and the browser
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
nedb/test/benchmark.test.js

292 lines
9.4 KiB

import { promisify } from 'util'
import { performance } from 'node:perf_hooks'
import Persistence from '../src/persistence.js'
import { access, unlink, constants } from 'fs/promises'
import Datastore from '../src/datastore.js'
const getRandomArray = n => {
const res = []
let i
let j
let temp
for (i = 0; i < n; i += 1) { res[i] = i }
for (i = n - 1; i >= 1; i -= 1) {
j = Math.floor((i + 1) * Math.random())
temp = res[i]
res[i] = res[j]
res[j] = temp
}
return res
}
const insertDocs = async (d, n) => {
const order = getRandomArray(n)
for (let i = 0; i <= n; i++) {
await d.insertAsync({ docNumber: order[i] })
await promisify(process.nextTick)()
}
}
const measure = async (name, n, cb) => {
performance.mark(`${name} start`)
for (let i = 0; i < n; i += 1) {
await cb(i)
}
performance.mark(`${name} end`)
const { duration } = performance.measure(`${name} average duration for ${n} operations`, `${name} start`, `${name} end`)
const opsPerSecond = Math.floor(1000 * n / duration)
console.log(`===== RESULT (${name}) ===== ${opsPerSecond} ops/s ===== ${Math.floor(duration / n * 1000) / 1000}ms/execution`)
}
describe('Performance tests without index', function () {
const n = 1000
const benchDb = 'workspace/bench.db'
let d
before(function () {
if (!process.argv.includes('--benchmark')) this.skip()
else this.timeout(60000)
})
beforeEach('Prepare database', async () => {
try {
await access(benchDb, constants.F_OK)
await unlink(benchDb)
} catch {}
await Persistence.ensureParentDirectoryExistsAsync(benchDb)
d = new Datastore({ filename: benchDb })
await d.loadDatabaseAsync()
})
afterEach('Clean database', async () => {
try {
await d.this.executor.queue.guardian
d = null
await access(benchDb, constants.F_OK)
await unlink(benchDb)
} catch {}
})
it('ensureIndex', async () => {
await insertDocs(d, n)
await measure('ensureIndex', n, async (i) => {
d.ensureIndexAsync({ fieldName: 'docNumber' })
delete d.indexes.docNumber
})
})
it('find', async () => {
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('find', n, async (i) => {
const docs = await d.findAsync({ docNumber: order[i] })
if (docs.length !== 1 || docs[0].docNumber !== order[i]) throw new Error('One find didnt work')
await promisify(process.nextTick)()
})
})
it('findOne', async () => {
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('findOne', n, async (i) => {
const doc = await d.findOneAsync({ docNumber: order[i] })
if (doc == null || doc.docNumber !== order[i]) throw new Error('One find didnt work')
await promisify(process.nextTick)()
})
})
it('find with $in', async () => {
await insertDocs(d, n)
const ins = []
const arraySize = Math.min(10, n)
// Preparing all the $in arrays, will take some time
for (let i = 0; i < n; i += 1) {
ins[i] = []
for (let j = 0; j < arraySize; j += 1) {
ins[i].push((i + j) % n)
}
}
await measure('find with $in', n, async (i) => {
const docs = await d.findAsync({ docNumber: { $in: ins[i] } })
if (docs.length !== arraySize) throw new Error('One find didnt work')
await promisify(process.nextTick)()
})
})
it('insert docs', async () => {
const order = getRandomArray(n)
await measure('insert docs', n, async (i) => {
await d.insertAsync({ docNumber: order[i] })
await promisify(process.nextTick)()
})
})
it('load database', async () => {
await insertDocs(d, n)
await measure('load database', n, async (i) => {
await d.loadDatabaseAsync()
})
})
it('Insert and remove one', async () => {
// TODO measure only remove
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one', n, async (i) => {
const nr = await d.removeAsync({ docNumber: order[i] }, { multi: false })
if (nr !== 1) throw new Error('One remove didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('Insert and remove one with multi option', async () => {
// TODO measure only remove
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with multi option', n, async (i) => {
const nr = await d.removeAsync({ docNumber: order[i] }, { multi: true })
if (nr !== 1) throw new Error('One remove didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('Update', async () => {
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with multi option', n, async (i) => {
const { numAffected } = await d.updateAsync({ docNumber: order[i] }, { docNumber: order[i] }, { multi: false })
if (numAffected !== 1) throw new Error('One update didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('Update with multi option', async () => {
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with multi option', n, async (i) => {
const { numAffected } = await d.updateAsync({ docNumber: order[i] }, { docNumber: order[i] }, { multi: true })
if (numAffected !== 1) throw new Error('One update didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('find with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('find with index', n, async (i) => {
const docs = await d.findAsync({ docNumber: order[i] })
if (docs.length !== 1 || docs[0].docNumber !== order[i]) throw new Error('One find didnt work')
await promisify(process.nextTick)()
})
})
it('findOne with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('findOne with index', n, async (i) => {
const doc = await d.findOneAsync({ docNumber: order[i] })
if (doc == null || doc.docNumber !== order[i]) throw new Error('One find didnt work')
await promisify(process.nextTick)()
})
})
it('find with $in with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const ins = []
const arraySize = Math.min(10, n)
// Preparing all the $in arrays, will take some time
for (let i = 0; i < n; i += 1) {
ins[i] = []
for (let j = 0; j < arraySize; j += 1) {
ins[i].push((i + j) % n)
}
}
await measure('find with $in with index', n, async (i) => {
const docs = await d.findAsync({ docNumber: { $in: ins[i] } })
if (docs.length !== arraySize) throw new Error('One find didnt work')
await promisify(process.nextTick)()
})
})
it('insert docs with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
const order = getRandomArray(n)
await measure('insert docs with index', n, async (i) => {
await d.insertAsync({ docNumber: order[i] })
await promisify(process.nextTick)()
})
})
it('load database with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
await measure('load database with index', n, async (i) => {
await d.loadDatabaseAsync()
})
})
it('Insert and remove one with index', async () => {
// TODO measure only remove
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with index', n, async (i) => {
const nr = await d.removeAsync({ docNumber: order[i] }, { multi: false })
if (nr !== 1) throw new Error('One remove didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('Insert and remove one with multi option with index', async () => {
// TODO measure only remove
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with multi option with index', n, async (i) => {
const nr = await d.removeAsync({ docNumber: order[i] }, { multi: true })
if (nr !== 1) throw new Error('One remove didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('Update with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with multi option with index', n, async (i) => {
const { numAffected } = await d.updateAsync({ docNumber: order[i] }, { docNumber: order[i] }, { multi: false })
if (numAffected !== 1) throw new Error('One update didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
it('Update with multi option with index', async () => {
await d.ensureIndexAsync({ fieldName: 'docNumber' })
await insertDocs(d, n)
const order = getRandomArray(n)
await measure('insert and remove one with multi option with index', n, async (i) => {
const { numAffected } = await d.updateAsync({ docNumber: order[i] }, { docNumber: order[i] }, { multi: true })
if (numAffected !== 1) throw new Error('One update didnt work')
await d.insertAsync({ docNumber: order[i] })
})
})
})