Skip to content

Commit

Permalink
Implement the buffer feature
Browse files Browse the repository at this point in the history
  • Loading branch information
devraymondsh committed Jan 8, 2024
1 parent ae7d133 commit e26d7b8
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 551 deletions.
45 changes: 21 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,31 @@ Kivi is a high-performance in-memory key-value database written in the Zig progr
## Latest benchmark:
```
JsMap:
┌─────────┬─────────────────┬─────────────────────┬────────────────────┬────────────────────────┬───────────────────┬───────────────────────┐
│ (index) │ totalLookupTime │ totalBulkLookupTime │ totalInsertionTime │ totalBulkInsertionTime │ totalDeletionTime │ totalBulkDeletionTime
├─────────┼─────────────────┼─────────────────────┼────────────────────┼────────────────────────┼───────────────────┼───────────────────────┤
│ 0 │ '134.17 ms' │ '138.9 ms' │ '155.65 ms' │ '301.3 ms' │ '197.46 ms' │ '215.23 ms'
│ 1 │ '137.91 ms' │ '135.72 ms' '151.54 ms' │ '167.48 ms' │ '242.4 ms' │ '217.72 ms'
│ average │ '136.04 ms' │ '137.31 ms' '153.59 ms' │ '234.39 ms' │ '219.93 ms' │ '216.48 ms'
└─────────┴─────────────────┴─────────────────────┴────────────────────┴────────────────────────┴───────────────────┴───────────────────────┘
┌─────────┬─────────────────┬───────────────────────────────────────┐
│ (index) │ totalLookupTime │ totalInsertionTime │ totalDeletionTime │
├─────────┼─────────────────┼───────────────────────────────────────┤
│ 0 │ '1112.18 ms' │ '1258.46 ms' │ '1272.44 ms' │
│ 1 │ '1103.26 ms' │ '1199.46 ms' │ '1281.72 ms' │
│ average │ '1107.72 ms' │ '1228.96 ms' │ '1277.08 ms' │
└─────────┴─────────────────┴───────────────────────────────────────┘
Kivi:
┌─────────┬─────────────────┬─────────────────────┬────────────────────┬────────────────────────┬───────────────────┬───────────────────────┐
│ (index) │ totalLookupTime │ totalBulkLookupTime │ totalInsertionTime │ totalBulkInsertionTime │ totalDeletionTime │ totalBulkDeletionTime
├─────────┼─────────────────┼─────────────────────┼────────────────────┼────────────────────────┼───────────────────┼───────────────────────┤
│ 0 │ '352.02 ms' │ '774.82 ms' │ '341.96 ms' │ '555.72 ms' │ '346.08 ms' │ '793.16 ms'
│ 1 │ '353.9 ms' '791.95 ms' │ '341.23 ms' │ '543.91 ms' │ '367.19 ms' │ '805.19 ms'
│ average │ '352.96 ms' │ '783.38 ms' │ '341.59 ms' │ '549.81 ms' │ '356.64 ms' │ '799.18 ms'
└─────────┴─────────────────┴─────────────────────┴────────────────────┴────────────────────────┴───────────────────┴───────────────────────┘
┌─────────┬─────────────────┬───────────────────────────────────────┐
│ (index) │ totalLookupTime │ totalInsertionTime │ totalDeletionTime │
├─────────┼─────────────────┼───────────────────────────────────────┤
│ 0 │ '1350.07 ms' │ '559.04 ms' │ '1355.66 ms' │
│ 1 │ '1349.39 ms' │ '557.93 ms' │ '1346.2 ms' │
│ average │ '1349.73 ms' │ '558.49 ms' │ '1350.93 ms' │
└─────────┴─────────────────┴───────────────────────────────────────┘
This table shows how much JsMap is faster than Kivi:
┌───────────────┬─────────┐
│ (index) │ Values │
├───────────────┼─────────┤
│ lookup │ '2.59x' │
│ insertion │ '2.22x' │
│ deletion │ '1.62x' │
│ bulkLookup │ '5.71x' │
│ bulkInsertion │ '2.35x' │
│ bulkDeletion │ '3.69x' │
└───────────────┴─────────┘
┌───────────┬─────────┐
│ (index) │ Values │
├───────────┼─────────┤
│ lookup │ '1.22x' │
│ insertion │ '0.45x' │
│ deletion │ '1.06x' │
└───────────┴─────────┘
```

## Code of conduct:
Expand Down
135 changes: 16 additions & 119 deletions bench/bench-with-builtin.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,61 +34,46 @@ const roundToTwoDecimal = (num) => +(Math.round(num + "e+2") + "e-2");
const benchmarkDeletion = (data, o) => {
const startingTime = performance.now();
for (const item of data) {
assert(`${o.name} deletion`, o.del(item.key), item.value);
assert(
`${o.name} deletion`,
o.del(Buffer.from(item.key, "utf8")).toString(),
Buffer.from(item.value, "utf8").toString()
);
}
return performance.now() - startingTime;
};
const benchmarkBulkDeletion = (data, o) => {
const startingTime = performance.now();
o.bulkDel(dataKeys);
return performance.now() - startingTime;
};
const benchmarkLookup = (data, o) => {
const startingTime = performance.now();
for (const item of data) {
assert(`${o.name} lookup`, o.get(item.key), item.value);
assert(
`${o.name} lookup`,
o.get(Buffer.from(item.key, "utf8")).toString(),
Buffer.from(item.value, "utf8").toString()
);
}
return performance.now() - startingTime;
};
const benchmarkBulkLookup = (data, o) => {
const startingTime = performance.now();
o.bulkGet(dataKeys);
return performance.now() - startingTime;
};
const benchmarkInsertion = (data, o) => {
const startingTime = performance.now();
for (const item of data) {
o.set(item.key, item.value);
o.set(Buffer.from(item.key, "utf8"), Buffer.from(item.value, "utf8"));
}
return performance.now() - startingTime;
};
const benchmarkBulkInsertion = (data, o) => {
const startingTime = performance.now();
o.bulkSet(data);
return performance.now() - startingTime;
};

let averageLogResult = [];
const wrapInHumanReadable = (value) => {
return {
totalLookupTime: roundToTwoDecimal(value.totalLookupTime) + " ms",
totalBulkLookupTime: roundToTwoDecimal(value.totalBulkLookupTime) + " ms",
totalInsertionTime: roundToTwoDecimal(value.totalInsertionTime) + " ms",
totalBulkInsertionTime:
roundToTwoDecimal(value.totalBulkInsertionTime) + " ms",
totalDeletionTime: roundToTwoDecimal(value.totalDeletionTime) + " ms",
totalBulkDeletionTime:
roundToTwoDecimal(value.totalBulkDeletionTime) + " ms",
};
};
const formatLogResult = (value) => {
return {
totalLookupTime: value.lookupDuration,
totalBulkLookupTime: value.bulkLookupDuration,
totalInsertionTime: value.insertionDuration,
totalBulkInsertionTime: value.bulkInsertionDuration,
totalDeletionTime: value.deletionDuration,
totalBulkDeletionTime: value.bulkDeletionDuration,
};
};
const logResults = (name, durationArr, averageArg) => {
Expand All @@ -101,11 +86,8 @@ const logResults = (name, durationArr, averageArg) => {
averageLogResult.push({
name,
totalLookupTime: average.totalLookupTime,
totalBulkLookupTime: average.totalBulkLookupTime,
totalInsertionTime: average.totalInsertionTime,
totalBulkInsertionTime: average.totalBulkInsertionTime,
totalDeletionTime: average.totalDeletionTime,
totalBulkDeletionTime: average.totalBulkDeletionTime,
});

console.log(`\n${name}:`);
Expand Down Expand Up @@ -135,21 +117,6 @@ const logRatio = () => {
averageLogResult[1].totalDeletionTime /
averageLogResult[0].totalDeletionTime
) + "x",
bulkLookup:
roundToTwoDecimal(
averageLogResult[1].totalBulkLookupTime /
averageLogResult[0].totalBulkLookupTime
) + "x",
bulkInsertion:
roundToTwoDecimal(
averageLogResult[1].totalBulkInsertionTime /
averageLogResult[0].totalBulkInsertionTime
) + "x",
bulkDeletion:
roundToTwoDecimal(
averageLogResult[1].totalBulkDeletionTime /
averageLogResult[0].totalBulkDeletionTime
) + "x",
});
};

Expand Down Expand Up @@ -182,49 +149,20 @@ const builtinMapBenchmark = () => {
name: "JsMap",
map: new Map(),
get: function (k) {
return this.map.get(k);
},
bulkGet: function (ks) {
const res = [];
for (const k of ks) {
res.push(this.map.get(k));
}
return res;
return this.map.get(k.toString());
},
set: function (k, v) {
return this.map.set(k, v);
},
bulkSet: function (data) {
const res = [];
for (const kv of data) {
res.push(this.map.set(kv.key, kv.value));
}
return res;
return this.map.set(k.toString(), v);
},
del: function (k) {
const v = this.map.get(k);
this.map.delete(k);
const v = this.map.get(k.toString());
this.map.delete(k.toString());
return v;
},
bulkDel: function (ks) {
const res = [];
for (const k of ks) {
res.push(this.map.get(k));
this.map.delete(k);
}
return res;
},
destroy: function () {
return this.map.clear();
},
};
const bulkInsertionDuration = benchmarkBulkInsertion(data, o);
const bulkLookupDuration = benchmarkBulkLookup(data, o);
const bulkDeletionDuration = benchmarkBulkDeletion(data, o);
o.destroy();

o.map = new Map();

