Skip to content

Commit

Permalink
There is a problem with NAPI, pending to be solved on monday
Browse files Browse the repository at this point in the history
  • Loading branch information
miguelff committed Dec 15, 2023
1 parent 5b07aa2 commit 9d4b651
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 172 deletions.
2 changes: 1 addition & 1 deletion query-engine/driver-adapters/executor/script/bench.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/bench"
export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/bench?schema=imdb_bench&sslmode=disable"
node --experimental-wasm-modules "$(dirname "${BASH_SOURCE[0]}")"/../dist/bench.mjs < "$(dirname "${BASH_SOURCE[0]}")"/../bench/schema.prisma
63 changes: 32 additions & 31 deletions query-engine/driver-adapters/executor/src/bench.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ async function main(): Promise<void> {
}
const pg = await pgAdapter(url);
const { recorder, replayer } = recording(pg);

await recordQueries(recorder, datamodel, prismaQueries);
await benchMarkQueries(replayer, datamodel, prismaQueries);
}
Expand All @@ -48,49 +47,57 @@ async function recordQueries(
datamodel: string,
prismaQueries: any
): Promise<void> {
const qe = await initQeNapiCurrent(adapter, datamodel);
const qe = await initQeWasmBaseLine(adapter, datamodel);
await qe.connect("");

for (const prismaQuery of prismaQueries) {
const { description, query } = prismaQuery;
console.error("Recording query: " + description);
await qe.query(JSON.stringify(query), "", undefined);
}

await qe.disconnect("");
}

