You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Any redb file created or opened by iroh-docs 0.94 through 0.98 fails to open under 0.99 with TableError::TableTypeMismatch on the records-1 table (and two others). The db.upgrade() shim added in #69 runs as intended, but it does not actually cover what #100 needs it to cover. #100 then bumps redb straight from 2.6 to 4.1, skipping the only release line where the documented migration path can run.
Result: the on-disk store is now unreachable for anyone who upgrades to 0.99 without first running a redb 3.x release that wraps these three tables in Legacy<...>. There is no such iroh-docs release.
Repro
Create a doc store with iroh-docs 0.98 (redb 2.6.3). The db.upgrade() call added in feat: upgrade redb to v3 compatible format #69 runs on first open and stamps the file format header as v3.
Upgrade to iroh-docs 0.99 (redb 4.1.0).
Open the same store. Tables::new(&write_tx) returns:
records-1 is of type Table<([u8;32],[u8;32],&[u8]), (u64,[u8;64],[u8;64],u64,[u8;32])>
The redb error formatter only prints the on-disk type, which makes this look tautological at first glance. It is in fact a mismatch on the type classification byte stored in the table metadata. See below.
Root cause
redb 3.0 changed how variable-width tuple types are tagged in table metadata. The type-name string is unchanged, but the leading classification byte goes from Internal = 1 to Internal2 = 3. From cberner/redb at src/tuple_types.rs in 4.1.0:
LATEST_PER_AUTHOR_TABLE (latest-by-author-1), value (u64, &[u8])
Stores written by redb 2.6 have these stamped with classification Internal = 1. redb 4.1 expects Internal2 = 3 for the same definitions. The type check fails on open.
The remaining tables (authors-1, namespaces-1, namespaces-2, sync-peers-1, download-policy-1) are fixed-width or non-tuple, so they keep the Internal = 1 classification under both redb versions and migrate cleanly.
#69 ("feat: upgrade redb to v3 compatible format") kept redb pinned at 2.6 and called db.upgrade() after Database::create():
letmut db = Database::create(&path)?;match db.upgrade(){Ok(true) => info!("Database was upgraded to redb v3 compatible format"),Ok(false) => {}Err(err) => warn!(...),}
The intent reads correctly: do the 2 to 3 migration that redb's CHANGELOG describes before crossing into a redb 3.x release. That part does run.
Why that wasn't enough
Database::upgrade() in redb 2.6.3 only updates the file format header. It does not walk tables and does not rewrite per-table type metadata. From redb-2.6.3/src/tree_store/page_store/page_manager.rs:
That is the whole thing. The classification byte stamped into each table's type metadata at table creation time stays as Internal = 1. There is no mechanism in redb 2.6 to re-stamp it as Internal2 = 3, because redb 2.6 doesn't know Internal2 exists.
So #69 successfully bumps the file format header. It cannot, even in principle, fix the per-table classification metadata.
What the redb CHANGELOG actually says
From cberner/redbCHANGELOG.md:
redb 3.0.0:
Optimize storage of tuple types. (...) This encoding is not compatible with the previous format. To load tuple data created prior to version 3.0, wrap them in the Legacy type.
redb 4.0.0:
Remove Legacy type. To migrate off the Legacy type, use the Legacy type in the 3.x release and copy the data to a table with plain tuples, before upgrading to the 4.x release.
So the documented path is three steps, not two:
redb 2.6: call db.upgrade() to migrate the file format header.
redb 3.x: open the same store with RECORDS_TABLE, RECORDS_BY_KEY_TABLE, and LATEST_PER_AUTHOR_TABLE redefined to use Legacy<...> wrappers, read each row, write it back into the same table without the wrapper. That commit re-stamps the metadata as Internal2.
redb 4.x: drop the wrappers entirely. Open normally.
#100 goes from step 1 to step 3 with no intermediate Legacy pass. After redb 4.0 dropped the Legacy type, there is no longer a way to do step 2 from inside an iroh-docs build that depends on redb 4.x. The migration window is closed for any store still on the old classification.
Summary
Any redb file created or opened by iroh-docs 0.94 through 0.98 fails to open under 0.99 with
TableError::TableTypeMismatchon therecords-1table (and two others). Thedb.upgrade()shim added in #69 runs as intended, but it does not actually cover what #100 needs it to cover. #100 then bumps redb straight from 2.6 to 4.1, skipping the only release line where the documented migration path can run.Result: the on-disk store is now unreachable for anyone who upgrades to 0.99 without first running a redb 3.x release that wraps these three tables in
Legacy<...>. There is no such iroh-docs release.Repro
db.upgrade()call added in feat: upgrade redb to v3 compatible format #69 runs on first open and stamps the file format header as v3.Tables::new(&write_tx)returns:The redb error formatter only prints the on-disk type, which makes this look tautological at first glance. It is in fact a mismatch on the type classification byte stored in the table metadata. See below.
Root cause
redb 3.0 changed how variable-width tuple types are tagged in table metadata. The type-name string is unchanged, but the leading classification byte goes from
Internal = 1toInternal2 = 3. Fromcberner/redbatsrc/tuple_types.rsin 4.1.0:Three tables in
src/store/fs/tables.rsuse a tuple containing&[u8], which makes the tuple variable-width:RECORDS_TABLE(records-1), key(&[u8;32], &[u8;32], &[u8])RECORDS_BY_KEY_TABLE(records-by-key-1), key(&[u8;32], &[u8], &[u8;32])LATEST_PER_AUTHOR_TABLE(latest-by-author-1), value(u64, &[u8])Stores written by redb 2.6 have these stamped with classification
Internal = 1. redb 4.1 expectsInternal2 = 3for the same definitions. The type check fails on open.The remaining tables (
authors-1,namespaces-1,namespaces-2,sync-peers-1,download-policy-1) are fixed-width or non-tuple, so they keep theInternal = 1classification under both redb versions and migrate cleanly.What #69 attempted
#69 ("feat: upgrade redb to v3 compatible format") kept redb pinned at 2.6 and called
db.upgrade()afterDatabase::create():The intent reads correctly: do the 2 to 3 migration that redb's CHANGELOG describes before crossing into a redb 3.x release. That part does run.
Why that wasn't enough
Database::upgrade()in redb 2.6.3 only updates the file format header. It does not walk tables and does not rewrite per-table type metadata. Fromredb-2.6.3/src/tree_store/page_store/page_manager.rs:That is the whole thing. The classification byte stamped into each table's type metadata at table creation time stays as
Internal = 1. There is no mechanism in redb 2.6 to re-stamp it asInternal2 = 3, because redb 2.6 doesn't knowInternal2exists.So #69 successfully bumps the file format header. It cannot, even in principle, fix the per-table classification metadata.
What the redb CHANGELOG actually says
From
cberner/redbCHANGELOG.md:redb 3.0.0:
redb 4.0.0:
So the documented path is three steps, not two:
db.upgrade()to migrate the file format header.RECORDS_TABLE,RECORDS_BY_KEY_TABLE, andLATEST_PER_AUTHOR_TABLEredefined to useLegacy<...>wrappers, read each row, write it back into the same table without the wrapper. That commit re-stamps the metadata asInternal2.#100 goes from step 1 to step 3 with no intermediate
Legacypass. After redb 4.0 dropped theLegacytype, there is no longer a way to do step 2 from inside an iroh-docs build that depends on redb 4.x. The migration window is closed for any store still on the old classification.References
db.upgrade()shim): feat: upgrade redb to v3 compatible format #69Database::upgradesource: https://github.com/cberner/redb/blob/v2.6.3/src/db.rs#L459Legacy(introduced): https://github.com/cberner/redb/blob/v3.0.0/src/lib.rs#L74tuple_types.rs(variable-width branch): https://github.com/cberner/redb/blob/v4.1.0/src/tuple_types.rs