const insertionDuration = benchmarkInsertion(data, o);
const lookupDuration = benchmarkLookup(data, o);
const deletionDuration = benchmarkDeletion(data, o);
Expand All @@ -234,31 +172,18 @@ const builtinMapBenchmark = () => {
insertionDuration,
lookupDuration,
deletionDuration,
bulkInsertionDuration,
bulkLookupDuration,
bulkDeletionDuration,
});
if (average.insertionDuration === 0) {
average = {
insertionDuration,
lookupDuration,
deletionDuration,
bulkInsertionDuration,
bulkInsertionDuration,
bulkLookupDuration,
bulkDeletionDuration,
};
} else {
average = {
insertionDuration: (average.insertionDuration + insertionDuration) / 2,
bulkInsertionDuration:
(average.bulkInsertionDuration + bulkInsertionDuration) / 2,
lookupDuration: (average.lookupDuration + lookupDuration) / 2,
bulkLookupDuration:
(average.bulkLookupDuration + bulkLookupDuration) / 2,
deletionDuration: (average.deletionDuration + deletionDuration) / 2,
bulkDeletionDuration:
(average.bulkDeletionDuration + bulkDeletionDuration) / 2,
};
}
}
Expand All @@ -278,32 +203,16 @@ const kiviBenchmark = () => {
get: function (k) {
return this.map.get(k);
},
bulkGet: function (ks) {
return this.map.bulkGet(ks);
},
set: function (k, v) {
return this.map.set(k, v);
},
bulkSet: function (data) {
return this.map.bulkSet(data);
},
del: function (k) {
return this.map.fetchDel(k);
},
bulkDel: function (ks) {
return this.map.bulkFetchDel(ks);
return this.map.del(k);
},
destroy: function () {
return this.map.destroy();
},
};
const bulkInsertionDuration = benchmarkBulkInsertion(data, o);
const bulkLookupDuration = benchmarkBulkLookup(data, o);
const bulkDeletionDuration = benchmarkBulkDeletion(data, o);
o.destroy();

o.map = new Kivi();

const insertionDuration = benchmarkInsertion(data, o);
const lookupDuration = benchmarkLookup(data, o);
const deletionDuration = benchmarkDeletion(data, o);
Expand All @@ -313,30 +222,18 @@ const kiviBenchmark = () => {
insertionDuration,
lookupDuration,
deletionDuration,
bulkInsertionDuration,
bulkLookupDuration,
bulkDeletionDuration,
});
if (average.insertionDuration === 0) {
average = {
insertionDuration,
lookupDuration,
deletionDuration,
bulkInsertionDuration,
bulkLookupDuration,
bulkDeletionDuration,
};
} else {
average = {
insertionDuration: (average.insertionDuration + insertionDuration) / 2,
bulkInsertionDuration:
(average.bulkInsertionDuration + bulkInsertionDuration) / 2,
lookupDuration: (average.lookupDuration + lookupDuration) / 2,
bulkLookupDuration:
(average.bulkLookupDuration + bulkLookupDuration) / 2,
deletionDuration: (average.deletionDuration + deletionDuration) / 2,
bulkDeletionDuration:
(average.bulkDeletionDuration + bulkDeletionDuration) / 2,
};
}
}
Expand Down
53 changes: 2 additions & 51 deletions src/drivers/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ export class Kivi {
this.#InnerKivi = new NodeKivi();
}

if (!this.#InnerKivi.init()) {
console.log(this.#InnerKivi.init());
throw new Error(`Failed to initialize a Kivi!`);
}
return this.#InnerKivi.init();
}
/**
* Releases the allocated memory and deinitializes Kivi.
Expand All @@ -72,15 +69,6 @@ export class Kivi {
get(key) {
return this.#InnerKivi.get(key);
}
/**
* Returns values of given keys.
* This function is noticeably faster when multiple data is given due to process in parallel.
* @param {string[]} keys
* @returns {(string|null)[]}
*/
bulkGet(keys) {
return this.#InnerKivi.bulkGet(keys);
}

/**
* Sets a key to the given value.
Expand All @@ -89,18 +77,7 @@ export class Kivi {
* @returns {boolean}
*/
set(key, value) {
if (!this.#InnerKivi.set(key, value)) {
throw new Error("Failed to insert!");
}
}
/**
* Sets values to given keys.
* This function is noticeably faster when multiple data is given due to process in parallel.
* @param {{key: string, value: string}[]} data
* @returns {boolean[]}
*/
bulkSet(data) {
return this.#InnerKivi.bulkSet(data);
return this.#InnerKivi.set(key, value);
}

/**
Expand All @@ -111,30 +88,4 @@ export class Kivi {
del(key) {
return this.#InnerKivi.del(key);
}
/**
* Removes a key with its value and returns the value.
* @param {string} key
* @returns {string}
*/
fetchDel(key) {
return this.#InnerKivi.fetchDel(key);
}
/**
* Removes keys with their values and returns the values.
* This function is noticeably faster when multiple data is given due to process in parallel.
* @param {string[]} keys
* @returns {string[]}
*/
bulkFetchDel(keys) {
return this.#InnerKivi.bulkFetchDel(keys);
}
/**
* Removes keys with their values.
* This function is noticeably faster when multiple data is given due to process in parallel.
* @param {string[]} keys
* @returns {void}
*/
bulkDel(keys) {
return this.#InnerKivi.bulkDel(keys);
}
}
Loading

0 comments on commit e26d7b8

Please sign in to comment.