Transaction log deletion is database-wide on RocksDB; table-scoped requests are rejected - #618
Transaction log deletion is database-wide on RocksDB; table-scoped requests are rejected#618cb1kenobi wants to merge 7 commits into
Conversation
delete_transaction_logs_before now rejects table-scoped requests on RocksDB (HarperFast/harper#2049), and the deprecated delete_audit_logs_before always errors there since it requires table. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request updates the database transaction documentation to deprecate the delete_audit_logs_before operation and introduces documentation for the delete_transaction_logs_before operation, detailing its behavior on RocksDB and LMDB. The feedback suggests adding a dedicated ### Transaction Log Operations section header to improve the document's structure and clarity.
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
…ecords Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
kriszyp
left a comment
There was a problem hiding this comment.
Probably should clarify the response, since it is returns a job-id.
🤖 Reviewed with Codex
…ment, type style Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
Ethan-Arrowood
left a comment
There was a problem hiding this comment.
I went through this against the merged implementation in harper#2064 rather than taking the prose on trust — the 400 guard for a RocksDB table scope, the engine-agnostic 404 that sits before the engine branch, cleanup_deleted_records against Table.deleteHistory, the background-job dispatch, and the response body all check out line by line. Every factual claim in the diff is accurate, and all eight points from the earlier rounds (Gemini's section header, @kriszyp's five Codex findings, Barber AI's two) are correctly resolved in ffe30c44. I'm not re-raising any of those.
What's left is what the page doesn't say, which on a destructive operation is the part that matters. Four gaps:
-
On LMDB, omitting
tableis a silent no-op — and the section's only example omits it. That request resolvesgetTable()toundefined, falls into theif (!table)branch, finds noRocksDatabaseinstance, and returnsentries_deleted: 0with job statusCOMPLETE. An LMDB operator copying the example verbatim schedules a retention job that quietly does nothing and reports success. Harper's own validator acknowledges this (validation/transactionLogValidator.ts:20:// \table` will need to be required for lmdb, but not for rocksdb`). Inline suggestion below. -
Requires clustering: Yesin the comparison table is false on v5/RocksDB. The 5.0 release notes describe the transaction log as Harper's "own native transaction log as a write-ahead log (WAL) for RocksDB" — unconditional, not a clustering feature;readTransactionLogjust delegates toharperBridge.readAuditLogwith no stream involvement; andreference/backups/overview.mdsays every managed backup includes the transaction log with no clustering caveat. As it stands the row directly contradicts the Storage row above it, which this PR rewrote. A RocksDB reader concludes they have no transaction log unless they've configured replication, then can't reconcile that with a page telling them how to delete it. Inline suggestion below. (TheAvailable since v4.1.0row has the same v4-era problem, but I'd leave that one for a separate pass.) -
A database-wide destructive purge is documented in plain body prose. Line 146 is the sentence that tells an operator who wanted to prune one table to instead purge every table's history, and it sits in an unmarked paragraph. The reference tree uses admonitions for exactly this (
:::warning Data safetyinreference/database/api.md:54). Three things are missing beyond the wrapper: what is actually lost (purgeLogs()deletes whole log files — no per-table survivor, no undo), and the recovery route (a managed backup restores the transaction log alongside the data, perreference/backups/operations.md:113). Inline suggestion below covers both.The third piece I couldn't establish myself and it's a genuine question for you or @kriszyp: what happens if you purge below a lagging peer's replication position?
purgeLogslooks like a whole-file delete with no watermark check at the bridge layer. If there's no guard, "do not purge below your slowest replica's position" belongs in that admonition. If rocksdb-js refuses to delete unshipped files, that's reassuring and also belongs there. Either answer improves the page — silence is the only bad option, so I left it out of the suggestion rather than guess. -
No entry in
release-notes/v5-lincoln/5.2.md. This is breaking in three ways: table-scopeddelete_transaction_logs_beforenow errors where it previously returned success;delete_audit_logs_beforenow always errors on the default engine; and a nonexistenttablenow 404s on LMDB where it previously returned a clean success. Anyone with a scheduled retention job hits one of the first two on upgrade.5.2.mdis actively maintained with prose sections and a reference-page badge isn't a substitute. A short### Transaction Log Deletionsection would do it. Fine as a follow-up if you'd rather not grow this PR — but it shouldn't ship without one.
Everything else below is a suggestion, take or leave. Items 1-3 are cheap enough that I'd land them here.
sent with Claude Opus 5
…fety admonition, params/results, get_job error example, 5.2 release note Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@Ethan-Arrowood thanks for the verification-grade pass. All six inline threads are addressed in 5cc6c51 (replies on each), and gap 4 landed in this PR rather than as a follow-up: release-notes/v5-lincoln/5.2.md now has a "Transaction Log Deletion" section covering all three breaking behaviors (RocksDB table-scope rejection, delete_audit_logs_before always failing on RocksDB, nonexistent-table 404 on either engine) with a link to the updated reference page. Your replication-lag question turned out to be answerable — no purge-side guard exists, but the sender forces a bounded base copy when a peer's requested start predates retained history (shouldForceBaseCopyForRetention, harper-pro#277), so the admonition now states the real cost: full resync, not data loss. — Claude (Fable 5) |
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
kriszyp
left a comment
There was a problem hiding this comment.
Since we are editing the Audit Log / Transaction Log table... Let's just eliminate it and make it clear there is no such thing as a difference between an "audit log" and a "transaction log". That's an ancient relic of NATS that we don't talk about anymore. We just have a transaction log and that's it.
reference/database/transaction.md:159: The new parameter documentation says that omitting bothdatabaseandschemafails validation before a job starts, so “any rejection surfaces when the job runs” is now too broad. A client making that mistake will not receive the job ID described here and cannot pollget_job. Could you distinguish request-validation failures from errors raised after a job has been accepted, for example: “Once accepted, the operation runs as a background job; operation-time failures surface throughget_job”?
— KrAIs (Codex)
release-notes/v5-lincoln/5.2.md:22: “Always fails with the same guidance” conflicts with the next bullet and the operation reference: a nonexistent table fails with a not-found error before the RocksDB guidance is reached. Could you qualify this as an existing RocksDB table, matchingreference/database/transaction.md, so upgrade guidance does not promise the wrong error for typo'd table names?
— KrAIs (Codex)
reference/database/transaction.md:222: The comparison table now correctly says RocksDB transaction logging uses the native WAL and does not require clustering, but this related-doc description still says clustering setup is required for transaction logs generally. Could you qualify it as LMDB/clustering-stream transaction logs, or describe the linked page without claiming clustering is universally required?
— KrAIs (Codex)
🤖 Reviewed with Codex
…ging Per @kriszyp's review: there is no separate "audit log" — it and the transaction log are one thing (a NATS-era relic). Remove the comparison table and the "two complementary mechanisms" framing; the page now states there is one transaction log per database and adds an :::info callout noting read_audit_log / delete_audit_logs_before / logging.auditLog / @table(audit:) are legacy names for that single log. Merge the Audit/Transaction "Operations" split into one section. Codex threads: - transaction.md: distinguish synchronous request-validation failure (missing database/schema, no job id) from operation-time failures via get_job. - transaction.md: Related-docs Replication line no longer claims clustering is required for the transaction log (RocksDB native WAL). - 5.2.md: delete_audit_logs_before "always fails with the same guidance" qualified to an existing table (nonexistent table 404s first). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@kriszyp — done in 98b1a99. Agreed on the core point: there's one transaction log, and the "audit log" as a separate thing is a NATS-era relic. The table was the main offender, so it's gone, along with the "two complementary mechanisms" framing. Audit log vs. transaction log
The three Codex findings
— Claude (Opus 4.8) |
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
…ogy, config default Codex pass on PR 618 surfaced five findings (no blockers); verified each against harper / rocksdb-js source: - transaction.md: the delete_transaction_logs_before result never carries start_timestamp/end_timestamp (DeleteTransactionLogsBeforeResults is constructed with no args; the LMDB branch only sets entries_deleted). Corrected the field list and noted log_files_deleted is 0 on LMDB. - transaction.md: relabel the get_job example "A rejected request" -> "A failed job" (it's an accepted-then-failed job, not request validation). - transaction.md: soften the RocksDB warning — purgeLogs deletes whole log files (file granularity), so "history below the timestamp" overstated entry-level precision. - Cross-page terminology (kriszyp's directive, extended): drop the audit-log-vs-transaction-log two-log framing in database/overview.md, database/api.md, operations-api/operations.md, and logging/operations.md. - logging/configuration.md: logging.auditLog Default false -> true, matching the shipped default (static/defaultConfig.yaml) and transaction.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Ran a Codex review pass over the PR and fixed the findings in a7ad4a0 (no blockers; each verified against the
— Claude (Opus 4.8) |
🚀 Preview DeploymentYour preview deployment is ready! 🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-618 This preview will update automatically when you push new commits. |
kriszyp
left a comment
There was a problem hiding this comment.
Looks good, one small note about transaction vs audit log terminology.
🤖 Reviewed with Codex
| Default: `false` | ||
| Default: `true` | ||
|
|
||
| Enables audit (table transaction) logging. When enabled, Harper records every insert, update, and delete to a corresponding audit table. Audit log data is accessed via the `read_audit_log` operation. |
There was a problem hiding this comment.
The transaction page now explains that the audit log is not a separate mechanism, and on RocksDB changes are stored in the database-wide WAL rather than a corresponding audit table. This touched configuration entry still states that every change is written to an audit table, so readers get conflicting storage models across the two pages. Could you describe this as enabling transaction logging, with read_audit_log retained as the legacy operation name, and avoid promising an audit-table implementation that does not apply to RocksDB?
— KrAIs (Codex)
Companion to HarperFast/harper#2064 (fixes HarperFast/harper#2049 — RocksDB: table-scoped delete_transaction_logs_before destroys the entire database's transaction log).
Updates
reference/database/transaction.md:delete_transaction_logs_beforesection: on RocksDB (the default engine) deletion is database-wide because all tables in a database share one transaction log; as of v5.2.0 a request naming atableis rejected with a 400 (previously the table scope was silently ignored and the whole database's log was purged), and a nonexistenttablereturns a 404. On LMDB,tablescopes deletion to that table, unchanged.delete_audit_logs_beforethat it is deprecated in favor ofdelete_transaction_logs_before, and that on RocksDB it always errors since it requirestable.npm run buildandnpm run format:checkpass locally.Generated by Claude (Fable 5).
🤖 Generated with Claude Code