Skip to content

[READWISE] Port upstream fix: schema migration could never complete when docs already exist in the new storage - #22

Merged
TristanH merged 1 commit into
readwise-rxdb15from
fix/migration-conflict-loop
Sep 29, 2026
Merged

TristanH merged 1 commit into
readwise-rxdb15from
fix/migration-conflict-loop

Conversation

@TristanH

Copy link
Copy Markdown
Member

Problem

A schema migration never finishes when some docs already exist in the new storage. It then restarts on every launch and pins CPU and memory. This froze Bookwise on iOS during the tracked_books v12 to v13 migration, with the app reaching 1.4 GB before iOS killed other apps.

migrateStorage pushes each row with assumedMasterState: undefined. The storage replication handler treats that as an insert, so any doc already in the new storage comes back as a conflict. Upstream replication then writes the new doc back into the old storage. That write is a new change, so the same docs are pushed again, forever. The old storage is never removed, so the next launch starts the loop over.

Fix

Port of upstream pubkey#8871 (commit 8253bba830). After writing the rows, return no conflicts. The doc already in the new storage wins and the old state is dropped. The comment is copied from upstream.

Upstream's commit also closes storage instances when a migration is canceled. Our 15.27 fork has no migration cancel, so that part is left out.

Build

dist/esm and dist/cjs were rebuilt for this one file with the pinned Babel 7.24.7 config, the same as build:esm. Before editing, I recompiled the unchanged file. The JS came out byte-identical to the committed dist. The sourcemap mappings differ slightly, most likely because there is no lockfile to pin Babel's own dependencies. No other dist files are touched.

Testing

The regression test lives in rekindled (shared/test/vitest/database/schemaMigration.test.ts). It opens a v0 collection, then a v1 collection that already holds two of the docs, and runs the migration. Without the fix the vitest worker runs out of memory after 261s. With it the test passes in about 30ms. On the affected phone the migration finished in one pass and removed the v12 tables.

The fork's lint pre-commit hook was skipped with --no-verify because node_modules is not installed here. .eslintignore lists plugins/, so that lint skips this file anyway. Linting the file directly with --no-ignore and the pinned ESLint 8.57 config found only one pre-existing error, no-undef-init on line 137, which this change does not touch.

…hen docs already exist in the new storage

Port of pubkey#8871. The migration pushes rows with no assumed master
state, so every doc already in the new storage came back as a conflict, got
written back into the old storage and pushed again, forever. Ignore those
conflicts and keep the doc that is already in the new storage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@TristanH
TristanH merged commit 0d78cf5 into readwise-rxdb15 Sep 29, 2026
10 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant