Skip to content
Draft
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
gorm/
.idea
.DS_Store
node_modules
build/
package-lock.json
googleapis/
2 changes: 2 additions & 0 deletions spannerlib/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ vendor/bundle
*.swp
ext/
Gemfile.lock
/googleapis/
package-lock.json
31 changes: 25 additions & 6 deletions spannerlib/grpc-server/build-protos.sh
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
#!/bin/bash

PATH="${PATH}:${HOME}/go/bin"
git submodule add git@github.com:googleapis/googleapis.git
ln -sf "${PWD}"/google/spannerlib googleapis/google/spannerlib

# 1. Clean up and fetch dependencies
# We DO NOT delete googleapis at the end because Node.js needs it at runtime
if [ ! -d "googleapis" ]; then
echo "Fetching dependency protos..."
git clone --depth 1 https://github.com/googleapis/googleapis.git
fi

# Link local proto into the structure
mkdir -p googleapis/google/spannerlib/v1
ln -sf "${PWD}/google/spannerlib/v1/spannerlib.proto" "googleapis/google/spannerlib/v1/spannerlib.proto"

cd googleapis || exit 1

# 2. Go generation
echo "Generating Go..."
protoc \
--go_out=../ \
--go_opt=paths=source_relative \
--go-grpc_out=../ \
--go-grpc_opt=paths=source_relative \
google/spannerlib/v1/spannerlib.proto

# 3. Java generation
echo "Generating Java..."
protoc \
--java_out=../../wrappers/spannerlib-java/src/main/java/ \
--plugin=protoc-gen-java-grpc=/Users/loite/protoc-gen-grpc-java-1.75.0-osx-aarch_64.exe \
--java-grpc_out=../../wrappers/spannerlib-java/src/main/java/ \
--java-grpc_opt=paths=source_relative \
google/spannerlib/v1/spannerlib.proto

# dotnet add package Grpc.Tools --version 2.76.0
# 4. C# generation
echo "Generating C#..."
protoc \
--csharp_out=../../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/ \
--plugin=protoc-gen-csharp_grpc=/Users/loite/.nuget/packages/grpc.tools/2.76.0/tools/macosx_x64/grpc_csharp_plugin \
Comment on lines 31 to 40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

critical

The script contains hardcoded paths to protoc plugins, which makes it non-portable and specific to a single user's machine (/Users/loite/...). This will cause the script to fail for other developers or in CI/CD environments.

To improve this, consider one of the following approaches:

  1. Rely on PATH: Require developers to have the protoc-gen-* executables in their PATH.
  2. Use Environment Variables: Allow developers to specify the path to the plugins via environment variables.
  3. Local Installation: Add a step to download and install the required plugins locally within the project or use a package manager that handles this.

Expand All @@ -24,7 +43,7 @@ protoc \
--csharp_grpc_opt=no_server \
--proto_path=. \
google/spannerlib/v1/spannerlib.proto

cd .. || exit 1
rm googleapis/google/spannerlib
git rm googleapis -f
rm ../../.gitmodules
echo "Code generation complete for Go, Java, and C#."
echo "Node.js will use dynamic loading via @grpc/proto-loader."
79 changes: 79 additions & 0 deletions spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Spanner Node.js Wrappers Benchmark

This directory contains a benchmark suite to compare the performance, throughput, and memory usage of three different Node.js wrappers for the Spanner Shared C-Library:
1. **Koffi** (Fast FFI)
2. **N-API** (Native C++ Addon)
3. **IPC** (gRPC Server/Client)

## Prerequisites
Ensure you have the following installed on the machine:
* **Node.js** (v22 recommended)
* **Go** (v1.22 recommended)
* **Build Tools** (`gcc`, `g++`, `make`)

---

## Setup Instructions

### 1. Fetch Google API Protos (For IPC)
The IPC wrapper depends on standard Google API protos. You can fetch them by running the build script in the `grpc-server` directory:

