Skip to content

Commit fc7dd9a

Browse files
committed
Fix InfluxDB concurrent reads and MongoDB benchmark hosts
Snapshot each completed InfluxDB WAL file through the native persistence path so concurrent point queries do not materialize the entire million-record mutable buffer. Extend the existing real million-record control with sixteen independently owned concurrent readers. Use the Ubuntu 22.04 family consistently for benchmark preparation and workers to retain a kernel supported by the pinned MongoDB image, and record actual host/Docker kernels. Verified: strict Debug comparison-host build, real 1M-record control failed before and passed after with all sixteen bodies checked and physical container/volume cleanup, complete-solution formatting, repository governance, actionlint and diff whitespace checks. Complete solution checks and full Linux session qualification remain pending at this checkpoint. KeyLoad runtime and adapter sources are unchanged.
1 parent fc4fc00 commit fc7dd9a

7 files changed

Lines changed: 73 additions & 24 deletions

File tree

‎.github/workflows/Features/BenchmarkComparisons/SessionSetup/action.yml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ runs:
2323
shell: bash
2424
run: |
2525
docker version
26+
uname -a
27+
docker info --format 'Docker kernel: {{.KernelVersion}}'
2628
sudo sysctl -w vm.max_map_count=262144
2729
- name: Verify this GitHub session job
2830
shell: bash

‎.github/workflows/benchmarks.yml‎

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
comparison-runtime:
2020
name: Prepare comparison runtime
2121
if: github.repository == 'managedcode/KeyLoad' && github.ref == 'refs/heads/main'
22-
runs-on: ubuntu-24.04
22+
runs-on: ubuntu-22.04
2323
timeout-minutes: 150
2424
permissions: {contents: read, actions: read, packages: read}
2525
outputs:
@@ -71,7 +71,10 @@ jobs:
7171
if-no-files-found: error
7272
retention-days: 90
7373
- name: Check Docker
74-
run: docker version
74+
run: |
75+
docker version
76+
uname -a
77+
docker info --format 'Docker kernel: {{.KernelVersion}}'
7578
- name: Resolve the latest released KeyLoad server image to one digest
7679
id: keyload-image
7780
if: (github.event_name == 'push' || inputs.mode == 'full')
@@ -137,7 +140,7 @@ jobs:
137140
name: ${{ matrix.jobName }}
138141
if: (github.event_name == 'push' || inputs.mode == 'full')
139142
needs: [comparison-runtime]
140-
runs-on: ubuntu-24.04
143+
runs-on: ubuntu-22.04
141144
timeout-minutes: 240
142145
permissions: {contents: read, actions: read, packages: read}
143146
strategy:
@@ -190,7 +193,7 @@ jobs:
190193
name: ${{ matrix.jobName }}
191194
if: (github.event_name == 'push' || inputs.mode == 'full')
192195
needs: [comparison-runtime]
193-
runs-on: ubuntu-24.04
196+
runs-on: ubuntu-22.04
194197
timeout-minutes: 240
195198
strategy:
196199
fail-fast: false
@@ -201,7 +204,7 @@ jobs:
201204
name: ${{ matrix.jobName }}
202205
if: (github.event_name == 'push' || inputs.mode == 'full')
203206
needs: [comparison-runtime]
204-
runs-on: ubuntu-24.04
207+
runs-on: ubuntu-22.04
205208
timeout-minutes: 240
206209
strategy:
207210
fail-fast: false
@@ -212,7 +215,7 @@ jobs:
212215
name: ${{ matrix.jobName }}
213216
if: (github.event_name == 'push' || inputs.mode == 'full')
214217
needs: [comparison-runtime]
215-
runs-on: ubuntu-24.04
218+
runs-on: ubuntu-22.04
216219
timeout-minutes: 240
217220
strategy:
218221
fail-fast: false
@@ -223,7 +226,7 @@ jobs:
223226
name: ${{ matrix.jobName }}
224227
if: (github.event_name == 'push' || inputs.mode == 'full')
225228
needs: [comparison-runtime]
226-
runs-on: ubuntu-24.04
229+
runs-on: ubuntu-22.04
227230
timeout-minutes: 240
228231
strategy:
229232
fail-fast: false
@@ -234,7 +237,7 @@ jobs:
234237
name: ${{ matrix.jobName }}
235238
if: (github.event_name == 'push' || inputs.mode == 'full')
236239
needs: [comparison-runtime]
237-
runs-on: ubuntu-24.04
240+
runs-on: ubuntu-22.04
238241
timeout-minutes: 240
239242
strategy:
240243
fail-fast: false
@@ -245,7 +248,7 @@ jobs:
245248
name: ${{ matrix.jobName }}
246249
if: (github.event_name == 'push' || inputs.mode == 'full')
247250
needs: [comparison-runtime]
248-
runs-on: ubuntu-24.04
251+
runs-on: ubuntu-22.04
249252
timeout-minutes: 240
250253
strategy:
251254
fail-fast: false
@@ -256,7 +259,7 @@ jobs:
256259
name: ${{ matrix.jobName }}
257260
if: (github.event_name == 'push' || inputs.mode == 'full')
258261
needs: [comparison-runtime]
259-
runs-on: ubuntu-24.04
262+
runs-on: ubuntu-22.04
260263
timeout-minutes: 240
261264
strategy:
262265
fail-fast: false
@@ -267,7 +270,7 @@ jobs:
267270
name: ${{ matrix.jobName }}
268271
if: (github.event_name == 'push' || inputs.mode == 'full')
269272
needs: [comparison-runtime]
270-
runs-on: ubuntu-24.04
273+
runs-on: ubuntu-22.04
271274
timeout-minutes: 240
272275
strategy:
273276
fail-fast: false
@@ -278,7 +281,7 @@ jobs:
278281
name: ${{ matrix.jobName }}
279282
if: (github.event_name == 'push' || inputs.mode == 'full')
280283
needs: [comparison-runtime]
281-
runs-on: ubuntu-24.04
284+
runs-on: ubuntu-22.04
282285
timeout-minutes: 240
283286
strategy:
284287
fail-fast: false
@@ -289,7 +292,7 @@ jobs:
289292
name: ${{ matrix.jobName }}
290293
if: (github.event_name == 'push' || inputs.mode == 'full')
291294
needs: [comparison-runtime]
292-
runs-on: ubuntu-24.04
295+
runs-on: ubuntu-22.04
293296
timeout-minutes: 240
294297
strategy:
295298
fail-fast: false
@@ -300,7 +303,7 @@ jobs:
300303
name: ${{ matrix.jobName }}
301304
if: (github.event_name == 'push' || inputs.mode == 'full')
302305
needs: [comparison-runtime]
303-
runs-on: ubuntu-24.04
306+
runs-on: ubuntu-22.04
304307
timeout-minutes: 240
305308
strategy:
306309
fail-fast: false
@@ -311,7 +314,7 @@ jobs:
311314
name: ${{ matrix.jobName }}
312315
if: (github.event_name == 'push' || inputs.mode == 'full')
313316
needs: [comparison-runtime]
314-
runs-on: ubuntu-24.04
317+
runs-on: ubuntu-22.04
315318
timeout-minutes: 240
316319
strategy:
317320
fail-fast: false
@@ -322,7 +325,7 @@ jobs:
322325
name: ${{ matrix.jobName }}
323326
if: (github.event_name == 'push' || inputs.mode == 'full')
324327
needs: [comparison-runtime]
325-
runs-on: ubuntu-24.04
328+
runs-on: ubuntu-22.04
326329
timeout-minutes: 240
327330
strategy:
328331
fail-fast: false
@@ -333,7 +336,7 @@ jobs:
333336
name: ${{ matrix.jobName }}
334337
if: (github.event_name == 'push' || inputs.mode == 'full')
335338
needs: [comparison-runtime]
336-
runs-on: ubuntu-24.04
339+
runs-on: ubuntu-22.04
337340
timeout-minutes: 240
338341
strategy:
339342
fail-fast: false
@@ -344,7 +347,7 @@ jobs:
344347
name: ${{ matrix.jobName }}
345348
if: (github.event_name == 'push' || inputs.mode == 'full')
346349
needs: [comparison-runtime]
347-
runs-on: ubuntu-24.04
350+
runs-on: ubuntu-22.04
348351
timeout-minutes: 240
349352
strategy:
350353
fail-fast: false
@@ -355,7 +358,7 @@ jobs:
355358
name: Combine benchmark results
356359
needs: [comparison-runtime, comparison-keyload, comparison-postgresql, comparison-qdrant, comparison-rabbitmq, comparison-redis, comparison-neo4j, comparison-mongodb, comparison-opensearch, comparison-kurrentdb, comparison-surrealdb, comparison-helixdb, comparison-timescaledb, comparison-sqlserver, comparison-mysql, comparison-clickhouse, comparison-influxdb]
357360
if: ${{ always() && !cancelled() && (github.event_name == 'push' || inputs.mode == 'full') && needs.comparison-runtime.result == 'success' }}
358-
runs-on: ubuntu-24.04
361+
runs-on: ubuntu-22.04
359362
timeout-minutes: 150
360363
env:
361364
GH_TOKEN: ${{ github.token }}
@@ -392,7 +395,7 @@ jobs:
392395
(github.event_name == 'push' || inputs.mode == 'full') &&
393396
github.repository == 'managedcode/KeyLoad' && github.event.repository.id == 477801965 &&
394397
github.ref == 'refs/heads/main'
395-
runs-on: ubuntu-24.04
398+
runs-on: ubuntu-22.04
396399
timeout-minutes: 5
397400
permissions: {actions: write}
398401
env:

