Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ type ArchiveStoreModules = {
metrics: Metrics | null;
};

type ArchiveStoreInitOpts = ArchiveStoreOpts & {dbName: string; anchorState: {finalizedCheckpoint: Checkpoint}};
type ArchiveStoreInitOpts = ArchiveStoreOpts & {
dbName: string;
dbType: "level" | "lmdb";
anchorState: {finalizedCheckpoint: Checkpoint};
};

/**
* Used for running tasks that depends on some events or are executed
Expand Down Expand Up @@ -110,6 +114,7 @@ export class ArchiveStore {
opts: {
genesisTime: this.chain.clock.genesisTime,
dbLocation: this.opts.dbName,
dbType: this.opts.dbType,
},
config: this.chain.config,
metrics: this.metrics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export class HistoricalStateRegen implements HistoricalStateWorkerApi {
maxConcurrency: 1,
maxLength: 50,
dbLocation: modules.opts.dbLocation,
dbType: modules.opts.dbType,
metricsEnabled: Boolean(modules.metrics),
loggerOpts: modules.logger.toOpts(),
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type HistoricalStateRegenInitModules = {
opts: {
genesisTime: number;
dbLocation: string;
dbType: "level" | "lmdb";
};
config: BeaconConfig;
logger: LoggerNode;
Expand All @@ -24,6 +25,7 @@ export type HistoricalStateWorkerData = {
maxConcurrency: number;
maxLength: number;
dbLocation: string;
dbType: "level" | "lmdb";
metricsEnabled: boolean;
loggerOpts: LoggerNodeOpts;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {PubkeyIndexMap} from "@chainsafe/pubkey-index-map";
import {Transfer, expose} from "@chainsafe/threads/worker";
import {chainConfigFromJson, createBeaconConfig} from "@lodestar/config";
import {LevelDbController} from "@lodestar/db/controller/level";
import {LmdbController} from "@lodestar/db/controller/lmdb";
import {getNodeLogger} from "@lodestar/logger/node";
import {BeaconDb} from "../../../db/index.js";
import {RegistryMetricCreator, collectNodeJSMetrics} from "../../../metrics/index.js";
Expand All @@ -26,7 +27,11 @@ logger.info("Historical state worker started");

const config = createBeaconConfig(chainConfigFromJson(workerData.chainConfigJson), workerData.genesisValidatorsRoot);

const db = new BeaconDb(config, await LevelDbController.create({name: workerData.dbLocation}, {logger}));
const controller =
workerData.dbType === "level"
? await LevelDbController.create({name: workerData.dbLocation}, {logger})
: await LmdbController.create({name: workerData.dbLocation}, {logger});
const db = new BeaconDb(config, controller);

const abortController = new AbortController();

Expand Down
4 changes: 3 additions & 1 deletion packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export class BeaconChain implements IBeaconChain {
config,
db,
dbName,
dbType,
dataDir,
logger,
processShutdownCallback,
Expand All @@ -218,6 +219,7 @@ export class BeaconChain implements IBeaconChain {
config: BeaconConfig;
db: IBeaconDb;
dbName: string;
dbType: "level" | "lmdb";
dataDir: string;
logger: Logger;
processShutdownCallback: ProcessShutdownCallback;
Expand Down Expand Up @@ -403,7 +405,7 @@ export class BeaconChain implements IBeaconChain {

this.archiveStore = new ArchiveStore(
{db, chain: this, logger: logger as LoggerNode, metrics},
{...opts, dbName, anchorState: {finalizedCheckpoint: anchorState.finalizedCheckpoint}},
{...opts, dbName, dbType, anchorState: {finalizedCheckpoint: anchorState.finalizedCheckpoint}},
signal
);

Expand Down
2 changes: 2 additions & 0 deletions packages/beacon-node/src/db/options.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
export type DatabaseOptions = {
name: string;
type: "level" | "lmdb";
};

export const defaultDbOptions: DatabaseOptions = {
name: "./.tmp/lodestar-db",
type: "level",
};
1 change: 1 addition & 0 deletions packages/beacon-node/src/node/nodejs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ export class BeaconNode {
dataDir,
db,
dbName: opts.db.name,
dbType: opts.db.type,
logger: logger.child({module: LoggerModule.chain}),
processShutdownCallback,
metrics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe("produceBlockBody", () => {
db,
dataDir: ".",
dbName: ".",
dbType: "level",
logger,
processShutdownCallback: () => {},
metrics: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ describe.skip("verify+import blocks - range sync perf test", () => {
db,
dataDir: ".",
dbName: ".",
dbType: "level",
logger,
processShutdownCallback: () => {},
metrics: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ const forkChoiceTest =
db: getMockedBeaconDb(),
dataDir: ".",
dbName: ",",
dbType: "level",
logger,
processShutdownCallback: () => {},
clock,
Expand Down
1 change: 1 addition & 0 deletions packages/beacon-node/test/utils/networkWithMockDb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export async function getNetworkForTest(
db,
dataDir: ".",
dbName: ".",
dbType: "level",
logger,
processShutdownCallback: () => {},
// set genesis time so that we are at ALTAIR_FORK_EPOCH
Expand Down
16 changes: 13 additions & 3 deletions packages/cli/src/cmds/beacon/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {hasher} from "@chainsafe/persistent-merkle-tree";
import {BeaconDb, BeaconNode} from "@lodestar/beacon-node";
import {ChainForkConfig, createBeaconConfig} from "@lodestar/config";
import {LevelDbController} from "@lodestar/db/controller/level";
import {LmdbController} from "@lodestar/db/controller/lmdb";
import {LoggerNode, getNodeLogger} from "@lodestar/logger/node";
import {ACTIVE_PRESET, PresetName} from "@lodestar/params";
import {ErrorAborted, bytesToInt} from "@lodestar/utils";
Expand Down Expand Up @@ -65,8 +66,17 @@ export async function beaconHandler(args: BeaconArgs & GlobalArgs): Promise<void

if (ACTIVE_PRESET === PresetName.minimal) logger.info("ACTIVE_PRESET == minimal preset");

const db = new BeaconDb(config, await LevelDbController.create(options.db, {metrics: null, logger}));
logger.info("Connected to LevelDB database", {path: options.db.name});
let controller: LevelDbController | LmdbController;
if (options.db.type === "level") {
controller = await LevelDbController.create(options.db, {metrics: null, logger});
logger.info("Connected to LevelDB database", {path: options.db.name});
} else if (options.db.type === "lmdb") {
controller = await LmdbController.create(options.db, {metrics: null, logger});
logger.info("Connected to LMDB database", {path: options.db.name});
} else {
throw new Error(`Unsupported db type: ${options.db.type}`);
}
Comment on lines 71 to 84
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That logic might go well as static method inside BeaconDb as BeaconDB.init. This will help us reuse it.

const db = new BeaconDb(config, controller);

// BeaconNode setup
try {
Expand Down Expand Up @@ -172,7 +182,7 @@ export async function beaconHandlerInit(args: BeaconArgs & GlobalArgs) {
const {version, commit} = getVersionData();
const beaconPaths = getBeaconPaths(args, network);
// TODO: Rename db.name to db.path or db.location
beaconNodeOptions.set({db: {name: beaconPaths.dbDir}});
beaconNodeOptions.set({db: {name: beaconPaths.dbDir, type: args.dbType}});
beaconNodeOptions.set({
chain: {
validatorMonitorLogs: args.validatorMonitorLogs,
Expand Down
9 changes: 9 additions & 0 deletions packages/cli/src/cmds/beacon/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type BeaconExtraArgs = {
ignoreWeakSubjectivityCheck?: boolean;
beaconDir?: string;
dbDir?: string;
dbType?: "level" | "lmdb";
persistInvalidSszObjectsDir?: string;
persistInvalidSszObjectsRetentionHours?: number;
persistOrphanedBlocksDir?: string;
Expand Down Expand Up @@ -98,6 +99,14 @@ export const beaconExtraOptions: CliCommandOptions<BeaconExtraArgs> = {
type: "string",
},

dbType: {
description: "Database backend type",
choices: ["level", "lmdb"],
default: "level",
hidden: true,
type: "string",
},

persistInvalidSszObjectsDir: {
description: "Enable and specify a directory to persist invalid ssz objects",
defaultDescription: defaultBeaconPaths.persistInvalidSszObjectsDir,
Expand Down
4 changes: 4 additions & 0 deletions packages/db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
"./controller/level": {
"bun": "./src/controller/level_bun.ts",
"import": "./lib/controller/level.js"
},
"./controller/lmdb": {
"bun": "./src/controller/lmdb_bun.ts",
"import": "./lib/controller/lmdb.js"
}
},
"imports": {
Expand Down
68 changes: 68 additions & 0 deletions packages/db/src/controller/lmdb.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {Logger} from "@lodestar/utils";
import {DatabaseController, DatabaseOptions, DbReqOpts, FilterOptions, KeyValue} from "./interface.ts";
import {LevelDbControllerMetrics} from "./metrics.ts";

export type LmdbControllerModules = {
logger: Logger;
metrics?: LevelDbControllerMetrics | null;
};

export class LmdbController implements DatabaseController<Uint8Array, Uint8Array> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code must be covered with unit tests. May be using same fixture to test different implementations of db controllers.

It is important as if something missed goes wrong here make it very difficult to debug on higher layers.

static async create(options: DatabaseOptions, {metrics}: LmdbControllerModules): Promise<LmdbController> {
return new LmdbController();
}
static async destroy(_location: string): Promise<void> {}
close(): Promise<void> {
throw new Error("Method not implemented.");
}
setMetrics(metrics: LevelDbControllerMetrics): void {
throw new Error("Method not implemented.");
}
get(key: Uint8Array<ArrayBufferLike>, opts?: DbReqOpts): Promise<Uint8Array<ArrayBufferLike> | null> {
throw new Error("Method not implemented.");
}
getMany(key: Uint8Array<ArrayBufferLike>[], opts?: DbReqOpts): Promise<(Uint8Array<ArrayBufferLike> | undefined)[]> {
throw new Error("Method not implemented.");
}
put(key: Uint8Array<ArrayBufferLike>, value: Uint8Array<ArrayBufferLike>, opts?: DbReqOpts): Promise<void> {
throw new Error("Method not implemented.");
}
delete(key: Uint8Array<ArrayBufferLike>, opts?: DbReqOpts): Promise<void> {
throw new Error("Method not implemented.");
}
batchPut(
items: KeyValue<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>[],
opts?: DbReqOpts
): Promise<void> {
throw new Error("Method not implemented.");
}
batchDelete(keys: Uint8Array<ArrayBufferLike>[], opts?: DbReqOpts): Promise<void> {
throw new Error("Method not implemented.");
}
keysStream(
opts?: FilterOptions<Uint8Array<ArrayBufferLike>> | undefined
): AsyncIterable<Uint8Array<ArrayBufferLike>> {
throw new Error("Method not implemented.");
}
keys(opts?: FilterOptions<Uint8Array<ArrayBufferLike>> | undefined): Promise<Uint8Array<ArrayBufferLike>[]> {
throw new Error("Method not implemented.");
}
valuesStream(
opts?: FilterOptions<Uint8Array<ArrayBufferLike>> | undefined
): AsyncIterable<Uint8Array<ArrayBufferLike>> {
throw new Error("Method not implemented.");
}
values(opts?: FilterOptions<Uint8Array<ArrayBufferLike>> | undefined): Promise<Uint8Array<ArrayBufferLike>[]> {
throw new Error("Method not implemented.");
}
entriesStream(
opts?: FilterOptions<Uint8Array<ArrayBufferLike>> | undefined
): AsyncIterable<KeyValue<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>> {
throw new Error("Method not implemented.");
}
entries(
opts?: FilterOptions<Uint8Array<ArrayBufferLike>> | undefined
): Promise<KeyValue<Uint8Array<ArrayBufferLike>, Uint8Array<ArrayBufferLike>>[]> {
throw new Error("Method not implemented.");
}
}
Loading
Loading