This is an explanation of the root cause for WebKit bug 216962.
Okay, so WebKit wants to move from per-ObjectStore Index IDs to global Index IDs.
Our current indices table (in iOS 13) looks like this:
id | name | objectStoreID |
---|---|---|
1 | uuid | 1 |
2 | date | 1 |
1 | uuid | 2 |
2 | time | 2 |
3 | object_uuid | 2 |
4 | created_at | 2 |
1 | uuid | 3 |
2 | name | 3 |
1 | uuid | 4 |
2 | sort_order | 4 |
This code loops over all the existing indices and picks global IDs for them: https://github.com/WebKit/webkit/blob/37a90a973bb2dbfe5f55e8df2db2ac5a06423a87/Source/WebCore/Modules/indexeddb/server/SQLiteIDBBackingStore.cpp#L822-L828
So, in our case, that map looks something like this:
{ 1, 1 } = 1
{ 1, 2 } = 2
{ 2, 1 } = 3
{ 2, 2 } = 4
{ 2, 3 } = 5
{ 2, 4 } = 6
{ 3, 1 } = 7
{ 3, 2 } = 8
{ 4, 1 } = 9
{ 4, 2 } = 10
Now, we loop over each entry in that map and run the following:
UPDATE IndexInfo SET id = {map.value} WHERE id = {map.key[0]} AND objectStoreID = {map.key[1]};
Let's walk through this...
Basically no change.
UPDATE IndexInfo SET id = 1 WHERE id = 1 AND objectStoreID = 1;
id | name | objectStoreID | |
---|---|---|---|
🟊 | 1 | uuid | 1 |
2 | date | 1 | |
1 | uuid | 2 | |
2 | time | 2 | |
3 | object_uuid | 2 | |
4 | created_at | 2 | |
1 | uuid | 3 | |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
Also basically no change.
UPDATE IndexInfo SET id = 2 WHERE id = 2 AND objectStoreID = 1;
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
🟊 | 2 | date | 1 |
1 | uuid | 2 | |
2 | time | 2 | |
3 | object_uuid | 2 | |
4 | created_at | 2 | |
1 | uuid | 3 | |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
This is where things start changing...
UPDATE IndexInfo SET id = 3 WHERE id = 1 AND objectStoreID = 2;
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
2 | date | 1 | |
🟊 | 3 | uuid | 2 |
2 | time | 2 | |
3 | object_uuid | 2 | |
4 | created_at | 2 | |
1 | uuid | 3 | |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
Things are still working as expected here...
UPDATE IndexInfo SET id = 4 WHERE id = 2 AND objectStoreID = 2;
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
2 | date | 1 | |
3 | uuid | 2 | |
🟊 | 4 | time | 2 |
3 | object_uuid | 2 | |
4 | created_at | 2 | |
1 | uuid | 3 | |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
This is where we run into our first bit of index corruption
UPDATE IndexInfo SET id = 5 WHERE id = 3 AND objectStoreID = 2;
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
2 | date | 1 | |
🟊 | 5 | uuid | 2 |
4 | time | 2 | |
🟊 | 5 | object_uuid | 2 |
4 | created_at | 2 | |
1 | uuid | 3 | |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
This is where the second index gets corrupted
UPDATE IndexInfo SET id = 6 WHERE id = 4 AND objectStoreID = 2;
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
2 | date | 1 | |
5 | uuid | 2 | |
🟊 | 6 | time | 2 |
5 | object_uuid | 2 | |
🟊 | 6 | created_at | 2 |
1 | uuid | 3 | |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
Now it continues on normally
UPDATE IndexInfo SET id = 7 WHERE id = 1 AND objectStoreID = 3;
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
2 | date | 1 | |
5 | uuid | 2 | |
6 | time | 2 | |
5 | object_uuid | 2 | |
6 | created_at | 2 | |
🟊 | 7 | uuid | 3 |
2 | name | 3 | |
1 | uuid | 4 | |
2 | sort_order | 4 |
We have corrupted the index IDs and now our objectStore is broken.
id | name | objectStoreID | |
---|---|---|---|
1 | uuid | 1 | |
2 | date | 1 | |
🡂 | 5 | uuid | 2 |
🡂 | 6 | time | 2 |
5 | object_uuid | 2 | |
6 | created_at | 2 | |
7 | uuid | 3 | |
8 | name | 3 | |
9 | uuid | 4 | |
10 | sort_order | 4 |