‎benchmarks/KeyLoad.ComparisonHost/DatabaseAdapters/Cases/InfluxDocumentReadback.cs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal static async Task VerifyAsync(IComparisonTarget target, CancellationTok
1919
.Select(index => index == Updated ? corpus.Replacement(index) : corpus.CreateDocument(index));
2020
var observed = await DocumentComparisonOracle.VerifyAsync(independent.ReadDocumentsAsync(token), expected, token);
2121
await Assert.That(observed.Records).IsEqualTo(Records);
22+
await ReadConcurrentlyAsync(documents, corpus, token);
2223
using var cancelled = CancellationTokenSource.CreateLinkedTokenSource(token);
2324
await using (var cursor = independent.ReadDocumentsAsync(cancelled.Token).GetAsyncEnumerator(cancelled.Token))
2425
{
@@ -30,4 +31,21 @@ internal static async Task VerifyAsync(IComparisonTarget target, CancellationTok
3031
await Assert.That(BenchmarkDataset.SameDocument((await independent.ReadAsync(corpus.CreateDocument(Records), token)).Value,
3132
corpus.CreateDocument(Records))).IsTrue();
3233
}
34+
35+
private static async Task ReadConcurrentlyAsync(IDocumentComparisonTarget target, DocumentComparisonCorpus corpus,
36+
CancellationToken token)
37+
{
38+
const int StableStart = 200_000;
39+
var start = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
40+
var clients = Enumerable.Range(Empty, Clients).Select(async client =>
41+
{
42+
await using var session = await target.OpenDocumentSessionAsync(token);
43+
await start.Task;
44+
var document = corpus.CreateDocument(StableStart + client);
45+
var observed = await session.ReadAsync(document, token);
46+
await Assert.That(BenchmarkDataset.SameDocument(observed.Value, document)).IsTrue();
47+
}).ToArray();
48+
start.SetResult();
49+
await Task.WhenAll(clients);
50+
}
3351
}

‎build/KeyLoad.LoadTests.AppHost/Configuration/BenchmarkDeploymentOptions.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ internal sealed record BenchmarkDeploymentOptions
1010
private const int DefaultNeo4jPageCache = 256;
1111
private const int DefaultOpenSearchHeap = 1024;
1212
private const int DefaultInfluxQueryMemoryPercent = 70;
13+
private const int DefaultInfluxWalFilesPerSnapshot = 1;
14+
private const int MaximumInfluxWalFilesPerSnapshot = 600;
1315
private const int MaximumQueryMemoryPercent = 90;
1416
private const int DefaultPostgresSlotRetention = 512;
1517
private const int DefaultDocumentPostgresConnections = 512;
@@ -24,12 +26,14 @@ internal sealed record BenchmarkDeploymentOptions
2426
public int Neo4jPageCacheMegabytes { get; init; } = DefaultNeo4jPageCache;
2527
public int OpenSearchHeapMegabytes { get; init; } = DefaultOpenSearchHeap;
2628
public int InfluxQueryMemoryPercent { get; init; } = DefaultInfluxQueryMemoryPercent;
29+
public int InfluxWalFilesPerSnapshot { get; init; } = DefaultInfluxWalFilesPerSnapshot;
2730
public int PostgresSlotWalRetentionMegabytes { get; init; } = DefaultPostgresSlotRetention;
2831
public int DocumentPostgresMaximumConnections { get; init; } = DefaultDocumentPostgresConnections;
2932
internal bool IsValid() => DocumentPostgresMaximumConnections is >= MinimumDocumentPostgresConnections and <= MaximumDocumentPostgresConnections
3033
&& ValidMemory(Neo4jInitialHeapMegabytes) && ValidMemory(Neo4jMaximumHeapMegabytes)
3134
&& Neo4jInitialHeapMegabytes <= Neo4jMaximumHeapMegabytes && ValidMemory(Neo4jPageCacheMegabytes)
3235
&& ValidMemory(OpenSearchHeapMegabytes) && InfluxQueryMemoryPercent is >= 1 and <= MaximumQueryMemoryPercent
36+
&& InfluxWalFilesPerSnapshot is >= 1 and <= MaximumInfluxWalFilesPerSnapshot
3337
&& PostgresSlotWalRetentionMegabytes is >= 1 and <= MaximumWalMegabytes;
3438
private static bool ValidMemory(int value) => value is >= 1 and <= MaximumMemoryMegabytes;
3539
}

