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 file store #1684

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

nymius
Copy link
Contributor

@nymius nymius commented Nov 13, 2024

Description

The Store::open method doesn't recovers the previous Store state saved in the file and emplaces the file pointer just after the magic bytes prefix, this later is agravated by Store::append_changeset which sets the file pointer after the last written changeset. The combination of both causes the lost of any previous changeset there may have been in the file.

Is natural to think this shouldn't be the expected behavior, as @KnowWhoami pointed out in #1517, and the Store should recover the previous changesets stored in the file store.

The approach proposed in #1632 triggered a discussion about more changes in Store, which motivated the current refactor.

Besides the fix for #1517, the following methods have been changed/renamed/repurposed in Store:

  • create: create file and retrieve store, if exists fail.
  • load: load changesets from file, aggregate them and return aggregated changeset and Store. If there are problems with decoding, fail.
  • dump: aggregate all changesets and return them.
  • load_or_create: try load or fallback to create.

Fixes #1517.
Overrides #1632.

Notes to the reviewers

Load return type is Result<(Option<C>, Store), StoreErrorWithDump> to allow methods which doesn't use WalletPersister to get the aggregated changeset right away.

Dump is kept to allow WalletPersister::initialize method to retrieve the aggregated changeset without forcing the inclusion of the additional parameters needed by store::load to the trait, which would also affect the rusqlite implementation.

Changelog notice

Added:

  • StoreError enum, which includes Io, Bincode and InvalidMagicBytes.
  • "not intended for production" notice in general README for file store.

Changed:

  • Store::create_new to Store::create, with new return type: Result<Self, StoreError>
  • Store::open to Store::load, with new return type: Result<(Option<C>, Self), StoreErrorWithDump<C>>
  • Store::open_or_create to Store::load_or_create, with new return type: Result<(Option<C>, Self), StoreErrorWithDump<C>>
  • Store::aggregate_changesets to Store::dump, with new return type: Result<Option<C>, StoreErrorWithDump<C>>
  • FileError to StoreError
  • AggregateChangesetsError to StoreErrorWithDump, which now can include all the variants of StoreError in the error field.

Deleted:

  • IterError deleted.

Checklists

All Submissions:

  • I've signed all my commits
  • I followed the contribution guidelines
  • I ran cargo fmt and cargo clippy before committing

New Features:

  • I've added tests for the new feature
  • I've added docs for the new feature

Bugfixes:

  • This pull request breaks the existing API
  • I've added tests to reproduce the issue which are now passing
  • I'm linking the issue being fixed by this PR

`Path.exists` is not safe against time-of-creation, time-of-use (TOCTOU)
bugs.

`OpenOptions.create_new` on the other hand is atomic, so not prone to
this kind of problems.
`StoreError` included the `IterError` variants, making it replaceable.
The changes in this commit were motivated due to a bug in the
`StoreFile` which caused old data to be lost if the file was `open`
instead of created and new data was appended.
The bugfix later motivated a general name cleanup in StoreFile's methods
and some minor changes in their signatures. The new StoreFile methods
are:
- create: create file in write only mode or fail if file exists.
- load: open existing file, check integrity of content and retrieve
  Store.
- append: add new changesets to Store. Do nothing if changeset is empty.
- dump: aggregate and retrieve all stored changesets in store.
- load_or_create: load if file exists, create if not, and retrieve
  Store.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Needs Review
Development

Successfully merging this pull request may close these issues.

Appending changesets to Store after opening causes overwriting
2 participants