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 #18

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 1 deletion docs/assets/search.js

Large diffs are not rendered by default.

19 changes: 10 additions & 9 deletions docs/classes/DB.html

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions docs/classes/DBTransaction.html

Large diffs are not rendered by default.

11 changes: 8 additions & 3 deletions docs/classes/errors.ErrorDB.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBCreate.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBDecrypt.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBDelete.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBDestroyed.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBKey.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBNotRunning.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBParseKey.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBParseValue.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBRunning.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBTransactionCommitted.html

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBTransactionDestroyed.html

Large diffs are not rendered by default.

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions docs/classes/errors.ErrorDBTransactionRollbacked.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/modules.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/modules/errors.html

Large diffs are not rendered by default.

4,774 changes: 2,039 additions & 2,735 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
},
"dependencies": {
"@matrixai/async-init": "^1.7.3",
"@matrixai/async-locks": "^2.2.0",
"@matrixai/errors": "^1.1.1",
"@matrixai/logger": "^2.1.1",
"@matrixai/resources": "^1.1.3",
Expand All @@ -34,6 +35,7 @@
"@types/jest": "^27.0.2",
"@types/level": "^6.0.0",
"@types/node": "^16.11.7",
"@types/node-forge": "^0.10.4",
"@typescript-eslint/eslint-plugin": "^5.23.0",
"@typescript-eslint/parser": "^5.23.0",
"benny": "^3.6.15",
Expand Down
158 changes: 125 additions & 33 deletions src/DB.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class DB {
crypto?: {
key: Buffer;
ops: Crypto;
canary?: Buffer;
};
fs?: FileSystem;
logger?: Logger;
Expand Down Expand Up @@ -160,11 +159,16 @@ class DB {
public transaction(): ResourceAcquire<DBTransaction> {
return async () => {
const transactionId = this.transactionCounter++;
const tran = await DBTransaction.createTransaction({
const tran = new DBTransaction({
db: this,
transactionId,
logger: this.logger,
});
// const tran = await DBTransaction.createTransaction({
// db: this,
// transactionId,
// logger: this.logger,
// });
return [
async (e?: Error) => {
try {
Expand Down Expand Up @@ -216,7 +220,7 @@ class DB {
public async get<T>(
keyPath: KeyPath | string | Buffer,
raw: boolean = false,
): Promise<T | undefined> {
): Promise<T | Buffer | undefined> {
if (!Array.isArray(keyPath)) {
keyPath = [keyPath] as KeyPath;
}
Expand Down Expand Up @@ -400,22 +404,57 @@ class DB {
levelPath?: LevelPath,
): DBIterator<undefined, undefined>;
public iterator(
options: AbstractIteratorOptions & { keys: false },
options: AbstractIteratorOptions & { values: false; keyAsBuffer?: true },
levelPath?: LevelPath,
): DBIterator<undefined, Buffer>;
): DBIterator<Buffer, undefined>;
public iterator(
options: AbstractIteratorOptions & { values: false },
options: AbstractIteratorOptions & { values: false; keyAsBuffer: false },
levelPath?: LevelPath,
): DBIterator<Buffer, undefined>;
): DBIterator<string, undefined>;
public iterator(
options?: AbstractIteratorOptions,
options: AbstractIteratorOptions & { keys: false; valueAsBuffer?: true },
levelPath?: LevelPath,
): DBIterator<undefined, Buffer>;
public iterator<V>(
options: AbstractIteratorOptions & { keys: false; valueAsBuffer: false },
levelPath?: LevelPath,
): DBIterator<undefined, V>;
public iterator(
options?: AbstractIteratorOptions & {
keyAsBuffer?: true;
valueAsBuffer?: true;
},
levelPath?: LevelPath,
): DBIterator<Buffer, Buffer>;
@ready(new errors.ErrorDBNotRunning())
public iterator(
options?: AbstractIteratorOptions,
options?: AbstractIteratorOptions & {
keyAsBuffer: false;
valueAsBuffer?: true;
},
levelPath?: LevelPath,
): DBIterator<string, Buffer>;
public iterator<V>(
options?: AbstractIteratorOptions & {
keyAsBuffer?: true;
valueAsBuffer: false;
},
levelPath?: LevelPath,
): DBIterator<Buffer, V>;
public iterator<V>(
options?: AbstractIteratorOptions & {
keyAsBuffer: false;
valueAsBuffer: false;
},
levelPath?: LevelPath,
): DBIterator<string, V>;
@ready(new errors.ErrorDBNotRunning())
public iterator<V>(
options?: AbstractIteratorOptions & {
keyAsBuffer?: any;
valueAsBuffer?: any;
},
levelPath: LevelPath = [],
): DBIterator {
): DBIterator<Buffer | string | undefined, Buffer | V | undefined> {
levelPath = ['data', ...levelPath];
return this._iterator(options, levelPath);
}
Expand All @@ -432,29 +471,76 @@ class DB {
* @internal
*/
public _iterator(
options: AbstractIteratorOptions & { keys: false },
options: AbstractIteratorOptions & { values: false; keyAsBuffer?: true },
levelPath?: LevelPath,
): DBIterator<undefined, Buffer>;
): DBIterator<Buffer, undefined>;
/**
* @internal
*/
public _iterator(
options: AbstractIteratorOptions & { values: false },
options: AbstractIteratorOptions & { values: false; keyAsBuffer: false },
levelPath?: LevelPath,
): DBIterator<Buffer, undefined>;
): DBIterator<string, undefined>;
/**
* @internal
*/
public _iterator(
options?: AbstractIteratorOptions,
options: AbstractIteratorOptions & { keys: false; valueAsBuffer?: true },
levelPath?: LevelPath,
): DBIterator<undefined, Buffer>;
/**
* @internal
*/
public _iterator<V>(
options: AbstractIteratorOptions & { keys: false; valueAsBuffer: false },
levelPath?: LevelPath,
): DBIterator<undefined, V>;
/**
* @internal
*/
public _iterator(
options?: AbstractIteratorOptions & {
keyAsBuffer?: true;
valueAsBuffer?: true;
},
levelPath?: LevelPath,
): DBIterator<Buffer, Buffer>;
/**
* @internal
*/
public _iterator(
options?: AbstractIteratorOptions & {
keyAsBuffer: false;
valueAsBuffer?: true;
},
levelPath?: LevelPath,
): DBIterator<string, Buffer>;
/**
* @internal
*/
public _iterator<V>(
options?: AbstractIteratorOptions & {
keyAsBuffer?: true;
valueAsBuffer: false;
},
levelPath?: LevelPath,
): DBIterator<Buffer, V>;
/**
* @internal
*/
public _iterator<V>(
options?: AbstractIteratorOptions & {
keyAsBuffer: false;
valueAsBuffer: false;
},
levelPath?: LevelPath,
): DBIterator<string, V>;
public _iterator(
options?: AbstractIteratorOptions,
levelPath: LevelPath = [],
): DBIterator {
options = options ?? {};
): DBIterator<any, any> {
const levelKeyStart = utils.levelPathToKey(levelPath);
options = options ?? {};
if (options.gt != null) {
options.gt = Buffer.concat([
levelKeyStart,
Expand Down Expand Up @@ -508,15 +594,22 @@ class DB {
// Truncate level path so the returned key is relative to the level path
const keyPath = utils.parseKey(kv[0]).slice(levelPath.length);
kv[0] = utils.keyPathToKey(keyPath);
if (options?.keyAsBuffer === false) {
kv[0] = kv[0].toString('utf-8');
}
}
// Handle values: false
if (kv[1] != null) {
kv[1] = await this.deserializeDecrypt(kv[1], true);
if (options?.valueAsBuffer === false) {
kv[1] = await this.deserializeDecrypt(kv[1], false);
} else {
kv[1] = await this.deserializeDecrypt(kv[1], true);
}
}
}
return kv;
};
return iterator as unknown as DBIterator;
return iterator as unknown as DBIterator<any, any>;
}

/**
Expand Down Expand Up @@ -549,13 +642,14 @@ class DB {
}

/**
* Dump from root level
* Dump from root level path
* This will show entries from all levels
* It is intended for diagnostics
*/
public async dump(
public async dump<V>(
levelPath?: LevelPath,
raw?: false,
): Promise<Array<[string, any]>>;
): Promise<Array<[string, V]>>;
public async dump(
levelPath: LevelPath | undefined,
raw: true,
Expand All @@ -566,16 +660,14 @@ class DB {
raw: boolean = false,
): Promise<Array<[string | Buffer, any]>> {
const records: Array<[string | Buffer, any]> = [];
for await (const [k, v] of this._iterator(undefined, levelPath)) {
let key: string | Buffer, value: any;
if (raw) {
key = k;
value = v;
} else {
key = k.toString('utf-8');
value = utils.deserialize(v);
}
records.push([key, value]);
for await (const [k, v] of this._iterator(
{
keyAsBuffer: raw as any,
valueAsBuffer: raw as any,
},
levelPath,
)) {
records.push([k, v]);
}
return records;
}
Expand Down
Loading