Skip to content

Commit CRDT writes, coerce VECTOR literals, restore cluster tests - #413

Merged
farhan-syah merged 5 commits into
mainfrom
fix/small-cleanups
Oct 8, 2026
Merged

farhan-syah merged 5 commits into
mainfrom
fix/small-cleanups

Conversation

@farhan-syah

@farhan-syah farhan-syah commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

CRDT writes now commit every Loro operation and return typed client errors. VECTOR(dim) columns coerce array literals to floats, and three cluster tests return to the CI profile.

What changed

Area Change Paths
CRDT commit Add DocumentCell::mutate, which runs one local write and commits the Loro transaction, on success and on error. Route every CrdtState mutation through it. nodedb-crdt/src/state/document_cell.rs, nodedb-crdt/src/state/core.rs, nodedb-crdt/src/list_ops.rs, nodedb-crdt/src/state/
CRDT errors Add RowAbsentAtVersion, BlockListRowAbsent, BlockListPathUnresolved, BlockListNotMovable, and BlockListIndexOutOfBounds to CrdtError. Replace the CrdtError::Loro and DeltaApplyFailed strings in TenantCrdtEngine with typed variants. nodedb-crdt/src/error.rs, nodedb/src/engine/crdt/tenant_state/
Error mapping Map each CrdtError to an ErrorCode class in an exhaustive From<&CrdtError>. Add ErrorCode::UndefinedObject (42704) and ErrorCode::ObjectNotInPrerequisiteState (55000), and mirror both in DataPlaneErrorCode. nodedb/src/bridge/envelope/, nodedb-cluster/src/rpc_codec/data_plane_error.rs, nodedb/src/control/cluster/data_plane_error_wire.rs, nodedb/src/control/server/shared/ddl/sqlstate.rs, nodedb/src/error_classify/
Vector literals Coerce an array literal written to a VECTOR(dim) column to floats on the VALUES, SET, and DEFAULT paths. Refuse a non-numeric element with SqlError::VectorElementNotNumeric (42804). nodedb-sql/src/planner/declared_vector_coerce.rs, nodedb-sql/src/planner/declared_type_coerce.rs, nodedb-sql/src/error.rs
Declared type text Set ColumnInfo::raw_type in declared_column_info, so schemaless and columnar-family columns keep their VECTOR(dim) declaration. nodedb/src/control/planner/catalog_adapter/type_convert.rs, nodedb-sql/src/types/collection.rs
Calvin scheduler Move the scheduler event loop from scheduler.rs into Scheduler::run in run_loop.rs. nodedb/src/control/cluster/calvin/scheduler/driver/core/
CI profile Remove three tests from the default-filter: ollp_implicit_edge_delete_cleans_reverse_cross_node, ollp_implicit_edge_update_moves_edge_cross_node, native_implicit_edge_delete_cleans_reverse_cross_node. learner_caught_up_via_real_install_snapshot stays excluded. .config/nextest.toml
Fuzz dependencies Bump rustls to 0.23.45 (and rustls-webpki to 0.103.15) in the fuzz lockfile. The workspace lockfile already has 0.23.45. fuzz/Cargo.lock
Tests Cover SERIAL in the column list, array literals to VECTOR columns, and RESTORE ... SET VERSION on a CRDT collection in a non-default database. nodedb/tests/wire/cases/sql_serial_column_list.rs, nodedb/tests/wire/cases/sql_vector_array_literal.rs, nodedb/tests/wire/cases/crdt_restore_non_default_database.rs

Why

Symptom Cause
The restore test failed with "delta preview source has N pending operations" (SQLSTATE XX000). SQL writes to CRDT collections left Loro operations pending in the auto-commit transaction. A later preview refused the pending state.
Client mistakes on CRDT collections surfaced as XX000. crate::Error::Crdt mapped to a generic internal code, and several errors were plain strings.
Integer or decimal elements in a VECTOR array literal reached the engine untyped. The write coercion passed VECTOR(dim) through unchanged.
Dependabot flagged rustls 0.23.42 in fuzz/Cargo.lock (GHSA-2mjx-qc3c-rqvc, moderate). rustls before 0.23.45 accepts TLS 1.3 handshake messages across encryption level boundaries.
A VECTOR(dim) declaration on a schemaless or columnar-family column was lost. declared_column_info left raw_type as None.
Three cluster tests were excluded from the CI profile as hangs on CI. The hangs came from a retired Calvin scheduler spinning on a closed channel and a routing/Raft lock-order deadlock, both fixed on main. Each test passed 6/6 on ubuntu-24.04-arm and ubuntu-24.04 with no retries.

Linked issues

Issue Closed by
#306 Vector literals and declared type text rows, plus sql_vector_array_literal.rs
#319 sql_serial_column_list.rs: the behaviour already holds on main, and this PR adds the regression tests
#353 Calvin scheduler row
#379 CRDT commit row, plus crdt_restore_non_default_database.rs

Closes #306
Closes #319
Closes #353
Closes #379

Known limits

  • learner_caught_up_via_real_install_snapshot stays excluded from the CI profile. The Calvin sequencer stalls after log compaction because of the sequencer epoch seed. That work is open and outside this PR.
  • Loro cannot roll back an applied operation. A failed CrdtState mutation commits the operations it authored before the error. A caller that needs all-or-nothing captures a RowImage and calls restore_row_image on error.

How to check it

Command Result
cargo nextest run --workspace --exclude nodedb-cluster-tests --all-features --no-fail-fast --retries 0 20300 of 20300 passed
cargo nextest run -p nodedb-cluster-tests --all-features --no-fail-fast --retries 0 479 of 479 passed
cargo clippy --workspace --all-targets --all-features -- -D warnings Clean
Each script in .github/workflows/static-gates.yml Clean
cargo check --locked --bins in fuzz/ Clean

An array literal bound for a column declared VECTOR(dim) becomes an
array of floats on every write path and every engine, including
schemaless and columnar-family collections that advertise the column
as text. The declared type text is now kept on every raw DDL column so
the rule applies there. A non-numeric element is refused with
SQLSTATE 42804 naming the column.
Narrow the CI nextest exclusion to the one cluster test that still
fails there and document its cause.
A CRDT error now takes the Data-Plane error code of its cause instead
of reading as a server fault. The SQLSTATE, public error class, and
cluster wire form follow that code, and only a Loro fault stays
internal. Add UndefinedObject and ObjectNotInPrerequisiteState to the
exhaustive error-code matches.
rustls before 0.23.45 accepts TLS 1.3 handshake messages across
encryption level boundaries (GHSA-2mjx-qc3c-rqvc). Update the fuzz
lockfile to the patched release, along with rustls-webpki and the
other transitive updates the resolver pulled in.
@farhan-syah farhan-syah added the run-ci Opt this PR into the full test suite; re-add to force a re-run label Oct 8, 2026
@farhan-syah
farhan-syah merged commit 27e29aa into main Oct 8, 2026
14 checks passed
@farhan-syah
farhan-syah deleted the fix/small-cleanups branch October 8, 2026 23:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-ci Opt this PR into the full test suite; re-add to force a re-run

Projects

None yet

1 participant