Skip to content

ChronoSQL: SQL-style plugin for ChronoLog (#354)#629

Open
iameneko wants to merge 6 commits intodevelop-3.xfrom
feature/354-chronosql-plugin
Open

ChronoSQL: SQL-style plugin for ChronoLog (#354)#629
iameneko wants to merge 6 commits intodevelop-3.xfrom
feature/354-chronosql-plugin

Conversation

@iameneko
Copy link
Copy Markdown
Contributor

@iameneko iameneko commented Apr 30, 2026

Closes #354.

This adds ChronoSQL, a new client-side plugin that lets you talk to ChronoLog using a SQL-shaped interface aimed at YCSB-style workloads. It maps databases to chronicles, tables to stories, and rows to events whose payload is a JSON object of column values; schema state lives in a reserved metadata story that gets replayed on first use, so we don't depend on chronicle attrs or ShowStories (which aren't reliable yet). The plugin sits entirely on top of the existing client API — no client changes needed — and constructors follow the same pattern as chronokvs so it can target distributed deployments via a JSON config.

The SQL surface is intentionally small: CREATE/DROP TABLE, INSERT, and SELECT with either an equality filter or a __ts BETWEEN range that lowers to ReplayStory. Joins, aggregates, ORDER BY, LIMIT, and INSERT-time type checking are explicitly out of scope for v0.1, and DROP TABLE only removes the metadata mapping since the underlying event log is append-only. Coverage includes unit tests for the parser, row codec, and metadata replay, a config-loading test, and a manual integration test that exercises the full YCSB-shaped path against a live stack.

ChronoSQL is a new client-side plugin that exposes chronicles and stories
through a SQL-shaped interface targeting YCSB-compatible workloads. No
client changes are required; the plugin is built entirely on top of the
existing ChronoLog client API.

Storage model:
  - database  ↔ chronicle (ChronoSQLChronicle by default)
  - table     ↔ story (one per table)
  - row       ↔ event whose log_record is a JSON object of column values
  - schema/table-list ↔ a reserved __chronosql_metadata story whose events
    encode CREATE/DROP operations and are replayed on first use

Two coupled APIs:
  - Programmatic: createTable / dropTable / listTables / insert /
    selectByKey / selectRange / selectAll
  - SQL string facade: ChronoSQL::execute(sql) parses a YCSB-shaped subset
    (CREATE TABLE, DROP TABLE, INSERT, SELECT with WHERE col=val or
    WHERE __ts BETWEEN n AND n) via a hand-rolled tokenizer + recursive
    descent parser

The implicit __ts pseudo-column maps directly to the ChronoLog event
timestamp and lowers __ts BETWEEN to ReplayStory ranges.

Constructors mirror the chronokvs pattern: default + (config_path) so the
plugin can target distributed deployments via a ChronoLog client config
file. Failures to load the config throw std::runtime_error before any
RPC connection is attempted.

Tests:
  - chronosql_unit_test: 27 cases covering parser, JSON row codec, and
    metadata replay/idempotency
  - chronosql_config_test: throws on missing/section-less config files
  - chronosql_integration_test: MANUAL TRUE end-to-end YCSB-shaped workload
    (CREATE TABLE / INSERT x100 / SELECT * / SELECT WHERE = / SELECT WHERE
    __ts BETWEEN); not run in CI

Examples:
  - chrono-chronosql-example-writer / -reader, both accept --config/-c
@iameneko iameneko added Plugins Cross-cutting work on the serving/plugin layer (ChronoKVS, ChronoSQL, ChronoPubSub, etc.) Testing Test infrastructure, coverage, fixtures, end-to-end and unit tests labels Apr 30, 2026
@iameneko iameneko self-assigned this Apr 30, 2026
@iameneko iameneko linked an issue May 5, 2026 that may be closed by this pull request
iameneko added 2 commits May 5, 2026 16:52
The integration test aborted in CI because ChronoSQL's first call after
construction is a read (getSchema), which triggers a replay of the
__chronosql_metadata story. On a fresh deployment that story has no
events yet, the player never marks the query complete, and the client
hits its 180s replay timeout (CL_ERR_QUERY_TIMED_OUT). The exception
propagated past main() and the process was reported as Subprocess
aborted.

- Add a tolerate_timeout flag to ChronoSQLClientAdapter::replayEvents.
  When set, CL_ERR_QUERY_TIMED_OUT is logged as a warning and the call
  returns an empty event list. Used only for the metadata replay path,
  so data-story replays still surface real failures.
- Bump the integration test's post-INSERT propagation wait from 2s to
  120s, matching the ChronoKVS integration test. The previous wait was
  not long enough for the player to make events visible.
- Wrap main() in try/catch so connection failures exit cleanly (test
  treated as skipped, mirroring ChronoKVS) and other exceptions return
  EXIT_FAILURE instead of aborting the subprocess.
The first replay against an unwritten story blocks for the player's
hardcoded 180s replay-timeout before returning, and the test then waits
120s for data propagation before the SELECT roundtrips. The previous
300s ctest timeout was too tight and the test was killed mid-run.
@iameneko iameneko changed the title feat(chronosql): add SQL-style plugin for ChronoLog (#354) ChronoSQL: SQL-style plugin for ChronoLog (#354) May 5, 2026
iameneko and others added 3 commits May 5, 2026 14:09
Mirror the chronokvs follow-up to PR #628: confManager is a remnant of
the old ConfigurationManager class. Use a clearer client-facing name.
…te() factory

Mirror the chronokvs follow-up to PR #628: throwing exceptions across a
client-library boundary forces callers to wrap construction in try/catch
without an obvious set of exception types to catch. Convert the public
ChronoSQL API to a factory pattern instead:

- Make ChronoSQL constructors private.
- Add static std::unique_ptr<ChronoSQL> Create(...) noexcept overloads
  that catch any construction-path exception, log it via the configured
  log level, and return nullptr to signal failure.
- Update examples, integration test, and unit tests to use the factory
  and check for nullptr instead of catching std::runtime_error.

Internal layers (ChronoSQLMapper, ChronoSQLClientAdapter) keep using
exceptions for clarity; they are now caught at the library boundary
inside Create() rather than escaping to user code.
@iameneko iameneko marked this pull request as ready for review May 5, 2026 20:07
@iameneko iameneko requested review from fkengun and ibrodkin May 5, 2026 20:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Plugins Cross-cutting work on the serving/plugin layer (ChronoKVS, ChronoSQL, ChronoPubSub, etc.) Testing Test infrastructure, coverage, fixtures, end-to-end and unit tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ChronoSQL Plugin

1 participant