Skip to content

53 increase csv ingest speed#54

Open
wmehling wants to merge 5 commits into
mainfrom
53-increase-csv-ingest-speed
Open

53 increase csv ingest speed#54
wmehling wants to merge 5 commits into
mainfrom
53-increase-csv-ingest-speed

Conversation

@wmehling

@wmehling wmehling commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Increased CSV Ingest from ~400k Tokens/s to ~ 800k Tokens/s

Depends on #51 / Builds on branch, so review #52 first

The optimization was split into three commits so each idea remains independently reviewable, benchmarkable, and revertible:

  1. Column-major row groups: CSV rows are collected in bounded groups of 1,000 and emitted column by column. Creates consecutive tuples with the same item/property/context. Throughput increased from the baseline 391.7k/502.7k tuples/s to **528.0k/561.1k tuples/**s in two independent runs.

  2. Prefix and lock reuse: The LevelDB batch writer reuses the resolved prefix and lock for consecutive tuples with the same identity. Throughput increased further to 602.9k/635.9k tuples/s.

  3. Bounded parser/storage overlap: One task parses CSV row groups while the request thread stores them through a bounded two-group queue. Final endpoint throughput reached 851.9k tuples/s in Run A and 694.7k tuples/s in Run B.

The existing row-major parse() API and read path remain unchanged; only the optimized ingestion route uses column-major ordering within each bounded group.

wmehling added 4 commits July 17, 2026 15:42
- Implement KvinIngestionCsvDiagnosticBenchmark for performance testing of CSV ingestion.
- Create KvinIngestionJsonDiagnosticBenchmark for benchmarking JSON ingestion.
- Introduce KvinIngestionWorkload to generate test data for benchmarks.
- Add unit tests for KvinIngestionCsvDiagnosticBenchmark and KvinIngestionWorkload.
- Remove obsolete KvinServiceBenchmark Scala file.
- Document benchmark setup and execution in markdown format.
Keep the existing row-major CsvFormatParser.parse() contract, and add a bounded 1000-row column-major iterator for CSV ingestion. The service feeds that iterator through one KVIN iterable write, preserving one request-level batch while improving locality. Listener encounter order within each group is intentionally column-major.

JMH 30,000 tuples, JDK 21.0.11, 3 warmups, 5 measurements, 2 forks, 1 thread: postCsv A 76.581 -> 56.823 ms/op (392k -> 528k tuples/s, 25.8% faster); B 59.683 -> 53.465 ms/op (503k -> 561k, 10.4% faster). putCsvGrouped: A 45.397 ms/op (661k/s); B 48.841 ms/op (614k/s). CSV diagnostics A/B were also captured under .cache-main/benchmarks.
Cache the last item/property/context prefix and its striped lock inside KvinLevelDb.put(Iterable). The cache is invalidated naturally whenever tuple identity changes; key encoding, fetch behavior, batching, and listener APIs are unchanged.

JMH 30,000 tuples, JDK 21.0.11, 3 warmups, 5 measurements, 2 forks, 1 thread, incremental over a9f5a0d: postCsv A 56.823 -> 49.763 ms/op (528k -> 603k tuples/s, 12.4% faster); B 53.465 -> 47.179 ms/op (561k -> 636k, 11.8% faster). LevelDB KvinLevelDbTest: 7 passed.
Parse 1,000-row column-major groups on the shared executor while one iterable LevelDB write drains a two-group queue. Keep benchmark controls for direct overlap and shared-store concurrency, and record paired A/B results and read-contention caveats.
@wmehling wmehling linked an issue Jul 17, 2026 that may be closed by this pull request

@kenwenzel kenwenzel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The CsvIngestionPipeline could in general also be used by other formats and there be generalized. Furthermore, a lock-free communication can be faster especially for smaller batch sizes.

}

IExtendedIterator<List<KvinTuple>> groups = parser.parseRowGroupBatches(rowsPerGroup);
BlockingQueue<Object> queue = new ArrayBlockingQueue<>(queueCapacity);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is slower than using a CircularBuffer and Thread.onSpinWait() that allows to lock-free send data between too threads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Increase CSV Ingest speed

2 participants