‎build/KeyLoad.LoadTests.AppHost/Resources/Additional/AdditionalHttpResources.cs‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,13 @@ private static void AddInflux(IsolatedResourceContext context)
5353
const string Serve = "serve", NodeId = "--node-id=benchmark", Store = "--object-store=file";
5454
const string Directory = "--data-dir=" + Mount, Bind = "--http-bind=0.0.0.0:8181", Auth = "--without-auth";
5555
const string QueryMemory = "--exec-mem-pool-size=", Percent = "%";
56+
const string SnapshotFiles = "--wal-files-per-snapshot=";
5657
var deployment = LoadTestsOptionsRegistration.Get(context.Builder).Deployment.Value;
5758
var queryMemory = QueryMemory + deployment.InfluxQueryMemoryPercent.ToString(CultureInfo.InvariantCulture) + Percent;
59+
var snapshotFiles = SnapshotFiles + deployment.InfluxWalFilesPerSnapshot.ToString(CultureInfo.InvariantCulture);
5860
var node = context.Builder.AddContainer(Influx, BenchmarkAdditionalImages.InfluxImage, BenchmarkAdditionalImages.InfluxTag)
5961
.WithImageSHA256(BenchmarkAdditionalImages.InfluxDigest[BenchmarkAdditionalImages.DigestPrefixLength..])
60-
.WithArgs(Serve, NodeId, Store, Directory, Bind, Auth, queryMemory).WithVolume(target: Mount)
62+
.WithArgs(Serve, NodeId, Store, Directory, Bind, Auth, queryMemory, snapshotFiles).WithVolume(target: Mount)
6163
.WithHttpEndpoint(targetPort: InfluxPort, name: Http).WithHttpHealthCheck(Ready);
6264
context.BindEndpoint(EndpointIndex, node, Http);
6365
context.BindImage(Docker + BenchmarkAdditionalImages.InfluxImage + Separator + BenchmarkAdditionalImages.InfluxTag + DigestSeparator + BenchmarkAdditionalImages.InfluxDigest);

