Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Snapshot Isolation OCC to DBTransaction #19

Merged
merged 25 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
946a01e
Preparing for native leveldb build
CMCDragonkai May 31, 2022
a972390
Added leveldb native dependencies
CMCDragonkai May 31, 2022
e7229bf
Direct to C++ leveldb works
CMCDragonkai Jun 7, 2022
da767cc
Switching over to rocksdb
CMCDragonkai Jun 10, 2022
e42f01e
Removed StringOrBufferLength check from rocksdb.cpp
CMCDragonkai Jun 8, 2022
dc4db39
Modularized rocksdb.cpp into a rocksdb/napi directory
CMCDragonkai Jun 8, 2022
ba968b0
Added `infoLogLevel` to `RocksDBDatabaseOptions`
CMCDragonkai Jun 10, 2022
f521ab0
Added in basic `transaction_*` methods, and modularised `src/rocksdb/…
CMCDragonkai Jun 10, 2022
92edd7f
Native addon exported functions now match naming convention standard …
CMCDragonkai Jun 10, 2022
7b55563
Fixed Transaction* workers in C++ to instantiate the `Transaction`
CMCDragonkai Jun 10, 2022
6862983
Lint fixing native C/C++ code
CMCDragonkai Jun 11, 2022
dd1cec1
Tested write-skew anomaly and solved with transactionGetForUpdate
CMCDragonkai Jun 11, 2022
8e1135c
First class snapshots
CMCDragonkai Jun 11, 2022
0dc0b96
Transactions support iterators and refactoring C++ object lifecycle
CMCDragonkai Jun 14, 2022
c909c02
GC finalizers may run after `env_cleanup_hook`, so `Detach` methods can
CMCDragonkai Jun 17, 2022
04c5448
Fix database->isClosing_ and Transaction::DecrementPendingWork should…
CMCDragonkai Jun 17, 2022
434ef4a
Testing iterator consistency
CMCDragonkai Jun 17, 2022
23d3405
Adding transactionClear
CMCDragonkai Jun 17, 2022
f9cecbc
Adding transactionMultiGet and transactionMultiGetForUpdate
CMCDragonkai Jun 18, 2022
b8a6083
Re-enabled DBTransaction and integrated it with rocksdb's optimistic …
CMCDragonkai Jun 7, 2022
58a62f2
Added DBTransaction.getForUpdate to address write skew, and added tes…
CMCDragonkai Jun 26, 2022
a06ccdf
Introducing PCC locking for `DBTransaction`
CMCDragonkai Jun 27, 2022
cb25e1f
Export `RocksDB` and `RocksDBP` interfaces
CMCDragonkai Jun 30, 2022
567526b
Updated docs
CMCDragonkai Jun 30, 2022
879c5e2
Updated benchmarks
CMCDragonkai Jun 30, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
BasedOnStyle: Google
SortIncludes: false
9 changes: 9 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
"ignoreConsecutiveComments": true
}
],
"curly": [
"error",
"multi-line",
"consistent"
],
"import/order": [
"error",
{
Expand Down Expand Up @@ -137,6 +142,10 @@
"format": ["PascalCase"],
"trailingUnderscore": "allowSingleOrDouble"
},
{
"selector": "enumMember",
"format": ["PascalCase", "UPPER_CASE"]
},
{
"selector": "objectLiteralProperty",
"format": null
Expand Down
60 changes: 54 additions & 6 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ check:test:
- >
nix-shell --run '
npm run build --verbose;
npm test -- --ci;
npm test -- --ci --coverage;
'
artifacts:
when: always
reports:
junit:
- ./tmp/junit.xml
- ./tmp/junit/junit.xml
coverage_report:
coverage_format: cobertura
path: ./tmp/coverage/cobertura-coverage.xml
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
rules:
# Runs on staging commits and ignores version commits
- if: $CI_COMMIT_BRANCH =~ /^feature.*$/ && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/
Expand Down Expand Up @@ -114,17 +118,21 @@ build:linux:
- >
nix-shell --run '
npm run build --verbose;
npm test -- --ci;
npm test -- --ci --coverage;
'
artifacts:
when: always
reports:
junit:
- ./tmp/junit.xml
- ./tmp/junit/junit.xml
coverage_report:
coverage_format: cobertura
path: ./tmp/coverage/cobertura-coverage.xml
paths:
- ./prebuilds/
# Only the build:linux preserves the dist
- ./dist
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
rules:
# Runs on staging commits and ignores version commits
- if: $CI_COMMIT_BRANCH == 'staging' && $CI_COMMIT_TITLE !~ /^[0-9]+\.[0-9]+\.[0-9]+(?:-.*[0-9]+)?$/
Expand All @@ -150,7 +158,7 @@ build:windows:
when: always
reports:
junit:
- ./tmp/junit.xml
- ./tmp/junit/junit.xml
paths:
- ./prebuilds/
rules:
Expand All @@ -169,6 +177,7 @@ build:macos:
HOMEBREW_NO_INSTALL_UPGRADE: "true"
HOMEBREW_NO_INSTALL_CLEANUP: "true"
before_script:
- eval "$(brew shellenv)"
- brew install node@16
- brew link --overwrite node@16
- brew install python@3.9
Expand All @@ -184,7 +193,7 @@ build:macos:
when: always
reports:
junit:
- ./tmp/junit.xml
- ./tmp/junit/junit.xml
paths:
- ./prebuilds/
rules:
Expand All @@ -209,6 +218,26 @@ build:prerelease:
nix-shell --run '
npm publish --tag prerelease --access public;
'
- >
for d in prebuilds/*; do
tar \
--create \
--verbose \
--file="prebuilds/$(basename $d).tar" \
--directory=prebuilds \
"$(basename $d)";
done
- >
nix-shell -I nixpkgs=./pkgs.nix --packages gitAndTools.gh --run '
gh release \
create "$CI_COMMIT_TAG" \
prebuilds/*.tar \
--title "${CI_COMMIT_TAG}-$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--notes "" \
--prerelease \
--target staging \
--repo "$GH_PROJECT_PATH";
'
after_script:
- rm -f ./.npmrc
rules:
Expand Down Expand Up @@ -272,6 +301,25 @@ release:distribution:
nix-shell --run '
npm publish --access public;
'
- >
for d in prebuilds/*; do
tar \
--create \
--verbose \
--file="prebuilds/$(basename $d).tar" \
--directory=prebuilds \
"$(basename $d)";
done
- >
nix-shell -I nixpkgs=./pkgs.nix --packages gitAndTools.gh --run '
gh release \
create "$CI_COMMIT_TAG" \
prebuilds/*.tar \
--title "${CI_COMMIT_TAG}-$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
--notes "" \
--target master \
--repo "$GH_PROJECT_PATH";
'
after_script:
- rm -f ./.npmrc
rules:
Expand Down
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[submodule "deps/snappy/snappy"]
path = deps/snappy/snappy
url = https://github.com/google/snappy.git
[submodule "deps/rocksdb/rocksdb"]
path = deps/rocksdb/rocksdb
url = https://github.com/facebook/rocksdb.git
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,76 @@ master: [![pipeline status](https://gitlab.com/MatrixAI/open-source/js-db/badges

DB is library managing key value state for MatrixAI's JavaScript/TypeScript applications.

This forks classic-level's C++ binding code around LevelDB 1.20. Differences from classic-level:

* Uses TypeScript from ground-up
* Supports Snapshot-Isolation based transactions via `DBTransaction`
* API supports "key paths" which can be used to manipulate "levels" of nested keys
* Value encryption (key-encryption is not supported yet) - requires additional work with block-encryption

## Installation

```sh
npm install --save @matrixai/db
```

## Usage


```ts
import { DB } from '@matrixai/db';

async function main () {

const key = Buffer.from([
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03,
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03,
]);

const encrypt = async (
key: ArrayBuffer,
plainText: ArrayBuffer
): Promise<ArrayBuffer> {
return plainText;
};

const decrypt = async (
key: ArrayBuffer,
cipherText: ArrayBuffer
): Promise<ArrayBuffer | undefined> {
return cipherText;
}

const db = await DB.createDB({
dbPath: './tmp/db',
crypto: {
key,
ops: { encrypt, decrypt },
},
fresh: true,
});

await db.put(['level', Buffer.from([0x30, 0x30]), 'a'], 'value');
await db.put(['level', Buffer.from([0x30, 0x31]), 'b'], 'value');
await db.put(['level', Buffer.from([0x30, 0x32]), 'c'], 'value');
await db.put(['level', Buffer.from([0x30, 0x33]), 'c'], 'value');

console.log(await db.get(['level', Buffer.from([0x30, 0x32]), 'c']));

await db.del(['level', Buffer.from([0x30, 0x32]), 'c']);

for await (const [kP, v] of db.iterator({
lt: [Buffer.from([0x30, 0x32]), ''],
}, ['level'])) {
console.log(kP, v);
}

await db.stop();
}

main();
```

## Development

Run `nix-shell`, and once you're inside, you can use:
Expand Down
4 changes: 1 addition & 3 deletions benches/DB1KiB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ async function main() {
}

if (require.main === module) {
(async () => {
await main();
})();
void main();
}

export default main;
10 changes: 4 additions & 6 deletions benches/DB1MiB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ async function main() {
const summary = await b.suite(
'DB1MiB',
b.add('get 1 MiB of data', async () => {
await db.put('1kib', data1MiB, true);
await db.put('1mib', data1MiB, true);
return async () => {
await db.get('1kib', true);
await db.get('1mib', true);
};
}),
b.add('put 1 MiB of data', async () => {
await db.put('1kib', data1MiB, true);
await db.put('1mib', data1MiB, true);
}),
b.add('put zero data', async () => {
await db.put('0', data0, true);
Expand Down Expand Up @@ -58,9 +58,7 @@ async function main() {
}

if (require.main === module) {
(async () => {
await main();
})();
void main();
}

export default main;
4 changes: 1 addition & 3 deletions benches/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ async function main(): Promise<void> {
}

if (require.main === module) {
(async () => {
await main();
})();
void main();
}

export default main;
10 changes: 5 additions & 5 deletions benches/results/DB1KiB.chart.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</head>
<body>
<div style="max-width: 800px">
<canvas id="chart1654000546839" width="16" height="9"></canvas>
<canvas id="chart1656585967881" width="16" height="9"></canvas>
</div>
<script>
const format = (num) => {
Expand All @@ -34,10 +34,10 @@

return chunked.map((chunk) => chunk.join("")).join(" ");
};
const ctx1654000546839 = document
.getElementById("chart1654000546839")
const ctx1656585967881 = document
.getElementById("chart1656585967881")
.getContext("2d");
const chart1654000546839 = new Chart(ctx1654000546839, {
const chart1656585967881 = new Chart(ctx1656585967881, {
type: "bar",
data: {
labels: [
Expand All @@ -48,7 +48,7 @@
],
datasets: [
{
data: [55227, 28769, 33029, 16935],
data: [43375, 24504, 27503, 13785],
backgroundColor: [
"rgba(63, 142, 252, 0.8)",
"rgba(116, 165, 127, 0.8)",
Expand Down
Loading