mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-12 09:13:23 +00:00
relayBench measures relay-to-relay reconcile, not the amy/quartz client feature, so the deletion-settle perf claim belongs in an in-process benchmark of negentropySettleDeletions itself. Models the post-content-settle state: a relay with N notes, a local store with the same N except K it deleted (keeping the K kind-5s). The reconcile residual is exactly those K, so a sendUp settle fetches K — not N. Asserts residual==K, sentUp==K, and relay convergence (correctness guard at the small default N), and prints one-reconcile vs full-settle so the deletion overhead reads as "a few reconciles + K", never "+ a content re-download". Measured: N=2000 K=20: settle ~2x one reconcile, fetched K=20 not N N=100000 K=20: settle ~5x one reconcile, fetched K=20 not N=100000 The growth is the relay rebuilding its negentropy index after the deletions (O(N) once) — inherent to applying deletions, and still far cheaper than re-fetching the need set, which the old per-need-fetch approach did. Scale with -DdelBenchN / -DdelBenchK (forwarded by the geode test task). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JgL1WTV4Hkp2uuXcUHCHGt
140 lines
5.6 KiB
Kotlin
140 lines
5.6 KiB
Kotlin
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
|
|
plugins {
|
|
alias(libs.plugins.jetbrainsKotlinJvm)
|
|
alias(libs.plugins.serialization)
|
|
application
|
|
`java-test-fixtures`
|
|
}
|
|
|
|
application {
|
|
mainClass.set("com.vitorpamplona.geode.MainKt")
|
|
applicationName = "geode"
|
|
}
|
|
|
|
kotlin {
|
|
jvmToolchain(21)
|
|
compilerOptions {
|
|
jvmTarget.set(JvmTarget.JVM_21)
|
|
}
|
|
}
|
|
|
|
// Generate a BuildConfig.kt carrying the app version from the catalog so
|
|
// RelayInfo.VERSION (reported over NIP-11) tracks releases automatically
|
|
// instead of being a hand-bumped literal.
|
|
val generateVersionFile by tasks.registering {
|
|
val versionValue = libs.versions.app.get()
|
|
val outDir = layout.buildDirectory.dir("generated/version/kotlin")
|
|
inputs.property("version", versionValue)
|
|
outputs.dir(outDir)
|
|
doLast {
|
|
val file = outDir.get().file("com/vitorpamplona/geode/BuildConfig.kt").asFile
|
|
file.parentFile.mkdirs()
|
|
file.writeText(
|
|
buildString {
|
|
appendLine("// Generated by the :geode build — do not edit.")
|
|
appendLine("package com.vitorpamplona.geode")
|
|
appendLine()
|
|
appendLine("internal object BuildConfig {")
|
|
appendLine(" const val VERSION = \"$versionValue\"")
|
|
appendLine("}")
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
sourceSets {
|
|
main {
|
|
kotlin.srcDir("src/main/kotlin")
|
|
kotlin.srcDir(generateVersionFile)
|
|
}
|
|
test {
|
|
kotlin.srcDir("src/test/kotlin")
|
|
}
|
|
// The `java-test-fixtures` plugin auto-creates a `testFixtures`
|
|
// source set; we just point it at our Kotlin layout so the
|
|
// `geode.fixtures` (synthetic events) and `geode.testing`
|
|
// (RelayClientTest, collectUntilEose) packages don't ship in
|
|
// production jars but are still usable by every consumer's test
|
|
// source via `testImplementation(testFixtures(project(":geode")))`.
|
|
named("testFixtures") {
|
|
kotlin.srcDir("src/testFixtures/kotlin")
|
|
}
|
|
}
|
|
|
|
tasks.withType<Test>().configureEach {
|
|
// Forward `-DrunLoadBenchmark=true` to the test JVM so the
|
|
// perf.LoadBenchmark tests opt in. Off by default — load tests
|
|
// are noisy and slow.
|
|
systemProperty("runLoadBenchmark", System.getProperty("runLoadBenchmark") ?: "false")
|
|
System.getProperty("fanoutScalingEvents")?.let { systemProperty("fanoutScalingEvents", it) }
|
|
System.getProperty("fanoutScalingSubs")?.let { systemProperty("fanoutScalingSubs", it) }
|
|
// NegentropyServerReconcileBenchmark opt-in + sizing.
|
|
System.getProperty("negServerBench")?.let { systemProperty("negServerBench", it) }
|
|
System.getProperty("negBenchN")?.let { systemProperty("negBenchN", it) }
|
|
// DeletionSettleBenchmark sizing.
|
|
System.getProperty("delBenchN")?.let { systemProperty("delBenchN", it) }
|
|
System.getProperty("delBenchK")?.let { systemProperty("delBenchK", it) }
|
|
// MirrorSyncThroughputTest sizing + external-source opt-in.
|
|
System.getProperty("syncN")?.let { systemProperty("syncN", it) }
|
|
System.getProperty("syncExpect")?.let { systemProperty("syncExpect", it) }
|
|
System.getProperty("syncSourceUrl")?.let { systemProperty("syncSourceUrl", it) }
|
|
System.getProperty("syncLiveIndex")?.let { systemProperty("syncLiveIndex", it) }
|
|
System.getProperty("syncBackfillSeconds")?.let { systemProperty("syncBackfillSeconds", it) }
|
|
System.getProperty("syncFts")?.let { systemProperty("syncFts", it) }
|
|
System.getProperty("syncVerify")?.let { systemProperty("syncVerify", it) }
|
|
maxHeapSize = System.getProperty("testHeap") ?: maxHeapSize
|
|
// Opt-in JFR profiling (-PnegProfile=/tmp/neg.jfr).
|
|
(project.findProperty("negProfile") as? String)?.let {
|
|
jvmArgs("-XX:+FlightRecorder", "-XX:StartFlightRecording=filename=$it,settings=profile,dumponexit=true")
|
|
}
|
|
// Show println output from test JVM so the benchmark numbers are
|
|
// actually visible without grepping the report XML.
|
|
testLogging {
|
|
showStandardStreams =
|
|
(System.getProperty("runLoadBenchmark") == "true") ||
|
|
(System.getProperty("negServerBench") == "1")
|
|
events("standard_out")
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
api(project(":quartz"))
|
|
|
|
implementation(libs.kotlinx.coroutines.core)
|
|
implementation(libs.jackson.module.kotlin)
|
|
implementation(libs.kotlinx.serialization.json)
|
|
|
|
// Outbound WebSockets for the [[mirror]] upstream streams (quartz's
|
|
// BasicOkHttpWebSocket transport). Same OkHttp the rest of the repo
|
|
// already ships (Apache-2.0).
|
|
implementation(libs.okhttp)
|
|
|
|
// Bundled SQLite driver — Relay's default in-memory EventStore creates
|
|
// an in-memory DB at runtime.
|
|
implementation(libs.androidx.sqlite.bundled.jvm)
|
|
|
|
// Ktor server engine + WebSocket plugin so Relay can serve real ws://
|
|
// traffic. CIO is the coroutine-based engine — lighter than Netty.
|
|
api(libs.ktor.server.core)
|
|
api(libs.ktor.server.cio)
|
|
api(libs.ktor.server.websockets)
|
|
|
|
// TOML parsing for the operator config file. Mirrors the section
|
|
// layout of nostr-rs-relay's config.toml so existing operators can
|
|
// port their configs nearly verbatim.
|
|
implementation(libs.fourkoma)
|
|
|
|
// testFixtures: code in src/testFixtures/kotlin (RelayClientTest +
|
|
// synthetic event builders). Not shipped in the production jar but
|
|
// exposed to consumers via testImplementation(testFixtures(...)).
|
|
testFixturesApi(project(":quartz"))
|
|
testFixturesApi(libs.junit)
|
|
testFixturesImplementation(libs.kotlinx.coroutines.core)
|
|
|
|
testImplementation(libs.kotlin.test)
|
|
testImplementation(libs.kotlinx.coroutines.test)
|
|
testImplementation(libs.secp256k1.kmp.jni.jvm)
|
|
testImplementation(libs.okhttp)
|
|
}
|