Skip to content

Proposal for a new SQLiteStore implementation in zarr-python v3 #3319

Description

@auxym

Background

A proposal for a ZipStore spec is being discussed here: https://github.com/zarr-developers/zarr-specs/pull/311/files

ZipStore would be a convenient way to implement single-file zarr storage. Single file stores can be useful for many use cases which are discussed in this proposal.

There is also broader discussion around other archive formats here: zarr-developers/zarr-specs#209. In this issue, it was suggested I open another issue in order to discuss the imlementation of a single-file store based on sqlite.

Proposal

I'd like to propose bringing back SQLite storage as an alternative to, or possibly even a replacement for, zip storage. I say bring back, as sqlite storage was available in zarr-python v2. Sqlite would bring the following advantages over zip:

  • Mainly: supports key deletion, overwriting and setting partial values. This would allow the store to support all array operations such as deleting, overwriting, resizing and appending. ZipStore supports adding new arrays only, but not resizing or appending to them.
  • sqlite is rather ubiquitous. Maybe not as much as zip (zip is built-in many OS default file browsers, for example), but you can find implementations of sqlite in basically any programming language on any platform.
  • Provides at least some protection against data loss in case of a crash or power loss. sqlite itself provides full DBMS-like ACID guarantees. In the context of this proposal, this mostly means that the set operation is atomic: a value will be either fully and durably written to a key, or not at all. In constrast, a zipstore could be made unreadable (or very difficult to recover) if, for example, there is a crash before the file directory (footer) is written. This issue plagues HDF5 in a way, my understanding is that a crash during a write on a HDF5 file can render the whole file unreadable. I understand the HDF5 group had started to implement a rollback journal to solve this, but it was abandoned. By basing a zarr single-file store on sqlite, we get journaling for free, essentially.

Draft implementation

https://github.com/auxym/zarr-sqlite

This implementation re-uses the same database schema as in zarr-python v2 and many of the same SQL statements, but it implements zarr-python v3's Store ABC.

This experimental implementation has the following limitations:

  • The implementation relies on the standard library sqlite3 library and is not async. Async implementation would require either a 3rd party lib (for example https://aiosqlite.omnilib.dev/en/stable/index.html) or implementing our own async wrapper around a worker thread for example.

  • Does not support partial writes for the moment because I didn't take the time to implement it, but it should be possible through sqlite's "blobopen" API.

  • I've done only some rudimentary testing, there are probably many bugs or oversights remaining.

Notes on performance

I ran some very quick "write" benchmarks, and sqlitestore appears to be up to 2X faster than LocalStore on "small" arrays or chunks, up to around 100 kb (2X at 10 kb, 1.2X at 100 kb), but slower on larger chunks (0.6X at 1 MB).

Nevertheless, speed is not the main reason behind the sqlite store, and given the differences, I'd call the performance "roughly equivalent" to local storage.

Possible implementation of atomic writes of array data and metadata

SQLite could in theory support an atomic transaction where all chunks of an array as well as the array metadata are written as part of the same transaction and then committed. However, this would require higher level support in the storage API. The current implementation commits after every single "set" operation.

Final notes

Is there any interest in integrating an SQLite-backed single-file store in zarr-python and/or in the zarr specification? If so, I can work towards cleaning up the code, adding more tests and submitting a PR (or a draft spec).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions