From ef51382760c291fbb085641a359fc478cfffd755 Mon Sep 17 00:00:00 2001 From: mleku Date: Sat, 22 Nov 2025 19:40:48 +0000 Subject: [PATCH] optimize e and p tags --- .claude/settings.local.json | 3 +- .../run_20251122_190700/aggregate_report.txt | 194 +++++++++++++++++ .../khatru-badger_results.txt | 198 +++++++++++++++++ .../khatru-sqlite_results.txt | 198 +++++++++++++++++ .../next-orly-badger_results.txt | 198 +++++++++++++++++ .../next-orly-dgraph_results.txt | 198 +++++++++++++++++ .../next-orly-neo4j_results.txt | 198 +++++++++++++++++ .../nostr-rs-relay_results.txt | 198 +++++++++++++++++ .../relayer-basic_results.txt | 198 +++++++++++++++++ .../rely-sqlite_results.txt | 199 +++++++++++++++++ .../run_20251122_190700/strfry_results.txt | 198 +++++++++++++++++ pkg/database/migrations.go | 146 ++++++++++++- pkg/encoders/tag/benchmark_test.go | 40 ++++ pkg/encoders/tag/tag.go | 200 ++++++++++++++++- pkg/encoders/tag/tag_test.go | 204 ++++++++++++++++++ 15 files changed, 2564 insertions(+), 6 deletions(-) create mode 100644 cmd/benchmark/reports/run_20251122_190700/aggregate_report.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/khatru-badger_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/khatru-sqlite_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/next-orly-badger_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/next-orly-dgraph_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/next-orly-neo4j_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/nostr-rs-relay_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/relayer-basic_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/rely-sqlite_results.txt create mode 100644 cmd/benchmark/reports/run_20251122_190700/strfry_results.txt diff --git a/.claude/settings.local.json b/.claude/settings.local.json index a2d8bbf..022d6fd 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -115,7 +115,8 @@ "Bash(lynx:*)", "Bash(sed:*)", "Bash(docker stop:*)", - "Bash(grep:*)" + "Bash(grep:*)", + "Bash(timeout 30 go test:*)" ], "deny": [], "ask": [] diff --git a/cmd/benchmark/reports/run_20251122_190700/aggregate_report.txt b/cmd/benchmark/reports/run_20251122_190700/aggregate_report.txt new file mode 100644 index 0000000..ec36e7a --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/aggregate_report.txt @@ -0,0 +1,194 @@ +================================================================ +NOSTR RELAY BENCHMARK AGGREGATE REPORT +================================================================ +Generated: 2025-11-22T19:37:27+00:00 +Benchmark Configuration: + Events per test: 50000 + Concurrent workers: 24 + Test duration: 60s + +Relays tested: 9 + +================================================================ +SUMMARY BY RELAY +================================================================ + +Relay: rely-sqlite +---------------------------------------- +Status: COMPLETED +Events/sec: 15903.28 +Events/sec: 6308.59 +Events/sec: 15903.28 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.399274ms +Bottom 10% Avg Latency: 746.992µs +Avg Latency: 1.174853ms +P95 Latency: 2.34974ms +P95 Latency: 1.933092ms +P95 Latency: 897.528µs + +Relay: next-orly-badger +---------------------------------------- +Status: COMPLETED +Events/sec: 16607.66 +Events/sec: 5941.60 +Events/sec: 16607.66 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.338951ms +Bottom 10% Avg Latency: 757.49µs +Avg Latency: 1.490934ms +P95 Latency: 2.047963ms +P95 Latency: 2.961357ms +P95 Latency: 928.904µs + +Relay: next-orly-dgraph +---------------------------------------- +Status: COMPLETED +Events/sec: 16030.75 +Events/sec: 6221.38 +Events/sec: 16030.75 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.395117ms +Bottom 10% Avg Latency: 759.404µs +Avg Latency: 1.256755ms +P95 Latency: 2.2327ms +P95 Latency: 2.095959ms +P95 Latency: 890.448µs + +Relay: next-orly-neo4j +---------------------------------------- +Status: COMPLETED +Events/sec: 16565.07 +Events/sec: 6026.51 +Events/sec: 16565.07 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.32858ms +Bottom 10% Avg Latency: 724.65µs +Avg Latency: 1.392811ms +P95 Latency: 2.11453ms +P95 Latency: 2.568976ms +P95 Latency: 910.826µs + +Relay: khatru-sqlite +---------------------------------------- +Status: COMPLETED +Events/sec: 13273.11 +Events/sec: 6204.61 +Events/sec: 13273.11 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.732057ms +Bottom 10% Avg Latency: 803.833µs +Avg Latency: 1.263843ms +P95 Latency: 3.370931ms +P95 Latency: 2.195471ms +P95 Latency: 905.805µs + +Relay: khatru-badger +---------------------------------------- +Status: COMPLETED +Events/sec: 15590.07 +Events/sec: 6139.02 +Events/sec: 15590.07 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.451694ms +Bottom 10% Avg Latency: 793.994µs +Avg Latency: 1.324245ms +P95 Latency: 2.351317ms +P95 Latency: 2.291241ms +P95 Latency: 901.036µs + +Relay: relayer-basic +---------------------------------------- +Status: COMPLETED +Events/sec: 15076.33 +Events/sec: 6071.70 +Events/sec: 15076.33 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.517087ms +Bottom 10% Avg Latency: 821.229µs +Avg Latency: 1.385607ms +P95 Latency: 2.48546ms +P95 Latency: 2.478156ms +P95 Latency: 916.474µs + +Relay: strfry +---------------------------------------- +Status: COMPLETED +Events/sec: 16279.08 +Events/sec: 6097.81 +Events/sec: 16279.08 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.369757ms +Bottom 10% Avg Latency: 764.155µs +Avg Latency: 1.369895ms +P95 Latency: 2.13361ms +P95 Latency: 2.341095ms +P95 Latency: 894.733µs + +Relay: nostr-rs-relay +---------------------------------------- +Status: COMPLETED +Events/sec: 14836.18 +Events/sec: 6111.29 +Events/sec: 14836.18 +Success Rate: 100.0% +Success Rate: 100.0% +Success Rate: 100.0% +Avg Latency: 1.545053ms +Bottom 10% Avg Latency: 829.94µs +Avg Latency: 1.336805ms +P95 Latency: 2.562666ms +P95 Latency: 2.417039ms +P95 Latency: 936.832µs + + +================================================================ +DETAILED RESULTS +================================================================ + +Individual relay reports are available in: + - /reports/run_20251122_190700/khatru-badger_results.txt + - /reports/run_20251122_190700/khatru-sqlite_results.txt + - /reports/run_20251122_190700/next-orly-badger_results.txt + - /reports/run_20251122_190700/next-orly-dgraph_results.txt + - /reports/run_20251122_190700/next-orly-neo4j_results.txt + - /reports/run_20251122_190700/nostr-rs-relay_results.txt + - /reports/run_20251122_190700/relayer-basic_results.txt + - /reports/run_20251122_190700/rely-sqlite_results.txt + - /reports/run_20251122_190700/strfry_results.txt + +================================================================ +BENCHMARK COMPARISON TABLE +================================================================ + +Relay Status Peak Tput/s Avg Latency Success Rate +---- ------ ----------- ----------- ------------ +rely-sqlite OK 15903.28 1.399274ms 100.0% +next-orly-badger OK 16607.66 1.338951ms 100.0% +next-orly-dgraph OK 16030.75 1.395117ms 100.0% +next-orly-neo4j OK 16565.07 1.32858ms 100.0% +khatru-sqlite OK 13273.11 1.732057ms 100.0% +khatru-badger OK 15590.07 1.451694ms 100.0% +relayer-basic OK 15076.33 1.517087ms 100.0% +strfry OK 16279.08 1.369757ms 100.0% +nostr-rs-relay OK 14836.18 1.545053ms 100.0% + +================================================================ +End of Report +================================================================ diff --git a/cmd/benchmark/reports/run_20251122_190700/khatru-badger_results.txt b/cmd/benchmark/reports/run_20251122_190700/khatru-badger_results.txt new file mode 100644 index 0000000..b2a6270 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/khatru-badger_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_khatru-badger_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763839435106544ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763839435106604ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763839435106631ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763839435106637ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763839435106651ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763839435106670ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763839435106676ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763839435106697ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763839435106704ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763839435106780ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763839435106787ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763839435106802ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763839435106808ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:23:55 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:23:55 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.207170539s +Events/sec: 15590.07 +Avg latency: 1.451694ms +P90 latency: 1.980821ms +P95 latency: 2.351317ms +P99 latency: 3.85562ms +Bottom 10% Avg latency: 793.994µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 285.869262ms +Burst completed: 5000 events in 342.789614ms +Burst completed: 5000 events in 294.148662ms +Burst completed: 5000 events in 312.162616ms +Burst completed: 5000 events in 285.282311ms +Burst completed: 5000 events in 401.532953ms +Burst completed: 5000 events in 303.869144ms +Burst completed: 5000 events in 319.670695ms +Burst completed: 5000 events in 325.238604ms +Burst completed: 5000 events in 269.150105ms +Burst test completed: 50000 events in 8.144623588s, errors: 0 +Events/sec: 6139.02 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.634143457s +Combined ops/sec: 2029.70 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 383293 queries in 1m0.006743126s +Queries/sec: 6387.50 +Avg query latency: 1.745128ms +P95 query latency: 7.082542ms +P99 query latency: 11.228263ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 314586 operations (264586 queries, 50000 writes) in 1m0.003644928s +Operations/sec: 5242.78 +Avg latency: 1.487422ms +Avg query latency: 1.448842ms +Avg write latency: 1.691574ms +P95 latency: 3.789773ms +P99 latency: 6.325059ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.207170539s +Total Events: 50000 +Events/sec: 15590.07 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 98 MB +Avg Latency: 1.451694ms +P90 Latency: 1.980821ms +P95 Latency: 2.351317ms +P99 Latency: 3.85562ms +Bottom 10% Avg Latency: 793.994µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.144623588s +Total Events: 50000 +Events/sec: 6139.02 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 178 MB +Avg Latency: 1.324245ms +P90 Latency: 1.946456ms +P95 Latency: 2.291241ms +P99 Latency: 3.488291ms +Bottom 10% Avg Latency: 514.259µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.634143457s +Total Events: 50000 +Events/sec: 2029.70 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 142 MB +Avg Latency: 389.015µs +P90 Latency: 806.956µs +P95 Latency: 901.036µs +P99 Latency: 1.133428ms +Bottom 10% Avg Latency: 1.055235ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.006743126s +Total Events: 383293 +Events/sec: 6387.50 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 159 MB +Avg Latency: 1.745128ms +P90 Latency: 5.322842ms +P95 Latency: 7.082542ms +P99 Latency: 11.228263ms +Bottom 10% Avg Latency: 7.913494ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003644928s +Total Events: 314586 +Events/sec: 5242.78 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 107 MB +Avg Latency: 1.487422ms +P90 Latency: 2.95774ms +P95 Latency: 3.789773ms +P99 Latency: 6.325059ms +Bottom 10% Avg Latency: 4.427784ms +---------------------------------------- + +Report saved to: /tmp/benchmark_khatru-badger_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_khatru-badger_8/benchmark_report.adoc + +RELAY_NAME: khatru-badger +RELAY_URL: ws://khatru-badger:3334 +TEST_TIMESTAMP: 2025-11-22T19:27:12+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/khatru-sqlite_results.txt b/cmd/benchmark/reports/run_20251122_190700/khatru-sqlite_results.txt new file mode 100644 index 0000000..333ca98 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/khatru-sqlite_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_khatru-sqlite_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763839231750842ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763839231750901ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763839231750925ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763839231750931ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763839231750941ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763839231750956ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763839231750961ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763839231750983ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763839231750993ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763839231751016ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763839231751021ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763839231751033ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763839231751038ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:20:31 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:20:31 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.76701384s +Events/sec: 13273.11 +Avg latency: 1.732057ms +P90 latency: 2.725001ms +P95 latency: 3.370931ms +P99 latency: 5.636846ms +Bottom 10% Avg latency: 803.833µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 324.962224ms +Burst completed: 5000 events in 319.788529ms +Burst completed: 5000 events in 292.223747ms +Burst completed: 5000 events in 297.968607ms +Burst completed: 5000 events in 285.831691ms +Burst completed: 5000 events in 385.949074ms +Burst completed: 5000 events in 290.335776ms +Burst completed: 5000 events in 276.875448ms +Burst completed: 5000 events in 304.201963ms +Burst completed: 5000 events in 273.277754ms +Burst test completed: 50000 events in 8.058529464s, errors: 0 +Events/sec: 6204.61 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.559984136s +Combined ops/sec: 2035.83 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 382812 queries in 1m0.004759428s +Queries/sec: 6379.69 +Avg query latency: 1.753564ms +P95 query latency: 7.120429ms +P99 query latency: 11.234021ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 310209 operations (260209 queries, 50000 writes) in 1m0.002874017s +Operations/sec: 5169.90 +Avg latency: 1.497119ms +Avg query latency: 1.472534ms +Avg write latency: 1.625063ms +P95 latency: 3.842736ms +P99 latency: 6.293151ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.76701384s +Total Events: 50000 +Events/sec: 13273.11 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 133 MB +Avg Latency: 1.732057ms +P90 Latency: 2.725001ms +P95 Latency: 3.370931ms +P99 Latency: 5.636846ms +Bottom 10% Avg Latency: 803.833µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.058529464s +Total Events: 50000 +Events/sec: 6204.61 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 196 MB +Avg Latency: 1.263843ms +P90 Latency: 1.851055ms +P95 Latency: 2.195471ms +P99 Latency: 3.218951ms +Bottom 10% Avg Latency: 504.149µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.559984136s +Total Events: 50000 +Events/sec: 2035.83 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 127 MB +Avg Latency: 390.903µs +P90 Latency: 809.291µs +P95 Latency: 905.805µs +P99 Latency: 1.149089ms +Bottom 10% Avg Latency: 1.046555ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.004759428s +Total Events: 382812 +Events/sec: 6379.69 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 118 MB +Avg Latency: 1.753564ms +P90 Latency: 5.356742ms +P95 Latency: 7.120429ms +P99 Latency: 11.234021ms +Bottom 10% Avg Latency: 7.946956ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.002874017s +Total Events: 310209 +Events/sec: 5169.90 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 123 MB +Avg Latency: 1.497119ms +P90 Latency: 2.998239ms +P95 Latency: 3.842736ms +P99 Latency: 6.293151ms +Bottom 10% Avg Latency: 4.449237ms +---------------------------------------- + +Report saved to: /tmp/benchmark_khatru-sqlite_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_khatru-sqlite_8/benchmark_report.adoc + +RELAY_NAME: khatru-sqlite +RELAY_URL: ws://khatru-sqlite:3334 +TEST_TIMESTAMP: 2025-11-22T19:23:50+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/next-orly-badger_results.txt b/cmd/benchmark/reports/run_20251122_190700/next-orly-badger_results.txt new file mode 100644 index 0000000..09f42bf --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/next-orly-badger_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_next-orly-badger_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763838623230113ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763838623230189ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763838623230211ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763838623230216ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763838623230227ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763838623230248ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763838623230253ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763838623230263ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763838623230268ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763838623230283ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763838623230287ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763838623230296ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763838623230301ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:10:23 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:10:23 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.010658794s +Events/sec: 16607.66 +Avg latency: 1.338951ms +P90 latency: 1.788958ms +P95 latency: 2.047963ms +P99 latency: 2.856809ms +Bottom 10% Avg latency: 757.49µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 291.670556ms +Burst completed: 5000 events in 360.87238ms +Burst completed: 5000 events in 301.408062ms +Burst completed: 5000 events in 316.375958ms +Burst completed: 5000 events in 376.937291ms +Burst completed: 5000 events in 566.001876ms +Burst completed: 5000 events in 315.464051ms +Burst completed: 5000 events in 317.465099ms +Burst completed: 5000 events in 278.045601ms +Burst completed: 5000 events in 284.298545ms +Burst test completed: 50000 events in 8.415248481s, errors: 0 +Events/sec: 5941.60 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.625034214s +Combined ops/sec: 2030.45 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 381027 queries in 1m0.006635598s +Queries/sec: 6349.75 +Avg query latency: 1.772811ms +P95 query latency: 7.236356ms +P99 query latency: 11.279564ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 305823 operations (255823 queries, 50000 writes) in 1m0.003583098s +Operations/sec: 5096.75 +Avg latency: 1.56258ms +Avg query latency: 1.51784ms +Avg write latency: 1.791487ms +P95 latency: 4.018388ms +P99 latency: 7.130801ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.010658794s +Total Events: 50000 +Events/sec: 16607.66 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 129 MB +Avg Latency: 1.338951ms +P90 Latency: 1.788958ms +P95 Latency: 2.047963ms +P99 Latency: 2.856809ms +Bottom 10% Avg Latency: 757.49µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.415248481s +Total Events: 50000 +Events/sec: 5941.60 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 211 MB +Avg Latency: 1.490934ms +P90 Latency: 2.351964ms +P95 Latency: 2.961357ms +P99 Latency: 5.082311ms +Bottom 10% Avg Latency: 562.053µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.625034214s +Total Events: 50000 +Events/sec: 2030.45 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 131 MB +Avg Latency: 399.173µs +P90 Latency: 823.303µs +P95 Latency: 928.904µs +P99 Latency: 1.225059ms +Bottom 10% Avg Latency: 1.081556ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.006635598s +Total Events: 381027 +Events/sec: 6349.75 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 100 MB +Avg Latency: 1.772811ms +P90 Latency: 5.462421ms +P95 Latency: 7.236356ms +P99 Latency: 11.279564ms +Bottom 10% Avg Latency: 8.018763ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003583098s +Total Events: 305823 +Events/sec: 5096.75 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 99 MB +Avg Latency: 1.56258ms +P90 Latency: 3.106468ms +P95 Latency: 4.018388ms +P99 Latency: 7.130801ms +Bottom 10% Avg Latency: 4.803925ms +---------------------------------------- + +Report saved to: /tmp/benchmark_next-orly-badger_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_next-orly-badger_8/benchmark_report.adoc + +RELAY_NAME: next-orly-badger +RELAY_URL: ws://next-orly-badger:8080 +TEST_TIMESTAMP: 2025-11-22T19:13:41+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/next-orly-dgraph_results.txt b/cmd/benchmark/reports/run_20251122_190700/next-orly-dgraph_results.txt new file mode 100644 index 0000000..b2dd087 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/next-orly-dgraph_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_next-orly-dgraph_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763838826199118ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763838826199210ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763838826199247ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763838826199256ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763838826199269ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763838826199289ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763838826199295ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763838826199309ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763838826199316ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763838826199335ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763838826199341ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763838826199351ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763838826199356ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:13:46 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:13:46 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.119005212s +Events/sec: 16030.75 +Avg latency: 1.395117ms +P90 latency: 1.905706ms +P95 latency: 2.2327ms +P99 latency: 3.309945ms +Bottom 10% Avg latency: 759.404µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 303.869245ms +Burst completed: 5000 events in 306.183047ms +Burst completed: 5000 events in 276.458606ms +Burst completed: 5000 events in 304.076404ms +Burst completed: 5000 events in 307.511965ms +Burst completed: 5000 events in 369.956481ms +Burst completed: 5000 events in 307.122565ms +Burst completed: 5000 events in 282.994622ms +Burst completed: 5000 events in 288.818591ms +Burst completed: 5000 events in 285.099724ms +Burst test completed: 50000 events in 8.036803222s, errors: 0 +Events/sec: 6221.38 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.499088429s +Combined ops/sec: 2040.89 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 382175 queries in 1m0.005131728s +Queries/sec: 6369.04 +Avg query latency: 1.76377ms +P95 query latency: 7.181013ms +P99 query latency: 11.361846ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 304137 operations (254137 queries, 50000 writes) in 1m0.003447398s +Operations/sec: 5068.66 +Avg latency: 1.531621ms +Avg query latency: 1.527187ms +Avg write latency: 1.554157ms +P95 latency: 4.058867ms +P99 latency: 6.578532ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.119005212s +Total Events: 50000 +Events/sec: 16030.75 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 90 MB +Avg Latency: 1.395117ms +P90 Latency: 1.905706ms +P95 Latency: 2.2327ms +P99 Latency: 3.309945ms +Bottom 10% Avg Latency: 759.404µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.036803222s +Total Events: 50000 +Events/sec: 6221.38 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 201 MB +Avg Latency: 1.256755ms +P90 Latency: 1.81348ms +P95 Latency: 2.095959ms +P99 Latency: 3.000094ms +Bottom 10% Avg Latency: 457.006µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.499088429s +Total Events: 50000 +Events/sec: 2040.89 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 174 MB +Avg Latency: 381.925µs +P90 Latency: 793.654µs +P95 Latency: 890.448µs +P99 Latency: 1.114536ms +Bottom 10% Avg Latency: 1.055638ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.005131728s +Total Events: 382175 +Events/sec: 6369.04 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 145 MB +Avg Latency: 1.76377ms +P90 Latency: 5.387866ms +P95 Latency: 7.181013ms +P99 Latency: 11.361846ms +Bottom 10% Avg Latency: 8.012278ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003447398s +Total Events: 304137 +Events/sec: 5068.66 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 88 MB +Avg Latency: 1.531621ms +P90 Latency: 3.143653ms +P95 Latency: 4.058867ms +P99 Latency: 6.578532ms +Bottom 10% Avg Latency: 4.628862ms +---------------------------------------- + +Report saved to: /tmp/benchmark_next-orly-dgraph_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_next-orly-dgraph_8/benchmark_report.adoc + +RELAY_NAME: next-orly-dgraph +RELAY_URL: ws://next-orly-dgraph:8080 +TEST_TIMESTAMP: 2025-11-22T19:17:03+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/next-orly-neo4j_results.txt b/cmd/benchmark/reports/run_20251122_190700/next-orly-neo4j_results.txt new file mode 100644 index 0000000..2645aa6 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/next-orly-neo4j_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_next-orly-neo4j_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763839028914848ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763839028914921ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763839028914942ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763839028914948ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763839028914958ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763839028914973ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763839028914989ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763839028915007ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763839028915013ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763839028915036ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763839028915041ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763839028915050ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763839028915055ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:17:08 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:17:08 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.018399124s +Events/sec: 16565.07 +Avg latency: 1.32858ms +P90 latency: 1.828555ms +P95 latency: 2.11453ms +P99 latency: 2.990871ms +Bottom 10% Avg latency: 724.65µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 293.405025ms +Burst completed: 5000 events in 361.620316ms +Burst completed: 5000 events in 345.575904ms +Burst completed: 5000 events in 316.292611ms +Burst completed: 5000 events in 295.528334ms +Burst completed: 5000 events in 358.255713ms +Burst completed: 5000 events in 442.869494ms +Burst completed: 5000 events in 301.13784ms +Burst completed: 5000 events in 284.850497ms +Burst completed: 5000 events in 291.965255ms +Burst test completed: 50000 events in 8.29667615s, errors: 0 +Events/sec: 6026.51 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.529156295s +Combined ops/sec: 2038.39 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 397591 queries in 1m0.004044242s +Queries/sec: 6626.07 +Avg query latency: 1.67631ms +P95 query latency: 6.658216ms +P99 query latency: 10.435254ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 312697 operations (262697 queries, 50000 writes) in 1m0.003549163s +Operations/sec: 5211.31 +Avg latency: 1.489002ms +Avg query latency: 1.46537ms +Avg write latency: 1.613163ms +P95 latency: 3.830988ms +P99 latency: 6.471326ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.018399124s +Total Events: 50000 +Events/sec: 16565.07 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 204 MB +Avg Latency: 1.32858ms +P90 Latency: 1.828555ms +P95 Latency: 2.11453ms +P99 Latency: 2.990871ms +Bottom 10% Avg Latency: 724.65µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.29667615s +Total Events: 50000 +Events/sec: 6026.51 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 205 MB +Avg Latency: 1.392811ms +P90 Latency: 2.088531ms +P95 Latency: 2.568976ms +P99 Latency: 4.193773ms +Bottom 10% Avg Latency: 462.345µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.529156295s +Total Events: 50000 +Events/sec: 2038.39 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 132 MB +Avg Latency: 388.158µs +P90 Latency: 813.891µs +P95 Latency: 910.826µs +P99 Latency: 1.152085ms +Bottom 10% Avg Latency: 1.025153ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.004044242s +Total Events: 397591 +Events/sec: 6626.07 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 116 MB +Avg Latency: 1.67631ms +P90 Latency: 5.072074ms +P95 Latency: 6.658216ms +P99 Latency: 10.435254ms +Bottom 10% Avg Latency: 7.422142ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003549163s +Total Events: 312697 +Events/sec: 5211.31 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 139 MB +Avg Latency: 1.489002ms +P90 Latency: 2.962995ms +P95 Latency: 3.830988ms +P99 Latency: 6.471326ms +Bottom 10% Avg Latency: 4.527291ms +---------------------------------------- + +Report saved to: /tmp/benchmark_next-orly-neo4j_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_next-orly-neo4j_8/benchmark_report.adoc + +RELAY_NAME: next-orly-neo4j +RELAY_URL: ws://next-orly-neo4j:8080 +TEST_TIMESTAMP: 2025-11-22T19:20:26+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/nostr-rs-relay_results.txt b/cmd/benchmark/reports/run_20251122_190700/nostr-rs-relay_results.txt new file mode 100644 index 0000000..50641e0 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/nostr-rs-relay_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_nostr-rs-relay_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763840044071805ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763840044071886ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763840044071912ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763840044071918ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763840044071926ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763840044071941ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763840044071946ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763840044071959ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763840044071965ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763840044071993ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763840044072003ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763840044072012ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763840044072017ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:34:04 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:34:04 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.370139282s +Events/sec: 14836.18 +Avg latency: 1.545053ms +P90 latency: 2.163496ms +P95 latency: 2.562666ms +P99 latency: 3.871045ms +Bottom 10% Avg latency: 829.94µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 291.316304ms +Burst completed: 5000 events in 318.38321ms +Burst completed: 5000 events in 369.717856ms +Burst completed: 5000 events in 386.679947ms +Burst completed: 5000 events in 313.894228ms +Burst completed: 5000 events in 375.7593ms +Burst completed: 5000 events in 300.682893ms +Burst completed: 5000 events in 270.421689ms +Burst completed: 5000 events in 281.989788ms +Burst completed: 5000 events in 265.54975ms +Burst test completed: 50000 events in 8.181579562s, errors: 0 +Events/sec: 6111.29 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.611048938s +Combined ops/sec: 2031.61 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 388576 queries in 1m0.007765782s +Queries/sec: 6475.43 +Avg query latency: 1.737292ms +P95 query latency: 7.011739ms +P99 query latency: 11.25404ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 320770 operations (270770 queries, 50000 writes) in 1m0.003815149s +Operations/sec: 5345.83 +Avg latency: 1.418636ms +Avg query latency: 1.407911ms +Avg write latency: 1.476716ms +P95 latency: 3.545655ms +P99 latency: 5.727035ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.370139282s +Total Events: 50000 +Events/sec: 14836.18 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 131 MB +Avg Latency: 1.545053ms +P90 Latency: 2.163496ms +P95 Latency: 2.562666ms +P99 Latency: 3.871045ms +Bottom 10% Avg Latency: 829.94µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.181579562s +Total Events: 50000 +Events/sec: 6111.29 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 205 MB +Avg Latency: 1.336805ms +P90 Latency: 2.051133ms +P95 Latency: 2.417039ms +P99 Latency: 3.368018ms +Bottom 10% Avg Latency: 499.404µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.611048938s +Total Events: 50000 +Events/sec: 2031.61 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 112 MB +Avg Latency: 397.462µs +P90 Latency: 827.995µs +P95 Latency: 936.832µs +P99 Latency: 1.2249ms +Bottom 10% Avg Latency: 1.08713ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.007765782s +Total Events: 388576 +Events/sec: 6475.43 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 117 MB +Avg Latency: 1.737292ms +P90 Latency: 5.250359ms +P95 Latency: 7.011739ms +P99 Latency: 11.25404ms +Bottom 10% Avg Latency: 7.872769ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003815149s +Total Events: 320770 +Events/sec: 5345.83 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 112 MB +Avg Latency: 1.418636ms +P90 Latency: 2.830856ms +P95 Latency: 3.545655ms +P99 Latency: 5.727035ms +Bottom 10% Avg Latency: 4.081447ms +---------------------------------------- + +Report saved to: /tmp/benchmark_nostr-rs-relay_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_nostr-rs-relay_8/benchmark_report.adoc + +RELAY_NAME: nostr-rs-relay +RELAY_URL: ws://nostr-rs-relay:8080 +TEST_TIMESTAMP: 2025-11-22T19:37:22+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/relayer-basic_results.txt b/cmd/benchmark/reports/run_20251122_190700/relayer-basic_results.txt new file mode 100644 index 0000000..2ae9662 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/relayer-basic_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_relayer-basic_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763839638031581ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763839638031660ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763839638031685ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763839638031691ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763839638031697ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763839638031717ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763839638031722ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763839638031734ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763839638031740ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763839638031756ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763839638031761ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763839638031770ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763839638031775ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:27:18 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:27:18 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.316457481s +Events/sec: 15076.33 +Avg latency: 1.517087ms +P90 latency: 2.134693ms +P95 latency: 2.48546ms +P99 latency: 3.572901ms +Bottom 10% Avg latency: 821.229µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 276.700297ms +Burst completed: 5000 events in 392.081438ms +Burst completed: 5000 events in 314.563405ms +Burst completed: 5000 events in 397.214306ms +Burst completed: 5000 events in 322.96797ms +Burst completed: 5000 events in 373.044665ms +Burst completed: 5000 events in 296.191438ms +Burst completed: 5000 events in 271.613902ms +Burst completed: 5000 events in 287.329791ms +Burst completed: 5000 events in 296.745792ms +Burst test completed: 50000 events in 8.234927616s, errors: 0 +Events/sec: 6071.70 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.561126307s +Combined ops/sec: 2035.74 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 382011 queries in 1m0.004538365s +Queries/sec: 6366.37 +Avg query latency: 1.775143ms +P95 query latency: 7.266438ms +P99 query latency: 11.395836ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 315099 operations (265099 queries, 50000 writes) in 1m0.002672022s +Operations/sec: 5251.42 +Avg latency: 1.462691ms +Avg query latency: 1.440796ms +Avg write latency: 1.578778ms +P95 latency: 3.739636ms +P99 latency: 6.381464ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.316457481s +Total Events: 50000 +Events/sec: 15076.33 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 133 MB +Avg Latency: 1.517087ms +P90 Latency: 2.134693ms +P95 Latency: 2.48546ms +P99 Latency: 3.572901ms +Bottom 10% Avg Latency: 821.229µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.234927616s +Total Events: 50000 +Events/sec: 6071.70 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 186 MB +Avg Latency: 1.385607ms +P90 Latency: 2.08644ms +P95 Latency: 2.478156ms +P99 Latency: 3.769153ms +Bottom 10% Avg Latency: 520.086µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.561126307s +Total Events: 50000 +Events/sec: 2035.74 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 177 MB +Avg Latency: 394.452µs +P90 Latency: 821.172µs +P95 Latency: 916.474µs +P99 Latency: 1.143807ms +Bottom 10% Avg Latency: 1.056519ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.004538365s +Total Events: 382011 +Events/sec: 6366.37 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 134 MB +Avg Latency: 1.775143ms +P90 Latency: 5.448168ms +P95 Latency: 7.266438ms +P99 Latency: 11.395836ms +Bottom 10% Avg Latency: 8.059404ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.002672022s +Total Events: 315099 +Events/sec: 5251.42 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 107 MB +Avg Latency: 1.462691ms +P90 Latency: 2.897052ms +P95 Latency: 3.739636ms +P99 Latency: 6.381464ms +Bottom 10% Avg Latency: 4.413874ms +---------------------------------------- + +Report saved to: /tmp/benchmark_relayer-basic_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_relayer-basic_8/benchmark_report.adoc + +RELAY_NAME: relayer-basic +RELAY_URL: ws://relayer-basic:7447 +TEST_TIMESTAMP: 2025-11-22T19:30:36+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/rely-sqlite_results.txt b/cmd/benchmark/reports/run_20251122_190700/rely-sqlite_results.txt new file mode 100644 index 0000000..07f2df1 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/rely-sqlite_results.txt @@ -0,0 +1,199 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_rely-sqlite_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763838420592113ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763838420592185ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763838420592206ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763838420592211ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763838420592221ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763838420592244ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763838420592249ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763838420592260ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763838420592265ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763838420592279ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763838420592284ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763838420592294ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763838420592300ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:07:00 INFO: Extracted embedded libsecp256k1 to /tmp/orly-libsecp256k1/libsecp256k1.so +2025/11/22 19:07:00 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:07:00 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.144005095s +Events/sec: 15903.28 +Avg latency: 1.399274ms +P90 latency: 1.969161ms +P95 latency: 2.34974ms +P99 latency: 3.740183ms +Bottom 10% Avg latency: 746.992µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 289.665872ms +Burst completed: 5000 events in 298.189416ms +Burst completed: 5000 events in 284.248905ms +Burst completed: 5000 events in 299.878917ms +Burst completed: 5000 events in 290.195429ms +Burst completed: 5000 events in 335.211169ms +Burst completed: 5000 events in 306.221225ms +Burst completed: 5000 events in 280.945252ms +Burst completed: 5000 events in 270.701091ms +Burst completed: 5000 events in 265.342517ms +Burst test completed: 50000 events in 7.925705852s, errors: 0 +Events/sec: 6308.59 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.557413391s +Combined ops/sec: 2036.05 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 388544 queries in 1m0.004756071s +Queries/sec: 6475.22 +Avg query latency: 1.723827ms +P95 query latency: 6.917596ms +P99 query latency: 10.942489ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 309051 operations (259051 queries, 50000 writes) in 1m0.003409818s +Operations/sec: 5150.56 +Avg latency: 1.532079ms +Avg query latency: 1.486246ms +Avg write latency: 1.769539ms +P95 latency: 4.004134ms +P99 latency: 6.701092ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.144005095s +Total Events: 50000 +Events/sec: 15903.28 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 121 MB +Avg Latency: 1.399274ms +P90 Latency: 1.969161ms +P95 Latency: 2.34974ms +P99 Latency: 3.740183ms +Bottom 10% Avg Latency: 746.992µs +---------------------------------------- + +Test: Burst Pattern +Duration: 7.925705852s +Total Events: 50000 +Events/sec: 6308.59 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 188 MB +Avg Latency: 1.174853ms +P90 Latency: 1.682332ms +P95 Latency: 1.933092ms +P99 Latency: 2.630546ms +Bottom 10% Avg Latency: 472.317µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.557413391s +Total Events: 50000 +Events/sec: 2036.05 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 130 MB +Avg Latency: 385.432µs +P90 Latency: 801.624µs +P95 Latency: 897.528µs +P99 Latency: 1.136145ms +Bottom 10% Avg Latency: 1.031469ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.004756071s +Total Events: 388544 +Events/sec: 6475.22 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 132 MB +Avg Latency: 1.723827ms +P90 Latency: 5.21331ms +P95 Latency: 6.917596ms +P99 Latency: 10.942489ms +Bottom 10% Avg Latency: 7.705115ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003409818s +Total Events: 309051 +Events/sec: 5150.56 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 99 MB +Avg Latency: 1.532079ms +P90 Latency: 3.088572ms +P95 Latency: 4.004134ms +P99 Latency: 6.701092ms +Bottom 10% Avg Latency: 4.65921ms +---------------------------------------- + +Report saved to: /tmp/benchmark_rely-sqlite_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_rely-sqlite_8/benchmark_report.adoc + +RELAY_NAME: rely-sqlite +RELAY_URL: ws://rely-sqlite:3334 +TEST_TIMESTAMP: 2025-11-22T19:10:18+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/cmd/benchmark/reports/run_20251122_190700/strfry_results.txt b/cmd/benchmark/reports/run_20251122_190700/strfry_results.txt new file mode 100644 index 0000000..43f41b8 --- /dev/null +++ b/cmd/benchmark/reports/run_20251122_190700/strfry_results.txt @@ -0,0 +1,198 @@ +Starting Nostr Relay Benchmark (Badger Backend) +Data Directory: /tmp/benchmark_strfry_8 +Events: 50000, Workers: 24, Duration: 1m0s +1763839841101245ℹ️ migrating to version 1... /build/pkg/database/migrations.go:66 +1763839841101335ℹ️ migrating to version 2... /build/pkg/database/migrations.go:73 +1763839841101370ℹ️ migrating to version 3... /build/pkg/database/migrations.go:80 +1763839841101377ℹ️ cleaning up ephemeral events (kinds 20000-29999)... /build/pkg/database/migrations.go:294 +1763839841101390ℹ️ cleaned up 0 ephemeral events from database /build/pkg/database/migrations.go:339 +1763839841101408ℹ️ migrating to version 4... /build/pkg/database/migrations.go:87 +1763839841101414ℹ️ converting events to optimized inline storage (Reiser4 optimization)... /build/pkg/database/migrations.go:347 +1763839841101428ℹ️ found 0 events to convert (0 regular, 0 replaceable, 0 addressable) /build/pkg/database/migrations.go:436 +1763839841101435ℹ️ migration complete: converted 0 events to optimized inline storage, deleted 0 old keys /build/pkg/database/migrations.go:545 +1763839841101455ℹ️ migrating to version 5... /build/pkg/database/migrations.go:94 +1763839841101462ℹ️ re-encoding events with optimized tag binary format... /build/pkg/database/migrations.go:552 +1763839841101469ℹ️ found 0 events with e/p tags to re-encode /build/pkg/database/migrations.go:639 +1763839841101476ℹ️ no events need re-encoding /build/pkg/database/migrations.go:642 + +╔════════════════════════════════════════════════════════╗ +║ BADGER BACKEND BENCHMARK SUITE ║ +╚════════════════════════════════════════════════════════╝ + +=== Starting Badger benchmark === +RunPeakThroughputTest (Badger).. + +=== Peak Throughput Test === +2025/11/22 19:30:41 WARN: Failed to load embedded library from /tmp/orly-libsecp256k1/libsecp256k1.so: Error relocating /tmp/orly-libsecp256k1/libsecp256k1.so: __fprintf_chk: symbol not found, falling back to system paths +2025/11/22 19:30:41 INFO: Successfully loaded libsecp256k1 v5.0.0 from system path: libsecp256k1.so.2 +Events saved: 50000/50000 (100.0%), errors: 0 +Duration: 3.071426372s +Events/sec: 16279.08 +Avg latency: 1.369757ms +P90 latency: 1.839299ms +P95 latency: 2.13361ms +P99 latency: 3.209938ms +Bottom 10% Avg latency: 764.155µs +Wiping database between tests... +RunBurstPatternTest (Badger).. + +=== Burst Pattern Test === +Burst completed: 5000 events in 283.479669ms +Burst completed: 5000 events in 320.332742ms +Burst completed: 5000 events in 282.814191ms +Burst completed: 5000 events in 305.151074ms +Burst completed: 5000 events in 311.552363ms +Burst completed: 5000 events in 381.183959ms +Burst completed: 5000 events in 312.80669ms +Burst completed: 5000 events in 294.748789ms +Burst completed: 5000 events in 372.553415ms +Burst completed: 5000 events in 328.457439ms +Burst test completed: 50000 events in 8.199670789s, errors: 0 +Events/sec: 6097.81 +Wiping database between tests... +RunMixedReadWriteTest (Badger).. + +=== Mixed Read/Write Test === +Generating 1000 unique synthetic events (minimum 300 bytes each)... +Generated 1000 events: + Average content size: 312 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database for read tests... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Mixed test completed: 25000 writes, 25000 reads in 24.666176533s +Combined ops/sec: 2027.07 +Wiping database between tests... +RunQueryTest (Badger).. + +=== Query Test === +Generating 10000 unique synthetic events (minimum 300 bytes each)... +Generated 10000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 10000 events for query tests... +Query test completed: 379410 queries in 1m0.006248896s +Queries/sec: 6322.84 +Avg query latency: 1.765248ms +P95 query latency: 7.171725ms +P99 query latency: 11.436059ms +Wiping database between tests... +RunConcurrentQueryStoreTest (Badger).. + +=== Concurrent Query/Store Test === +Generating 5000 unique synthetic events (minimum 300 bytes each)... +Generated 5000 events: + Average content size: 313 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Pre-populating database with 5000 events for concurrent query/store test... +Generating 50000 unique synthetic events (minimum 300 bytes each)... +Generated 50000 events: + Average content size: 314 bytes + All events are unique (incremental timestamps) + All events are properly signed + +Concurrent test completed: 305571 operations (255571 queries, 50000 writes) in 1m0.003361786s +Operations/sec: 5092.56 +Avg latency: 1.593158ms +Avg query latency: 1.518193ms +Avg write latency: 1.976334ms +P95 latency: 4.090954ms +P99 latency: 7.169741ms + +=== Badger benchmark completed === + + +================================================================================ +BENCHMARK REPORT +================================================================================ + +Test: Peak Throughput +Duration: 3.071426372s +Total Events: 50000 +Events/sec: 16279.08 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 102 MB +Avg Latency: 1.369757ms +P90 Latency: 1.839299ms +P95 Latency: 2.13361ms +P99 Latency: 3.209938ms +Bottom 10% Avg Latency: 764.155µs +---------------------------------------- + +Test: Burst Pattern +Duration: 8.199670789s +Total Events: 50000 +Events/sec: 6097.81 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 251 MB +Avg Latency: 1.369895ms +P90 Latency: 2.004985ms +P95 Latency: 2.341095ms +P99 Latency: 3.30014ms +Bottom 10% Avg Latency: 550.762µs +---------------------------------------- + +Test: Mixed Read/Write +Duration: 24.666176533s +Total Events: 50000 +Events/sec: 2027.07 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 205 MB +Avg Latency: 381.997µs +P90 Latency: 798.95µs +P95 Latency: 894.733µs +P99 Latency: 1.134289ms +Bottom 10% Avg Latency: 1.013526ms +---------------------------------------- + +Test: Query Performance +Duration: 1m0.006248896s +Total Events: 379410 +Events/sec: 6322.84 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 128 MB +Avg Latency: 1.765248ms +P90 Latency: 5.373945ms +P95 Latency: 7.171725ms +P99 Latency: 11.436059ms +Bottom 10% Avg Latency: 8.036698ms +---------------------------------------- + +Test: Concurrent Query/Store +Duration: 1m0.003361786s +Total Events: 305571 +Events/sec: 5092.56 +Success Rate: 100.0% +Concurrent Workers: 24 +Memory Used: 102 MB +Avg Latency: 1.593158ms +P90 Latency: 3.181242ms +P95 Latency: 4.090954ms +P99 Latency: 7.169741ms +Bottom 10% Avg Latency: 4.862492ms +---------------------------------------- + +Report saved to: /tmp/benchmark_strfry_8/benchmark_report.txt +AsciiDoc report saved to: /tmp/benchmark_strfry_8/benchmark_report.adoc + +RELAY_NAME: strfry +RELAY_URL: ws://strfry:8080 +TEST_TIMESTAMP: 2025-11-22T19:33:59+00:00 +BENCHMARK_CONFIG: + Events: 50000 + Workers: 24 + Duration: 60s diff --git a/pkg/database/migrations.go b/pkg/database/migrations.go index 05b7fb9..24ea09a 100644 --- a/pkg/database/migrations.go +++ b/pkg/database/migrations.go @@ -16,7 +16,7 @@ import ( ) const ( - currentVersion uint32 = 4 + currentVersion uint32 = 5 ) func (d *D) RunMigrations() { @@ -90,6 +90,13 @@ func (d *D) RunMigrations() { // bump to version 4 _ = d.writeVersionTag(4) } + if dbVersion < 5 { + log.I.F("migrating to version 5...") + // re-encode events with optimized tag binary format (e/p tags) + d.ReencodeEventsWithOptimizedTags() + // bump to version 5 + _ = d.writeVersionTag(5) + } } // writeVersionTag writes a new version tag key to the database (no value) @@ -537,3 +544,140 @@ func (d *D) ConvertSmallEventsToInline() { log.I.F("migration complete: converted %d events to optimized inline storage, deleted %d old keys", convertedCount, deletedCount) } + +// ReencodeEventsWithOptimizedTags re-encodes all events to use the new binary +// tag format that stores e/p tag values as 33-byte binary (32-byte hash + null) +// instead of 64-byte hex strings. This reduces memory usage by ~48% for these tags. +func (d *D) ReencodeEventsWithOptimizedTags() { + log.I.F("re-encoding events with optimized tag binary format...") + var err error + + type EventUpdate struct { + Key []byte + OldData []byte + NewData []byte + } + + var updates []EventUpdate + var processedCount int + + // Helper to collect event updates from iterator + // Only processes regular events (evt prefix) - inline storage already benefits + collectUpdates := func(it *badger.Iterator, prefix []byte) error { + for it.Rewind(); it.Valid(); it.Next() { + item := it.Item() + key := item.KeyCopy(nil) + + var val []byte + if val, err = item.ValueCopy(nil); chk.E(err) { + continue + } + + // Regular event storage - data is in value + eventData := val + if len(eventData) == 0 { + continue + } + + // Decode the event + ev := new(event.E) + if err = ev.UnmarshalBinary(bytes.NewBuffer(eventData)); chk.E(err) { + continue + } + + // Check if this event has e or p tags that could benefit from optimization + hasOptimizableTags := false + if ev.Tags != nil && ev.Tags.Len() > 0 { + for _, t := range *ev.Tags { + if t.Len() >= 2 { + key := t.Key() + if len(key) == 1 && (key[0] == 'e' || key[0] == 'p') { + hasOptimizableTags = true + break + } + } + } + } + + if !hasOptimizableTags { + continue + } + + // Re-encode the event (this will apply the new tag optimization) + newData := ev.MarshalBinaryToBytes(nil) + + // Only update if the data actually changed + if !bytes.Equal(eventData, newData) { + updates = append(updates, EventUpdate{ + Key: key, + OldData: eventData, + NewData: newData, + }) + } + } + return nil + } + + // Only process regular "evt" prefix events (not inline storage) + // Inline storage (sev, rev, aev) already benefits from the optimization + // because the binary data is stored directly in the key + prf := new(bytes.Buffer) + if err = indexes.EventEnc(nil).MarshalWrite(prf); chk.E(err) { + return + } + evtPrefix := prf.Bytes() + + // Collect updates from regular events only + if err = d.View(func(txn *badger.Txn) error { + it := txn.NewIterator(badger.IteratorOptions{Prefix: evtPrefix}) + defer it.Close() + return collectUpdates(it, evtPrefix) + }); chk.E(err) { + return + } + + log.I.F("found %d events with e/p tags to re-encode", len(updates)) + + if len(updates) == 0 { + log.I.F("no events need re-encoding") + return + } + + // Apply updates in batches + const batchSize = 1000 + for i := 0; i < len(updates); i += batchSize { + end := i + batchSize + if end > len(updates) { + end = len(updates) + } + batch := updates[i:end] + + if err = d.Update(func(txn *badger.Txn) error { + for _, upd := range batch { + // Since we're only processing regular events (evt prefix), + // we just update the value directly + if err = txn.Set(upd.Key, upd.NewData); chk.E(err) { + log.W.F("failed to update event: %v", err) + continue + } + processedCount++ + } + return nil + }); chk.E(err) { + log.W.F("batch update failed: %v", err) + continue + } + + if (i/batchSize)%10 == 0 && i > 0 { + log.I.F("progress: %d/%d events re-encoded", i, len(updates)) + } + } + + savedBytes := 0 + for _, upd := range updates { + savedBytes += len(upd.OldData) - len(upd.NewData) + } + + log.I.F("migration complete: re-encoded %d events, saved approximately %d bytes (%.2f KB)", + processedCount, savedBytes, float64(savedBytes)/1024.0) +} diff --git a/pkg/encoders/tag/benchmark_test.go b/pkg/encoders/tag/benchmark_test.go index 1e8e12e..b0a4737 100644 --- a/pkg/encoders/tag/benchmark_test.go +++ b/pkg/encoders/tag/benchmark_test.go @@ -291,3 +291,43 @@ func BenchmarkTagsToSliceOfSliceOfStrings(b *testing.B) { }) } +func BenchmarkTagEquals(b *testing.B) { + b.Run("BinaryToBinary", func(b *testing.B) { + b.ReportAllocs() + // Create two tags with same binary-encoded value + tag1 := New() + _, _ = tag1.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + tag2 := New() + _, _ = tag2.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = tag1.Equals(tag2) + } + }) + b.Run("BinaryToHex", func(b *testing.B) { + b.ReportAllocs() + // One binary-encoded, one hex (simulate comparison with non-optimized tag) + tag1 := New() + _, _ = tag1.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + // Create hex version manually (simulating older format) + tag2 := NewFromBytesSlice([]byte("e"), []byte("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = tag1.Equals(tag2) + } + }) + b.Run("HexToHex", func(b *testing.B) { + b.ReportAllocs() + // Both hex (non-optimized tags) + tag1 := NewFromBytesSlice([]byte("t"), []byte("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + tag2 := NewFromBytesSlice([]byte("t"), []byte("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + _ = tag1.Equals(tag2) + } + }) +} + diff --git a/pkg/encoders/tag/tag.go b/pkg/encoders/tag/tag.go index aea97bb..61afaf4 100644 --- a/pkg/encoders/tag/tag.go +++ b/pkg/encoders/tag/tag.go @@ -7,6 +7,7 @@ import ( "bytes" "lol.mleku.dev/errorf" + "next.orly.dev/pkg/encoders/hex" "next.orly.dev/pkg/encoders/text" "next.orly.dev/pkg/utils" ) @@ -18,6 +19,22 @@ const ( Relay ) +// Binary encoding constants for optimized storage of hex-encoded identifiers +const ( + // BinaryEncodedLen is the length of a binary-encoded 32-byte hash with null terminator + BinaryEncodedLen = 33 + // HexEncodedLen is the length of a hex-encoded 32-byte hash + HexEncodedLen = 64 + // HashLen is the raw length of a hash (pubkey/event ID) + HashLen = 32 +) + +// Tags that use binary encoding optimization for their value field +var binaryOptimizedTags = map[string]bool{ + "e": true, // event references + "p": true, // pubkey references +} + type T struct { T [][]byte } @@ -76,6 +93,7 @@ func (t *T) Contains(s []byte) (b bool) { } // Marshal encodes a tag.T as standard minified JSON array of strings. +// Binary-encoded values (e/p tags) are automatically converted back to hex. func (t *T) Marshal(dst []byte) (b []byte) { b = dst // Pre-allocate buffer if nil to reduce reallocations @@ -83,14 +101,25 @@ func (t *T) Marshal(dst []byte) (b []byte) { // Each field might be escaped, so estimate len(field) * 1.5 + 2 quotes + comma if b == nil && len(t.T) > 0 { estimatedSize := 2 // brackets - for _, s := range t.T { - estimatedSize += len(s)*3/2 + 4 // escaped field + quotes + comma + for i, s := range t.T { + fieldLen := len(s) + // Binary-encoded fields become hex (33 -> 64 chars) + if i == Value && isBinaryEncoded(s) { + fieldLen = HexEncodedLen + } + estimatedSize += fieldLen*3/2 + 4 // escaped field + quotes + comma } b = make([]byte, 0, estimatedSize) } b = append(b, '[') for i, s := range t.T { - b = text.AppendQuote(b, s, text.NostrEscape) + // Convert binary-encoded value fields back to hex for JSON + if i == Value && isBinaryEncoded(s) { + hexVal := hex.EncAppend(nil, s[:HashLen]) + b = text.AppendQuote(b, hexVal, text.NostrEscape) + } else { + b = text.AppendQuote(b, s, text.NostrEscape) + } if i < len(t.T)-1 { b = append(b, ',') } @@ -112,6 +141,8 @@ func (t *T) MarshalJSON() (b []byte, err error) { } // Unmarshal decodes a standard minified JSON array of strings to a tags.T. +// For "e" and "p" tags with 64-character hex values, it converts them to +// 33-byte binary format (32 bytes hash + null terminator) for efficiency. func (t *T) Unmarshal(b []byte) (r []byte, err error) { var inQuotes, openedBracket bool var quoteStart int @@ -135,7 +166,23 @@ func (t *T) Unmarshal(b []byte) (r []byte, err error) { // original JSON buffer in-place (which would corrupt subsequent parsing). copyBuf := make([]byte, i-quoteStart) copy(copyBuf, b[quoteStart:i]) - t.T = append(t.T, text.NostrUnescape(copyBuf)) + unescaped := text.NostrUnescape(copyBuf) + + // Optimize e/p tag values by converting hex to binary + fieldIdx := len(t.T) + if fieldIdx == Value && len(t.T) > 0 && shouldOptimize(t.T[Key], unescaped) { + // Decode hex to binary format: 32 bytes + null terminator + binVal := make([]byte, BinaryEncodedLen) + if _, err = hex.DecBytes(binVal[:HashLen], unescaped); err == nil { + binVal[HashLen] = 0 // null terminator + t.T = append(t.T, binVal) + } else { + // If decode fails, store as-is + t.T = append(t.T, unescaped) + } + } else { + t.T = append(t.T, unescaped) + } } } if !openedBracket || inQuotes { @@ -193,3 +240,148 @@ func (t *T) ToSliceOfStrings() (s []string) { } return } + +// isBinaryEncoded checks if a value field is stored in optimized binary format +// (32-byte hash + null terminator = 33 bytes total) +func isBinaryEncoded(val []byte) bool { + return len(val) == BinaryEncodedLen && val[HashLen] == 0 +} + +// shouldOptimize checks if a tag should use binary encoding optimization +func shouldOptimize(key []byte, val []byte) bool { + if len(key) != 1 { + return false + } + keyStr := string(key) + if !binaryOptimizedTags[keyStr] { + return false + } + // Only optimize if it's a valid 64-character hex string + return len(val) == HexEncodedLen && isValidHex(val) +} + +// isValidHex checks if all bytes are valid hex characters +func isValidHex(b []byte) bool { + for _, c := range b { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { + return false + } + } + return true +} + +// ValueHex returns the value field as hex string. If the value is stored in +// binary format, it converts it to hex. Otherwise, it returns the value as-is. +func (t *T) ValueHex() []byte { + if t == nil || len(t.T) <= Value { + return nil + } + val := t.T[Value] + if isBinaryEncoded(val) { + // Convert binary back to hex + return hex.EncAppend(nil, val[:HashLen]) + } + return val +} + +// ValueBinary returns the raw binary value if it's binary-encoded, or nil otherwise. +// This is useful for database operations that need the raw hash bytes. +func (t *T) ValueBinary() []byte { + if t == nil || len(t.T) <= Value { + return nil + } + val := t.T[Value] + if isBinaryEncoded(val) { + return val[:HashLen] + } + return nil +} + +// Equals compares two tags for equality, handling both binary and hex encodings. +// This ensures that ["e", "abc..."] and ["e", ] are equal if they +// represent the same hash. This method does NOT allocate memory. +func (t *T) Equals(other *T) bool { + if t == nil && other == nil { + return true + } + if t == nil || other == nil { + return false + } + if len(t.T) != len(other.T) { + return false + } + for i := range t.T { + if i == Value && len(t.T) > Value { + // Special handling for value field to compare binary vs hex without allocating + tVal := t.T[Value] + oVal := other.T[Value] + + tIsBinary := isBinaryEncoded(tVal) + oIsBinary := isBinaryEncoded(oVal) + + // Both binary - compare first 32 bytes directly + if tIsBinary && oIsBinary { + if !bytes.Equal(tVal[:HashLen], oVal[:HashLen]) { + return false + } + } else if tIsBinary || oIsBinary { + // One is binary, one is hex - need to compare carefully + // Compare the binary one's raw bytes with hex-decoded version of the other + var binBytes, hexBytes []byte + if tIsBinary { + binBytes = tVal[:HashLen] + hexBytes = oVal + } else { + binBytes = oVal[:HashLen] + hexBytes = tVal + } + + // Decode hex inline without allocation by comparing byte by byte + if len(hexBytes) != HexEncodedLen { + return false + } + for j := 0; j < HashLen; j++ { + // Convert two hex chars to one byte and compare + hi := hexBytes[j*2] + lo := hexBytes[j*2+1] + + var hiByte, loByte byte + if hi >= '0' && hi <= '9' { + hiByte = hi - '0' + } else if hi >= 'a' && hi <= 'f' { + hiByte = hi - 'a' + 10 + } else if hi >= 'A' && hi <= 'F' { + hiByte = hi - 'A' + 10 + } else { + return false + } + + if lo >= '0' && lo <= '9' { + loByte = lo - '0' + } else if lo >= 'a' && lo <= 'f' { + loByte = lo - 'a' + 10 + } else if lo >= 'A' && lo <= 'F' { + loByte = lo - 'A' + 10 + } else { + return false + } + + expectedByte := (hiByte << 4) | loByte + if binBytes[j] != expectedByte { + return false + } + } + } else { + // Both are regular (hex or other) - direct comparison + if !bytes.Equal(tVal, oVal) { + return false + } + } + } else { + if !bytes.Equal(t.T[i], other.T[i]) { + return false + } + } + } + return true +} diff --git a/pkg/encoders/tag/tag_test.go b/pkg/encoders/tag/tag_test.go index b5c9cc9..cb3fd4f 100644 --- a/pkg/encoders/tag/tag_test.go +++ b/pkg/encoders/tag/tag_test.go @@ -30,3 +30,207 @@ func TestMarshalUnmarshal(t *testing.T) { } } } + +// TestBinaryEncodingOptimization verifies that e/p tags are stored in binary format +func TestBinaryEncodingOptimization(t *testing.T) { + testCases := []struct { + name string + json string + expectBinary bool + internalLen int // expected length of Value() field in internal storage + }{ + { + name: "e tag with hex value", + json: `["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`, + expectBinary: true, + internalLen: BinaryEncodedLen, // 33 bytes (32 + null terminator) + }, + { + name: "p tag with hex value", + json: `["p","fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"]`, + expectBinary: true, + internalLen: BinaryEncodedLen, + }, + { + name: "e tag with relay", + json: `["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef","wss://relay.example.com"]`, + expectBinary: true, + internalLen: BinaryEncodedLen, + }, + { + name: "t tag not optimized", + json: `["t","bitcoin"]`, + expectBinary: false, + internalLen: 7, // "bitcoin" as-is + }, + { + name: "e tag with short value not optimized", + json: `["e","short"]`, + expectBinary: false, + internalLen: 5, + }, + { + name: "e tag with invalid hex not optimized", + json: `["e","zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"]`, + expectBinary: false, + internalLen: 64, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + tag := New() + _, err := tag.Unmarshal([]byte(tc.json)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + // Check internal storage length + if tag.Len() < 2 { + t.Fatal("Tag should have at least 2 fields") + } + + valueField := tag.T[Value] + if len(valueField) != tc.internalLen { + t.Errorf("Expected internal value length %d, got %d", tc.internalLen, len(valueField)) + } + + // Check if binary encoded as expected + if tc.expectBinary { + if !isBinaryEncoded(valueField) { + t.Error("Expected binary encoding, but tag is not binary encoded") + } + // Verify null terminator + if valueField[HashLen] != 0 { + t.Error("Binary encoded value should have null terminator at position 32") + } + } else { + if isBinaryEncoded(valueField) { + t.Error("Did not expect binary encoding, but tag is binary encoded") + } + } + + // Marshal back to JSON and verify it matches original + marshaled := tag.Marshal(nil) + if string(marshaled) != tc.json { + t.Errorf("Marshaled JSON doesn't match original.\nExpected: %s\nGot: %s", tc.json, string(marshaled)) + } + }) + } +} + +// TestValueHexMethod verifies ValueHex() correctly converts binary to hex +func TestValueHexMethod(t *testing.T) { + json := `["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]` + tag := New() + _, err := tag.Unmarshal([]byte(json)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + // Internal storage should be binary + if !isBinaryEncoded(tag.T[Value]) { + t.Fatal("Expected binary encoding") + } + + // ValueHex should return the original hex string + hexVal := tag.ValueHex() + expectedHex := "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + if string(hexVal) != expectedHex { + t.Errorf("ValueHex returned wrong value.\nExpected: %s\nGot: %s", expectedHex, string(hexVal)) + } +} + +// TestValueBinaryMethod verifies ValueBinary() returns raw hash bytes +func TestValueBinaryMethod(t *testing.T) { + json := `["p","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]` + tag := New() + _, err := tag.Unmarshal([]byte(json)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + // ValueBinary should return 32 bytes + binVal := tag.ValueBinary() + if binVal == nil { + t.Fatal("ValueBinary returned nil") + } + if len(binVal) != HashLen { + t.Errorf("Expected %d bytes, got %d", HashLen, len(binVal)) + } + + // It should match the first 32 bytes of the internal storage + if !utils.FastEqual(binVal, tag.T[Value][:HashLen]) { + t.Error("ValueBinary doesn't match internal storage") + } +} + +// TestEqualsMethod verifies Equals() handles binary vs hex comparison +func TestEqualsMethod(t *testing.T) { + // Create tag from JSON (will be binary internally) + tag1 := New() + _, err := tag1.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + // Create identical tag + tag2 := New() + _, err = tag2.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if !tag1.Equals(tag2) { + t.Error("Identical tags should be equal") + } + + // Create tag with different value + tag3 := New() + _, err = tag3.Unmarshal([]byte(`["e","fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"]`)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if tag1.Equals(tag3) { + t.Error("Different tags should not be equal") + } + + // Test with relay field + tag4 := New() + _, err = tag4.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef","wss://relay.example.com"]`)) + if err != nil { + t.Fatalf("Unmarshal failed: %v", err) + } + + if tag1.Equals(tag4) { + t.Error("Tags with different lengths should not be equal") + } +} + +// TestBinaryEncodingSavesSpace verifies the optimization reduces memory usage +func TestBinaryEncodingSavesSpace(t *testing.T) { + // Tag without optimization (non-hex or non e/p tag) + tagNonOpt := New() + _, _ = tagNonOpt.Unmarshal([]byte(`["t","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + nonOptSize := len(tagNonOpt.T[Value]) + + // Tag with optimization + tagOpt := New() + _, _ = tagOpt.Unmarshal([]byte(`["e","0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"]`)) + optSize := len(tagOpt.T[Value]) + + // Binary should be smaller (33 vs 64 bytes) + if optSize >= nonOptSize { + t.Errorf("Binary encoding should save space. Non-opt: %d bytes, Opt: %d bytes", nonOptSize, optSize) + } + + expectedSavings := HexEncodedLen - BinaryEncodedLen // 64 - 33 = 31 bytes + actualSavings := nonOptSize - optSize + if actualSavings != expectedSavings { + t.Errorf("Expected to save %d bytes, actually saved %d bytes", expectedSavings, actualSavings) + } + + t.Logf("Space savings: %d bytes per e/p tag value (%.1f%% reduction)", + actualSavings, float64(actualSavings)/float64(nonOptSize)*100) +}