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

refactor: do not use recursion but keep a stack #28

Merged
merged 2 commits into from
Sep 11, 2023

Conversation

baszalmstra
Copy link
Contributor

When using this library we consistently ran into stack overflow issues. We traced this back to this crate which uses recursion to be able to revert operations in case of an error. This is problematic when applying large patches because it will quickly overflow the stack.

This PR does two things:

  1. Introduces a stack of undo operations which is constructed as the patches are applied. The stack contains the inverse operations of the patches. If an error occurs this stack is unwound to reconstruct the original document. This effectively removes recursion and stores the undo stack on the heap instead of on the stack.
  2. Added (back) a patch_unsafe function which does not construct this undo stack and in turn leaves the document in an inconsistent state.

In our case, we are applying large patches and we don't care at all if the document is in an inconsistent state in case of an error. We throw it away anyway. With this PR this significantly reduces memory usage and increases the performance of applying the patches.

src/lib.rs Outdated
@@ -423,76 +423,166 @@ fn test(doc: &Value, path: &str, expected: &Value) -> Result<(), PatchErrorKind>
/// # }
/// ```
pub fn patch(doc: &mut Value, patch: &[PatchOperation]) -> Result<(), PatchError> {
apply_patches(doc, 0, patch)
let mut undo_stack = Vec::new();
Copy link
Owner

Choose a reason for hiding this comment

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

Really minor thing -- do you think you can reserve undo stack size? Vec::with_capacity(patch.len())?

Copy link
Owner

@idubrov idubrov left a comment

Choose a reason for hiding this comment

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

Seems like there are some test failures, too.

@baszalmstra
Copy link
Contributor Author

Thanks! I've applied your suggestion.

I'm not sure why the test was failing. The only change in the schema was that a description was added for PatchOperation which already existed in the code but was previously missing in the schema. I've updated the test reference to reflect this.

@baszalmstra
Copy link
Contributor Author

Now it seems like codecov is failing.. I think the github action needs to be updated perhaps?

@idubrov
Copy link
Owner

idubrov commented Sep 11, 2023

Sorry about that. Yes, it turned out the test was broken on main and codecov configuration stopped working (it didn't have the credentials). I fixed both of these issues on main, so if you rebase, this PR should become green.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants