-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update violates set semantics #2134
Comments
Reduced repro to: use spacetimedb::{ReducerContext, Table};
#[spacetimedb::table(name = boeuf)]
pub struct Boeuf {
#[primary_key]
pub id: u64,
pub n: u64,
}
#[spacetimedb::reducer]
pub fn add(ctx: &ReducerContext, id: u64, n: u64) {
ctx.db.boeuf().id().delete(id);
ctx.db.boeuf().insert(Boeuf { id, n });
} spacetime start &
spacetime publish kim-test
spacetime call kim-test add 1 1
spacetime call kim-test add 1 1
fg
^C
spacetime start &
spacetime sql kim-test 'select * from boeuf' Unsurprising, since |
+1, this is failing replication cluster restart smoketest |
I'm marking this P0. |
@kim could you post the result of your bisect here even if you don't believe it was correct? |
The issue is not fully fixed, potentially due to special handling of connect/disconnect transactions. imho, replaying should only warn, but never error on set semantic violations. |
Steps to reproduce:
Observe:
The offending transaction 3 is another This is explicitly allowed because we cannot guarantee the pairing connect/disconnect transactionally. Replaying must support this, either by special-casing connect/disconnect, or generally not erroring due to set semantic violations. |
To be clear, what should the behavior be in the case of an insert of an already-present row in a commitlog? Should the second insert:
Should we similarly ignore deletes of not-present rows? I will also point out that, due to our rejecting duplicate rows during commitlog replay, we identified and fixed an actual bug in the datastore which we might otherwise not have noticed. If removing that protection is the only or best option, so be it, but there is a cost to it. |
That’s nice, but it would have resulted in prolonged unavailability if it was caught in production. Since no automated testing caught it, this could very well have happened. I would prefer the replay to be as lenient as possible, ignoring duplicate inserts (leaving the first row in memory) and deletes (the row is already gone). I would also accept a solution which either special-cases connect/disconnect transactions, or revises the implementation and requirements to not require a potentially-duplicate disconnect. |
An update on this: there was no duplicate insert, there was a correct and consistent commitlog containing insert/delete pairs as it should have. We were unable to replay due to a bug in the datastore, described in #2161 . Kim's assertion that it is safe to ignore a failed delete because "the row is already gone" did not hold in this case; the row would still be present after the failed delete. If we had been "as lenient as possible," we would have reconstructed a state that was objectively incorrect, in that it would contain rows which according to the commitlog should have been deleted. I believe quite strongly that bringing up a database in the wrong state in this way would be worse than erroring loudly. |
Using the
update
method on a#[primary_key]
'ed table inserts a new row even if the row is unchanged.This prevents the database to restart from the commitlog:
To reproduce, create a module like so:
add
reducer twice with the same arguments.The text was updated successfully, but these errors were encountered: