benchmarks/latency-comparison/nodejs/src/spanner_benchmark_runner.ts (85 lines of code) (raw):
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import {Config, generate_random_string} from "./index";
import {Database, Spanner} from "@google-cloud/spanner";
import {Json} from "@google-cloud/spanner/build/src/codec";
import {randomInt} from "crypto";
let totalOperations: number;
let progress: number;
let numNull: number;
let numNotNull: number;
export async function runBenchmark(config: Config): Promise<number[][]> {
progress = 0;
numNull = 0;
numNotNull = 0;
totalOperations = config.numClients * config.numOperations;
const progressPrinter = setInterval(printProgress, 1000);
const databaseNameParts = config.database.split('/');
const projectId = databaseNameParts[1];
const instanceId = databaseNameParts[3];
const databaseId = databaseNameParts[5];
const spanner = new Spanner({projectId: projectId});
const instance = spanner.instance(instanceId);
const database = instance.database(databaseId);
const promises: Promise<number[]>[] = [];
for (let i=0; i<config.numClients; i++) {
promises.push(run(database, config));
}
const results = await Promise.all(promises);
// Close the connection.
spanner.close();
clearInterval(progressPrinter);
printProgress();
return results;
}
async function run(database: Database, config: Config): Promise<number[]> {
const results: number[] = [];
for (let i= 0; i < config.numOperations; i++) {
const start = performance.now();
const id: number = getRandomInt(100000);
if (config.readWrite) {
await executeUpdate(database, config, id);
} else {
await executeQuery(database, config, id);
}
progress++;
const elapsed = performance.now() - start;
results.push(elapsed);
if (config.wait > 0) {
const t = randomInt(0, 2 * config.wait);
await new Promise(f => setTimeout(f, t));
}
}
return results;
}
async function executeQuery(database: Database, config: Config, id: number) {
const [rows] = await database.run({
sql: config.sql,
params: {p1: `${id}`},
types: {p1: {type: 'int64'}},
json: true,
});
for (const row of rows) {
if ((row as Json).col_varchar) {
numNotNull++;
} else {
numNull++;
}
}
}
async function executeUpdate(database: Database, config: Config, id: number) {
await database.runTransactionAsync(transaction => {
return transaction.runUpdate({
sql: config.sql,
params: {p1: generate_random_string(64), p2: `${id}`},
types: {p1: {type: 'string'}, p2: {type: 'int64'}},
});
});
}
function printProgress() {
if (process.stdout.clearLine) {
process.stdout.clearLine(0);
process.stdout.cursorTo(0);
}
process.stdout.write(`${progress}/${totalOperations}`);
}
function getRandomInt(max: number) {
return Math.floor(Math.random() * max);
}