rocicorp / repc

The canonical Replicache client, implemented in Rust.
Other
31 stars 7 forks source link

Sync clobbers indexes #220

Closed aboodman closed 3 years ago

aboodman commented 3 years ago

Doh. Replicache sync too good.

One of the invariants of Replicache is that the client always snaps to the server, no matter what. The server doesn't know about indexes, so Replicache drops them after a sync.

Did not test this situation thoroughly because (a) rushing, and (b) was thinking sync was unrelated from indexes.

What's happening is that during sync, we rewind to the last snapshot, which of course doesn't include the new indexes, push the changes to server, server ignores index creation requests, and then we apply a patch which doesn't include anything about indexes. So after sync we end up with no more indexes.

On the plus side everything ends up in a perfectly consistent state and the old indexes are even GC'd! 😂.

aboodman commented 3 years ago

@phritz do you think something like https://github.com/rocicorp/repc/pull/221 makes sense?

phritz commented 3 years ago

@phritz do you think something like #221 makes sense?

It's close but I think more strictly correct would be to take the index definitions for the sync snapshot from the parent of the first replay commit, if any. If no replay commits, from the head of the main chain. Reasoning:

I can hear the reader asking themselves "can we make index operations idempotent"? Pretty sure the answer is yes (creation already is) but it doesn't buy us much. It would give us the option to take the index defs from either the parent of the first commit to be replayed or the first commit to be replayed (we can't take it from later replay commits on the main chain as we see in the last bullet above). We might be able to save a bit of work taking from the first commit to be replayed, but I argue that we should not because it messes with our mental model. Replay commits should be replayed, not partially applied (index changes) and then replayed. It's far more natural for us to take index defs from the parent of the first replay -- it keeps the mental model of replaying commits on top of the most recent confirmed state (from the client view or otherwise).

Note: above refers to where we get the index definitions. Once we have them we still need to rebuild the entire index; we don't have a nice way to re-use old indexes :(