Warning

This is not authoritative documentation. It describes a plan of work that is not yet implemented and will change as it lands.

Task 4: cursor read and write paths, autocommit, primary key only

Repo: https://opendev.org/drizzle/drizzle. Depends on task 3. Delivers full DML on primary-key-only tables under autocommit (each statement runs in its own shim transaction, committed at statement end via the doStartStatement/doEndStatement/doCommit plumbing in its simplest configuration; task 5 generalizes).

slatedb_cursor.{h,cc}, SlateDBCursor : drizzled::Cursor.

Read path

  • doStartTableScan / rnd_next: shim scan over the table’s PK prefix; each row decoded from the value by the task-2 codec into the record buffer.

  • doStartIndexScan(0) + the index_* family over the PK: index_first/index_last (ascending/descending prefix scans), index_next/index_prev.

  • index_read: implement the find-flag state machine completely and first — this is WiredTiger Tier 0.8 and it does not get to recur. Encode the (possibly prefix) key via encodeKeyFromIndexBuf; seek; then per HA_READ_KEY_EXACT / KEY_OR_NEXT / KEY_OR_PREV / AFTER_KEY / BEFORE_KEY adjust position using the prefix-byte-match property from task 2. Exact-match miss returns HA_ERR_KEY_NOT_FOUND; end-of-range returns HA_ERR_END_OF_FILE; never success with a stale buffer. A dedicated drizzle-test case exercises every find flag against fixed data, ascending and descending, with and without NULLs in the key.

  • position() / rnd_pos: length-prefixed encoded PK bytes in ref (the WiredTiger pattern verbatim); rnd_pos is a transactional point get.

  • records_in_range: bounded scan probe with a row cap; returns the capped estimate. info(): honest estimates only, per the spec — records comes from a capped probe of the table’s primary prefix (exact if the prefix is exhausted under the cap, a sampled estimate if not), never from a maintained counter and never from a fabricated floor. No HTON_HAS_RECORDS, so the optimizer is told these are estimates.

Write path

  • doInsertRecord: encode PK; transactional get probe; present → HA_ERR_FOUND_DUPP_KEY; else put. IODKU therefore flows through the kernel’s standard duplicate-handling path — no engine-side replace flag, no extra() shortcut (WiredTiger Tier 0.2/0.10 both structurally excluded).

  • doUpdateRecord: encode old and new PK from old_data / new_data; equal → single put; different → dup-probe new key, delete old, put new (Tier 0.4).

  • doDeleteRecord: encode PK from the current row image; delete.

  • delete_all_rows: batched prefix delete (shares the task-3 DROP helper).

  • Writes never operate through an open scan’s iterator: the statement transaction is the write target, scans are separate shim objects (Tier 0.5 structurally excluded).

Commit boundary

Three commits: read path (scans green on data seeded through a test backdoor or by landing writes first — implementer’s choice, note it); write path; find-flag tests + result files.

Verification

  • drizzle-test green: CRUD, ORDER BY ASC/DESC on PK, point and range WHERE on PK, dup-key errors, IODKU with distinct insert/update values (the case whose absence masked Tier 0.10), NULL-in-key lookups, the exhaustive find-flag case.

  • Kill-and-restart durability test: sysbench-style insert load, kill -9, restart, verify acknowledged rows present (await-durable on).

  • The storage_engine_api_tester plugin run against the engine; note any contract violations it finds in review.