```bash
cd spannerlib/grpc-server
./build-protos.sh
```
*(Note: This script also attempts to generate Go code using `protoc`. If you do not have `protoc` installed, it may show an error on the generation step, but it will still have successfully cloned the `googleapis` folder that Node.js needs).*

### 2. Build the Go Shared Library
Navigate to the shared library directory and build the `.so` file:
```bash
cd spannerlib/shared
go build -o libspanner.so -buildmode=c-shared shared_lib.go
```

### 3. Install Dependencies for Wrappers
Navigate to each wrapper directory and install its specific dependencies:

**Koffi:**
```bash
cd spannerlib/wrappers/spannerlib-nodejs-poc/koffi
npm install
```

**N-API:**
```bash
cd spannerlib/wrappers/spannerlib-nodejs-poc/napi
npm install # This will also automatically build the C++ addon
```

**IPC:**
```bash
cd spannerlib/wrappers/spannerlib-nodejs-poc/ipc
npm install
```

### 4. Start the gRPC Server (Required for IPC)
The IPC wrapper requires the Go gRPC server to be running.
Navigate to `spannerlib/grpc-server` and run it in the background (or in a `tmux` session):
```bash
cd spannerlib/grpc-server
nohup go run server.go localhost:50051 tcp > server.log 2>&1 &
```

---

## Running the Benchmark

Once all setups are complete, navigate to this directory:

```bash
cd spannerlib/wrappers/spannerlib-nodejs-poc/benchmark
npm install
node --expose-gc benchmark.js
```

## Results
The script will generate a `RESULTS.md` file in this directory containing:
* Latency statistics from `mitata`.
* Throughput (ops/sec) and Heap memory delta for 5 runs of each wrapper.
* A 1-minute cooldown sleep is automatically applied between wrappers to ensure DB cooling and isolation.
65 changes: 65 additions & 0 deletions spannerlib/wrappers/spannerlib-nodejs-poc/benchmark/RESULTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Benchmark Results

## Environment
- **Database**: `projects/span-cloud-testing/instances/gargsurbhi-testing/databases/test-db-koffi-136`

**Action Benchmarked**: A Single Point Read operation involving executing a SQL query (`SELECT ... WHERE SingerId = 1`), reading the first result row, and closing the result stream.

## Mitata Latency Benchmark

**cpu: Intel(R) Xeon(R) CPU @ 2.80GHz**
**runtime: node v22.22.2 (x64-linux)**

| Wrapper | Time (Avg) | Min … Max | p75 | p99 | p999 |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **Koffi** | 4'554 µs/iter | 2'985 µs … 6'313 µs | 5'295 µs | 6'288 µs | 6'313 µs |
| **N-API** | 4'608 µs/iter | 2'689 µs … 6'519 µs | 5'122 µs | 6'132 µs | 6'519 µs |
| **IPC** | 7'090 µs/iter | 4'831 µs … 11'449 µs | 8'010 µs | 11'449 µs | 11'449 µs |

## Summary of Manual Benchmark (Average of 5 Runs)

This table summarizes a manual benchmark designed to measure throughput and memory efficiency under sustained load.

Each run consists of 50,000 iterations of this action. The table displays the average results across 5 independent runs for each wrapper.

| Wrapper | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff (Avg) |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| **Koffi** | 230.82 ops/sec | 4.33 ms | 4.46 ms | 5.35 ms | 7.04 ms | 4.72 MB |
| **N-API** | 239.63 ops/sec | 4.17 ms | 4.30 ms | 5.23 ms | 6.62 ms | 4.06 MB |
| **IPC** | 171.31 ops/sec | 5.84 ms | 5.85 ms | 6.93 ms | 10.28 ms | 10.21 MB |

## Detailed Runs

### Koffi

| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Run 1 | 2026-04-17T09:05:36.744Z | 2026-04-17T09:09:15.783Z | 228.27 ops/sec | 4.38 ms | 4.50 ms | 5.39 ms | 7.35 ms | 2.63 MB |
| Run 2 | 2026-04-17T09:09:17.828Z | 2026-04-17T09:12:54.407Z | 230.86 ops/sec | 4.33 ms | 4.47 ms | 5.35 ms | 6.81 ms | 3.09 MB |
| Run 3 | 2026-04-17T09:12:56.451Z | 2026-04-17T09:16:31.826Z | 232.15 ops/sec | 4.31 ms | 4.44 ms | 5.31 ms | 6.82 ms | 6.09 MB |
| Run 4 | 2026-04-17T09:16:33.872Z | 2026-04-17T09:20:08.088Z | 233.41 ops/sec | 4.28 ms | 4.42 ms | 5.29 ms | 6.73 ms | 6.08 MB |
| Run 5 | 2026-04-17T09:20:10.133Z | 2026-04-17T09:23:48.067Z | 229.43 ops/sec | 4.36 ms | 4.47 ms | 5.38 ms | 7.47 ms | 5.71 MB |
| **Average** | - | - | 230.82 ops/sec | 4.33 ms | 4.46 ms | 5.35 ms | 7.04 ms | 4.72 MB |

### N-API

| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Run 1 | 2026-04-17T09:24:50.107Z | 2026-04-17T09:28:24.288Z | 233.45 ops/sec | 4.28 ms | 4.41 ms | 5.34 ms | 6.81 ms | 1.66 MB |
| Run 2 | 2026-04-17T09:28:26.330Z | 2026-04-17T09:31:56.971Z | 237.37 ops/sec | 4.21 ms | 4.35 ms | 5.24 ms | 6.47 ms | 2.83 MB |
| Run 3 | 2026-04-17T09:31:59.016Z | 2026-04-17T09:35:23.629Z | 244.36 ops/sec | 4.09 ms | 4.23 ms | 5.14 ms | 6.40 ms | 5.80 MB |
| Run 4 | 2026-04-17T09:35:25.673Z | 2026-04-17T09:38:53.506Z | 240.58 ops/sec | 4.16 ms | 4.26 ms | 5.22 ms | 6.84 ms | 5.21 MB |
| Run 5 | 2026-04-17T09:38:55.551Z | 2026-04-17T09:42:21.827Z | 242.39 ops/sec | 4.12 ms | 4.24 ms | 5.20 ms | 6.58 ms | 4.82 MB |
| **Average** | - | - | 239.63 ops/sec | 4.17 ms | 4.30 ms | 5.23 ms | 6.62 ms | 4.06 MB |

### IPC

| Run | Start Time | End Time | Throughput | Avg Latency | p50 | p90 | p99 | Heap Diff |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| Run 1 | 2026-04-17T09:43:23.923Z | 2026-04-17T09:48:16.443Z | 170.93 ops/sec | 5.85 ms | 5.85 ms | 6.94 ms | 10.36 ms | 13.09 MB |
| Run 2 | 2026-04-17T09:48:18.488Z | 2026-04-17T09:53:11.760Z | 170.49 ops/sec | 5.86 ms | 5.87 ms | 6.97 ms | 10.68 ms | 8.24 MB |
| Run 3 | 2026-04-17T09:53:13.800Z | 2026-04-17T09:58:03.738Z | 172.45 ops/sec | 5.80 ms | 5.82 ms | 6.89 ms | 10.28 ms | 6.35 MB |
| Run 4 | 2026-04-17T09:58:05.778Z | 2026-04-17T10:02:58.023Z | 171.09 ops/sec | 5.84 ms | 5.87 ms | 6.94 ms | 10.09 ms | 14.67 MB |
| Run 5 | 2026-04-17T10:03:00.069Z | 2026-04-17T10:07:51.418Z | 171.62 ops/sec | 5.83 ms | 5.84 ms | 6.89 ms | 9.97 ms | 8.72 MB |
| **Average** | - | - | 171.31 ops/sec | 5.84 ms | 5.85 ms | 6.93 ms | 10.28 ms | 10.21 MB |

Loading
Loading