async function benchMarkQueries(
adapter: DriverAdapter,
datamodel: string,
prismaQueries: any
) {
const napi = await initQeNapiCurrent(adapter, datamodel);
napi.connect("");
// const napi = await initQeNapiCurrent(adapter, datamodel);
// await napi.connect("");
const wasmCurrent = await initQeWasmCurrent(adapter, datamodel);
wasmCurrent.connect("");
await wasmCurrent.connect("");
const wasmBaseline = await initQeWasmBaseLine(adapter, datamodel);
wasmBaseline.connect("");
await wasmBaseline.connect("");
const wasmLatest = await initQeWasmLatest(adapter, datamodel);
wasmLatest.connect("");
await wasmLatest.connect("");

try {
for (const prismaQuery of prismaQueries) {
const { description, query } = prismaQuery;
const jsonQuery = JSON.stringify(query);

var res = await wasmBaseline.query(jsonQuery, "", undefined);
res = await wasmLatest.query(jsonQuery, "", undefined);
res = await wasmCurrent.query(jsonQuery, "", undefined);

group(description, () => {
bench("Web Assembly: Baseline", () =>
wasmBaseline.query(jsonQuery, "", undefined)
bench(
"Web Assembly: Baseline",
async () => (res = await wasmBaseline.query(jsonQuery, "", undefined))
);

bench("Web Assembly: Latest", () =>
wasmLatest.query(jsonQuery, "", undefined)
bench(
"Web Assembly: Latest",
async () => (res = await wasmLatest.query(jsonQuery, "", undefined))
);

baseline("Web Assembly: Current", () =>
wasmCurrent.query(jsonQuery, "", undefined)
baseline(
"Web Assembly: Current",
async () => (res = await wasmCurrent.query(jsonQuery, "", undefined))
);

bench("Node API: Current", () => napi.query(jsonQuery, "", undefined));
// bench(
// "Node API: Current",
// async () => await napi.query(jsonQuery, "", undefined)
// );
});
}

Expand All @@ -99,10 +106,10 @@ async function benchMarkQueries(
collect: true,
});
} finally {
napi.disconnect("");
wasmCurrent.disconnect("");
wasmBaseline.disconnect("");
wasmLatest.disconnect("");
// await napi.disconnect("");
await wasmCurrent.disconnect("");
await wasmBaseline.disconnect("");
await wasmLatest.disconnect("");
}
}

Expand Down Expand Up @@ -134,13 +141,7 @@ async function initQeNapiCurrent(
adapter: DriverAdapter,
datamodel: string
): Promise<qe.QueryEngine> {
return await qe.initQueryEngine(
"Napi",
adapter,
datamodel,
(...args) => {},
debug
);
return await qe.initQueryEngine("Napi", adapter, datamodel, debug, debug);
}

async function initQeWasmCurrent(
Expand All @@ -160,14 +161,14 @@ async function initQeWasmLatest(
adapter: DriverAdapter,
datamodel: string
): Promise<qe.QueryEngine> {
return new WasmLatest(qe.queryEngineOptions(datamodel), () => {}, adapter);
return new WasmLatest(qe.queryEngineOptions(datamodel), debug, adapter);
}

function initQeWasmBaseLine(
adapter: DriverAdapter,
datamodel: string
): qe.QueryEngine {
return new WasmBaseline(qe.queryEngineOptions(datamodel), () => {}, adapter);
return new WasmBaseline(qe.queryEngineOptions(datamodel), debug, adapter);
}

const err = (...args: any[]) => console.error("[nodejs] ERROR:", ...args);
Expand Down
216 changes: 76 additions & 140 deletions query-engine/driver-adapters/executor/src/recording.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,162 +3,98 @@ import {
type Query,
type Result,
type ResultSet,
type Transaction,
} from "@prisma/driver-adapter-utils";
import { RetryHandler } from "undici";

export const recording = (adapter: DriverAdapter) => {
const recordings = new InMemoryRecordings();
export function recording(adapter: DriverAdapter) {
const recordings = createInMemoryRecordings();

return {
recorder: new Recorder(adapter, recordings),
replayer: new Replayer(adapter, recordings),
recorder: recorder(adapter, recordings),
replayer: replayer(adapter, recordings),
};
};

export interface Recordings {
addQueryResults(params: Query, result: Result<ResultSet>);
addCommandResults(params: Query, result: Result<number>);
getQueryResults(params: Query): Result<ResultSet>;
getCommandResults(params: Query): Result<number>;
}

export class InMemoryRecordings implements Recordings {
readonly queryResults: Record<string, Result<ResultSet>> = {};
readonly commandResults: Record<string, Result<number>> = {};

addQueryResults(params: Query, result: Result<ResultSet>) {
const key = this.queryToKey(params);
if (key in this.queryResults) {
throw new Error(`Query already recorded: ${key}`);
}
this.queryResults[key] = result;
}

getQueryResults(params: Query): Result<ResultSet> {
const key = this.queryToKey(params);
if (!(key in this.queryResults)) {
throw new Error(`Query not recorded: ${key}`);
}
return this.queryResults[key];
}

addCommandResults(params: Query, result: Result<number>) {
const key = this.queryToKey(params);
if (key in this.commandResults) {
throw new Error(`Command already recorded: ${key}`);
}
this.commandResults[key] = result;
}

getCommandResults(params: Query): Result<number> {
const key = this.queryToKey(params);
if (!(key in this.commandResults)) {
throw new Error(`Command not recorded: ${key}`);
}
return this.commandResults[key];
}

protected queryToKey(query: Query): string {
return JSON.stringify(query);
}
function recorder(adapter: DriverAdapter, recordings) {
return {
provider: adapter.provider,
startTransaction: () => {
throw new Error("Not implemented");
},
getConnectionInfo: () => {
return adapter.getConnectionInfo!();
},
queryRaw: (params) => {
return adapter.queryRaw(params).then((result) => {
recordings.addQueryResults(params, result);
return result;
});
},
executeRaw: (params) => {
return adapter.executeRaw(params).then((result) => {
recordings.addCommandResults(params, result);
return result;
});
},
};
}

export class Recorder implements DriverAdapter {
provider: "mysql" | "postgres" | "sqlite";
recordings: Recordings;
adapter: DriverAdapter;

constructor(adapter: DriverAdapter, recordings: Recordings) {
this.adapter = adapter;
this.provider = adapter.provider;
this.recordings = recordings;
}

startTransaction(): Promise<Result<Transaction>> {
throw new Error(
"Not implemented. We didn't need transactions for our use case until now."
);
}

get getConnectionInfo() {
if (this.adapter && typeof this.adapter.getConnectionInfo === "function") {
return () => this.adapter.getConnectionInfo!();
}
return undefined;
}

queryRaw(params: Query): Promise<Result<ResultSet>> {
return new Promise((resolve, reject) => {
this.adapter
.queryRaw(params)
.then((result) => {
this.recordings.addQueryResults(params, result);
resolve(result);
})
.catch((error) => {
reject(error);
});
});
}

executeRaw(params: Query): Promise<Result<number>> {
return new Promise((resolve, reject) => {
this.adapter
.executeRaw(params)
.then((result) => {
this.recordings.addCommandResults(params, result);
resolve(result);
})
.catch((error) => {
reject(error);
});
});
}
function replayer(adapter: DriverAdapter, recordings) {
return {
provider: adapter.provider,
recordings: recordings,
startTransaction: () => {
throw new Error("Not implemented");
},
getConnectionInfo: () => {
return adapter.getConnectionInfo!();
},
queryRaw: async (params) => {
return recordings.getQueryResults(params);
},
executeRaw: async (params) => {
return recordings.getCommandResults(params);
},
};
}

export class Replayer implements DriverAdapter {
provider: "mysql" | "postgres" | "sqlite";
recordings: Recordings;
adapter: DriverAdapter;
function createInMemoryRecordings() {
const queryResults = {};
const commandResults = {};

constructor(adapter: DriverAdapter, recordings: Recordings) {
this.adapter = adapter;
this.provider = adapter.provider;
this.recordings = recordings;
}
const queryToKey = (query) => JSON.stringify(query);

startTransaction(): Promise<Result<Transaction>> {
throw new Error(
"Not implemented. We didn't need transactions for our use case until now."
);
}
return {
addQueryResults: (params, result) => {
const key = queryToKey(params);
if (key in queryResults) {
throw new Error(`Query already recorded: ${key}`);
}
queryResults[key] = result;
},

get getConnectionInfo() {
if (this.adapter && typeof this.adapter.getConnectionInfo === "function") {
return () => this.adapter.getConnectionInfo!();
}
return undefined;
}
getQueryResults: (params) => {
const key = queryToKey(params);
if (!(key in queryResults)) {
throw new Error(`Query not recorded: ${key}`);
}
return queryResults[key];
},

queryRaw(params: Query): Promise<Result<ResultSet>> {
return new Promise((resolve, reject) => {
try {
const result = this.recordings.getQueryResults(params);
resolve(result);
} catch (error) {
reject(error);
addCommandResults: (params, result) => {
const key = queryToKey(params);
if (key in commandResults) {
throw new Error(`Command already recorded: ${key}`);
}
});
}
commandResults[key] = result;
},

executeRaw(params: Query): Promise<Result<number>> {
return new Promise((resolve, reject) => {
try {
const result = this.recordings.getCommandResults(params);
resolve(result);
} catch (error) {
reject(error);
getCommandResults: (params) => {
const key = queryToKey(params);
if (!(key in commandResults)) {
throw new Error(`Command not recorded: ${key}`);
}
});
}
return commandResults[key];
},
};
}

0 comments on commit 9d4b651

Please sign in to comment.