Skip to content
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

Fix duplicates on update call #398

Merged
merged 1 commit into from
Aug 24, 2021
Merged

Fix duplicates on update call #398

merged 1 commit into from
Aug 24, 2021

Conversation

mosyp
Copy link
Contributor

@mosyp mosyp commented Aug 19, 2021

Description

Every time the update is called, the Add action from the latest checkpoints are being applied once more, leading into duplicates.
As it turned out, it's a regression from #124 changes.

First commit shows the repro steps, second revers mention changes and resolves the issue

xianwill
xianwill previously approved these changes Aug 19, 2021
@xianwill xianwill self-requested a review August 19, 2021 14:04
@rtyler
Copy link
Member

rtyler commented Aug 19, 2021

@dispanser If you're available, I think it would be helpful for you to chime in on this thread 😄

@rtyler rtyler added binding/rust Issues for the Rust crate bug Something isn't working labels Aug 19, 2021
@xianwill xianwill dismissed their stale review August 19, 2021 16:08

Need to take a closer inspection

@houqp
Copy link
Member

houqp commented Aug 19, 2021

I think the optimization that @dispanser introduced is valid, the bug is caused by incorrect use of apply_logs_from_current_version :)

@dispanser
Copy link
Contributor

@rtyler : just coming back from vacation today, I'll take a closer look tomorrow.

@dispanser
Copy link
Contributor

Indeed, calling updatewith the fixes from #124 produces a duplicate file. Nice catch @mosyp !

However, I believe the fix proposed in this PR only solves this as a side effect of not doing the proper thing in the first place: restore_checkpoint clears the state, which has the same cost (and code path) as loading a table from scratch, which is IMHO undesired for a table without any updates..

What the condition basically says is "if the previously loaded latest checkpoint is the same as the currently seen checkpoint, reload from the checkpoint", which leads to the checkpoints being only used if it was current anyway, so doesn't contain anything not already loaded. If the version has advanced past the next checkpoint, we don't use it, which is not what we want because these checkpoints are supposed to allow you skipping all those jsons. Hence the rationale for #124.

As @hougp already mentioned, the root cause for the duplication is calling apply_logs_from_current_version with the current version instead of the next version. The "restoring from checkpoint" code path works around that by increasing the version number self.apply_logs_from_current_version, which we could also do in an else branch:

            Ok(last_check_point) => {
                if self.last_check_point != Some(last_check_point) {
                    self.last_check_point = Some(last_check_point);
                    self.restore_checkpoint(last_check_point).await?;
                    self.version = last_check_point.version + 1;
                } else {
                    self.version += 1;
                }
            }

Of course, now we basically do a +1 in all non-error cases which is a bit odd so it's probably a good idea to move that out. Also, there's update_incremental, maybe we just call that?

@houqp
Copy link
Member

houqp commented Aug 21, 2021

Yep, i think it would be cleaner to use update_incremental wherever applicable, then remove all the self.version += 1 code. apply_logs_from_current_version is very easy to be missed use based on its name, so we should probably only use it in update_incremental as an internal method.

@mosyp
Copy link
Contributor Author

mosyp commented Aug 23, 2021

@dispanser @houqp I got rid of apply_logs_from_current_version (it was basically an incomplete version of update_incremental) and applied your suggestion.
So the update is pretty straightforward one.

  • If the latest checkpoint is the same - then just call update_incremental
  • otherwise - clear state and apply latest checkpoint then call update_incremental.

It also lead to rework the load function. But I've done a little trick there. Before calling the update_incremental, I clear the state and set version to -1 and then call update_incremental. This was we have the same behavior as before but with much less code. (the -1 is required for update_incremental to start from applying the version 0)

Copy link
Member

@houqp houqp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice clean up @mosyp !

@mosyp mosyp merged commit e7e549d into main Aug 24, 2021
@mosyp mosyp deleted the update_bug branch August 24, 2021 14:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
binding/rust Issues for the Rust crate bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants