milodb
Version:
A simple mini database with optional encryption to store key-value pairs
143 lines (120 loc) • 5.38 kB
JavaScript
const fs = require('fs').promises;
const path = require('path');
const MinoDB = require('../src/index');
const BENCHMARK_DB_PATH = path.join(__dirname, '..', 'db', 'benchmark-db.json');
const NUM_ROWS = 1_000_000;
const SEARCH_SAMPLES = 1000; // Number of search operations to perform
const EDIT_SAMPLES = 1000; // Number of edit operations to perform
async function runSearchEditBenchmark() {
console.log('Starting Search and Edit Benchmark...\n');
// Initialize database
const db = new MinoDB(null, false);
db.dbPath = BENCHMARK_DB_PATH;
// Generate test data if it doesn't exist
if (!await fileExists(BENCHMARK_DB_PATH)) {
console.log(`Creating test database with ${NUM_ROWS.toLocaleString()} entries...`);
for (let i = 0; i < NUM_ROWS; i++) {
await db.set(`key${i}`, `value${i}`);
if (i > 0 && i % 100_000 === 0) {
console.log(` Inserted ${i.toLocaleString()} entries...`);
}
}
}
// Benchmark Search Operations
console.log('\nBenchmarking Search Operations...');
const searchTimes = [];
const searchPatterns = [
'value1', // Common prefix
'999', // Common suffix
'500', // Middle value
'key1', // Key search
'nonexistent' // No matches
];
for (const pattern of searchPatterns) {
console.log(`\nSearching for pattern: "${pattern}"`);
// Basic search
const basicStart = Date.now();
const basicResults = await db.search(pattern);
const basicTime = Date.now() - basicStart;
searchTimes.push({ pattern, type: 'basic', time: basicTime, results: Object.keys(basicResults).length });
console.log(` Basic search: ${basicTime}ms, found ${Object.keys(basicResults).length} results`);
// Regex search
const regexStart = Date.now();
const regexResults = await db.search(pattern, { regex: true });
const regexTime = Date.now() - regexStart;
searchTimes.push({ pattern, type: 'regex', time: regexTime, results: Object.keys(regexResults).length });
console.log(` Regex search: ${regexTime}ms, found ${Object.keys(regexResults).length} results`);
// Case-sensitive search
const caseStart = Date.now();
const caseResults = await db.search(pattern.toUpperCase(), { caseSensitive: true });
const caseTime = Date.now() - caseStart;
searchTimes.push({ pattern, type: 'case-sensitive', time: caseTime, results: Object.keys(caseResults).length });
console.log(` Case-sensitive search: ${caseTime}ms, found ${Object.keys(caseResults).length} results`);
}
// Benchmark Edit Operations
console.log('\nBenchmarking Edit Operations...');
const editTimes = [];
// Random edits
for (let i = 0; i < EDIT_SAMPLES; i++) {
const key = `key${Math.floor(Math.random() * NUM_ROWS)}`;
const newValue = `updated_value_${i}`;
const start = Date.now();
await db.set(key, newValue);
const time = Date.now() - start;
editTimes.push(time);
if (i % 100 === 0) {
console.log(` Completed ${i} edits...`);
}
}
// Batch edits
console.log('\nBenchmarking Batch Edit Operations...');
const batchSize = 100;
const batchTimes = [];
for (let i = 0; i < EDIT_SAMPLES / batchSize; i++) {
const operations = [];
for (let j = 0; j < batchSize; j++) {
const key = `key${Math.floor(Math.random() * NUM_ROWS)}`;
operations.push({
type: 'set',
key,
value: `batch_updated_${i}_${j}`
});
}
const start = Date.now();
await db.batch(operations);
const time = Date.now() - start;
batchTimes.push(time);
console.log(` Completed batch ${i + 1}...`);
}
// Print Results
console.log('\nBenchmark Results:');
console.log('\nSearch Operations:');
searchTimes.forEach(({ pattern, type, time, results }) => {
console.log(` ${type} search for "${pattern}": ${time}ms, found ${results} results`);
});
console.log('\nEdit Operations:');
const avgEditTime = editTimes.reduce((a, b) => a + b, 0) / editTimes.length;
console.log(` Average single edit time: ${avgEditTime.toFixed(2)}ms`);
console.log('\nBatch Edit Operations:');
const avgBatchTime = batchTimes.reduce((a, b) => a + b, 0) / batchTimes.length;
console.log(` Average batch edit time (${batchSize} operations): ${avgBatchTime.toFixed(2)}ms`);
console.log(` Average time per operation in batch: ${(avgBatchTime / batchSize).toFixed(2)}ms`);
// Memory Usage
const mem = process.memoryUsage();
console.log('\nMemory Usage:');
console.log(` RSS: ${(mem.rss / 1024 / 1024).toFixed(2)} MB`);
console.log(` Heap Total: ${(mem.heapTotal / 1024 / 1024).toFixed(2)} MB`);
console.log(` Heap Used: ${(mem.heapUsed / 1024 / 1024).toFixed(2)} MB`);
}
async function fileExists(path) {
try {
await fs.access(path);
return true;
} catch {
return false;
}
}
runSearchEditBenchmark().catch(err => {
console.error('Benchmark failed:', err);
process.exit(1);
});