‎docs/Features/BenchmarkComparisons/AdditionalDatabases.md‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ JSON row, and the frozen corpus identity capacity bounds the total row count.
3333
The existing operation deadline bounds response headers and each read's idle wait;
3434
caller cancellation also stops buffered delivery. The independent ordered oracle
3535
still checks every identity, full body and digest. The native million-record
36-
control also exercises an update, cancellation during readback and a healthy write
37-
and read afterward. The vendor documents
36+
control also exercises an update, sixteen independent concurrent point reads after
37+
the complete readback, cancellation during readback and a healthy write and read
38+
afterward. The vendor documents
3839
[JSONL as its streaming HTTP query format](https://docs.influxdata.com/influxdb3/core/query-data/execute-queries/influxdb-v3-api/).
3940

4041
The typed deployment policy assigns InfluxDB's query execution pool 70% of the
@@ -44,6 +45,15 @@ This changes the engine's internal pool ceiling, not the runner's CPU or RAM.
4445
The native million-record check retains failures from sorting or deduplication;
4546
query memory errors remain failures.
4647

48+
InfluxDB snapshots each completed WAL file through its native
49+
[`wal-files-per-snapshot` setting](https://docs.influxdata.com/influxdb3/core/reference/config-options/#wal-files-per-snapshot).
50+
The default 600-file interval otherwise leaves this short million-record load in
51+
the mutable buffer: the pinned engine materializes that buffer while planning
52+
each query, so sixteen point reads can simultaneously copy the complete corpus.
53+
Native snapshots make Parquet available during the load and bound this planning
54+
pressure. The line protocol, `no_sync=false` acknowledgement, independent clients,
55+
operation deadlines and complete result checks stay the same.
56+
4757
## Deployment and qualification limits
4858

4959
The added native deployments currently implement one node. TimescaleDB, SQL Server,
@@ -57,6 +67,15 @@ replicas.
5767
Aspire owns the official pinned container images, anonymous session volumes,
5868
readiness and joined cleanup. Native SQL readiness opens a real provider
5969
connection and executes `SELECT 1`; HTTP targets use their server health endpoints.
70+
The complete Benchmarks workflow uses the Ubuntu 22.04 runner family so preparation
71+
and every worker share one declared OS baseline. Its published kernel is 6.8;
72+
MongoDB's native startup guard rejects kernels 6.19 through 7.0.13 because of its
73+
TCMalloc dependency. Preparation and worker logs record the actual host and Docker
74+
kernels. The pinned MongoDB image and its startup guard are unchanged. Actual
75+
kernel, CPU and memory evidence still determines resource equivalence; a common
76+
runner label alone does not qualify figures. See the
77+
[runner image inventory](https://github.com/actions/runner-images/blob/main/images/ubuntu/Ubuntu2204-Readme.md)
78+
and [MongoDB's kernel requirement](https://www.mongodb.com/docs/manual/release-notes/8.0/).
6079
SQL Server uses Developer edition for nonproduction benchmarks and requires the
6180
Linux x86-64 runner. Its local execution on ARM is not qualified.
6281

‎docs/Features/BenchmarkComparisons/SessionExecution.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ matrix, restarts or separate benchmark scenario.
158158
OpenSearch controls cover one million actual documents per topology. The HelixDB
159159
and ClickHouse controls also load one million documents and build the session indexes before
160160
mutations and complete readback. InfluxDB's million-record control verifies its
161-
native JSONL readback, an update, cancellation during streaming and healthy
161+
native JSONL readback, an update, sixteen concurrent point readers, cancellation
162+
during streaming and healthy
162163
continuation. The eight-control run has a 40-minute timeout;
163164
each operation keeps its 30-second deadline and document cleanup keeps its
164165
20-minute deadline. All native

0 commit comments

Comments
 (0)