copier: remove the legacy unbuffered copier - #1140
Open
morgo wants to merge 2 commits into
Open
Conversation
The buffered DBLog-style copier has been the default since v0.15.0 (block#908), and move/sync always required it. Nothing downstream sets --unbuffered, so retire the INSERT IGNORE .. SELECT implementation rather than keep maintaining two copy paths. Highlights: - Delete pkg/copier/unbuffered.go and the --unbuffered flag. CopierConfig loses Unbuffered and the vestigial TargetChunkTime; NewCopier no longer takes a *sql.DB and now requires a non-nil Applier. - Add copier.ChunkCopier, a synchronous single-chunk CopyChunk API on the buffered copier, so the checkpoint/resume and binlog tests that stepped the unbuffered copier chunk-by-chunk keep their deterministic stepping. - Stop the applier in Runner.Close(). Run's teardown already stopped it, but early-failure paths and incremental-stepping tests would otherwise leak the applier's worker goroutines. - Copy chunkers now always size by TargetChunkBytes; --target-chunk-time remains for the checksum. Also fix the startup log printing TargetChunkTime under the target-chunk-size key. - Re-home displaced coverage: range-optimizer refusal moves to pkg/dbconn (where the error classification lives), the NULL->NOT NULL unsafe warning is asserted on the buffered path, and the resume-phantom test is deleted outright — the phantom only existed on the INSERT IGNORE recopy path. - Collapse the buffered/unbuffered test matrices and update the docs to describe the single-copier world. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR removes Spirit’s legacy unbuffered (INSERT IGNORE ... SELECT) copier and its CLI/config surface area, consolidating the system on the DBLog-style buffered copier across migrate, move, and sync/datasync. It also introduces a small incremental copy interface (copier.ChunkCopier) to preserve deterministic “step chunk-by-chunk” testing without keeping the unbuffered implementation.
Changes:
- Deleted the unbuffered copier implementation and removed the
--unbufferedflag/config plumbing. - Simplified copier construction and config (
NewCopiersignature change;CopierConfigtrims legacy fields) and addedChunkCopier.CopyChunkfor deterministic stepping tests. - Adjusted runners and docs to reflect byte-budget chunk sizing for copy, time-budget chunk sizing for checksum; tightened teardown by stopping the applier in
Runner.Close().
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates dynamic chunking explanation for single-copier world. |
| AGENTS.md | Updates architecture notes to reflect buffered-only copier. |
| docs/README.md | Updates docs overview to remove unbuffered mode mention. |
| docs/migrate.md | Removes --unbuffered docs; clarifies chunk sizing responsibilities. |
| pkg/applier/README.md | Updates applier role/relationship now that copier is buffered-only. |
| pkg/change/binlog_test.go | Updates copier construction API usage in tests. |
| pkg/checksum/json_test.go | Updates historical wording re: legacy server-side copy. |
| pkg/copier/README.md | Rewrites copier docs around buffered-only algorithm + new ChunkCopier. |
| pkg/copier/copier.go | Removes unbuffered selection; adds ChunkCopier interface; updates NewCopier signature and validation. |
| pkg/copier/buffered.go | Adds synchronous CopyChunk implementation to support deterministic tests. |
| pkg/copier/unbuffered.go | Deletes legacy unbuffered copier implementation. |
| pkg/copier/copier_test.go | Collapses tests onto buffered path; updates NewCopier API usage. |
| pkg/copier/buffered_test.go | Updates construction and chunker config usage after config/API changes. |
| pkg/copier/autoscaler_test.go | Updates construction API usage. |
| pkg/dbconn/dbconn_test.go | Moves range-optimizer refusal coverage into dbconn tests. |
| pkg/datasync/runner.go | Updates copier construction API usage. |
| pkg/move/runner.go | Updates copier construction API usage. |
| pkg/migration/migration.go | Removes Unbuffered flag/field; clarifies chunk sizing docs for copy vs checksum. |
| pkg/migration/runner.go | Updates copier construction; fixes startup logging; always sizes copy chunks by bytes; stops applier in Close(). |
| pkg/migration/README.md | Updates locking explanation now that unbuffered is removed. |
| pkg/migration/check/rename.go | Updates rename-check comment to remove dual-mode wording. |
| pkg/migration/helpers_test.go | Removes WithBuffered helper option. |
| pkg/migration/resume_test.go | Updates deterministic stepping tests to use copier.ChunkCopier; removes unbuffered-only phantom test. |
| pkg/migration/binlog_test.go | Updates deterministic stepping tests to use copier.ChunkCopier. |
| pkg/migration/rename_column_test.go | Collapses buffered/unbuffered matrices into single-mode tests. |
| pkg/migration/migration_test.go | Collapses buffered/unbuffered matrices into single-mode tests. |
| pkg/migration/datatype_test.go | Collapses buffered/unbuffered matrices into single-mode tests. |
| pkg/migration/cutover_test.go | Collapses buffered/unbuffered matrices into single-mode tests. |
| pkg/migration/cutover_semisync_test.go | Collapses buffered/unbuffered matrices into single-mode tests. |
| pkg/table/README.md | Updates chunker docs to remove unbuffered distinctions. |
| pkg/table/chunk.go | Updates comments re: who sets ActualBytes. |
| pkg/table/chunker.go | Updates comments re: time vs byte signals. |
| pkg/table/dynamic_chunk_sizer.go | Updates comments re: time-signal path participants. |
| pkg/throttler/README.md | Updates example usage to new copier API (needs applier wiring to be complete). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- CopyChunk: select on ctx.Done() while waiting for the apply callback, as defense against a future applier that fails to invoke it. - buffered_test: make the tiny chunk-time target's unit explicit (10ns). - throttler README: show the required Applier wiring in the example. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The buffered DBLog-style copier has been the default since v0.15.0 (#908), and
move/synchave always required it. A search across Block automation and downstream consumers (tern, strata) found nothing setting--unbuffered, so this retires the legacyINSERT IGNORE .. SELECTimplementation rather than keep maintaining two copy paths. Net −832 lines.What changed
Code
pkg/copier/unbuffered.goand the--unbufferedflag.CopierConfiglosesUnbufferedand the vestigialTargetChunkTime(chunk sizing lives entirely in the chunker);NewCopierdrops its unused*sql.DBparameter and now requires a non-nilApplier.TargetChunkBytesnow;--target-chunk-timeremains for the checksum. Also fixes the startup log printing theTargetChunkTimevalue under thetarget-chunk-sizekey.Runner.Close()now stops the applier.Run's teardown already stopped it (Stop is idempotent), but early-failure paths — and tests that step the copy incrementally — would otherwise leak the applier's worker goroutines.New API:
copier.ChunkCopierThe unbuffered copier's synchronous
CopyChunkwas the vehicle for every deterministic-stepping test (checkpoint/watermark ordering, binlog interleaving). The buffered copier now implements the same contract behind a small interface:It auto-starts the applier (idempotent), applies the chunk, and waits on the applier callback — feedback reaches the chunker before it returns, so tests can complete chunks in a controlled order (e.g. 2, 1, 3) exactly as before.
Displaced test coverage
range_optimizer_max_mem_size→ fatal) moved topkg/dbconn, where the warning-code classification actually lives.TestBufferedCopierDataTypeConversionError.TestResumeFromCheckpointPhantomis deleted, not ported: per its own doc comment the phantom row only arises on theINSERT IGNORE ... SELECTrecopy path; the buffered copier applies row images via REPLACE and has no equivalent scenario.Docs
docs/migrate.mddrops the### unbufferedsection; README/AGENTS/package READMEs (copier, applier, table, throttler, migration) now describe the single-copier world, keeping short history notes where the contrast is still instructive.Verification
go build ./...,go vet(includingsemisyncandsingleversionbuild tags),gofmt,golangci-lint(0 issues, uncapped).pkg/copier(goleak-guarded),pkg/change,pkg/move,pkg/datasync;pkg/dbconn -run TestRangeOptimizerRefusal; focusedpkg/migrationruns covering the ported step-through tests (TestCheckpoint,TestCheckpointRestore, all 7TestE2EBinlogSubscribing*), resume E2E, and every collapsed matrix (16 rename tests, enum/set reorder+drop, cutover atomicity, generated-columns/binary-checksum/charset pairs). All pass.🤖 Generated with Claude Code