0
0
mirror of https://github.com/tursodatabase/libsql.git synced 2025-05-17 00:47:11 +00:00

10 Commits

Author SHA1 Message Date
7887f1d182 Improve error handling 2024-07-31 20:28:21 +05:30
53674d0895 Add ErrorDetails proto for errors 2024-07-31 20:27:55 +05:30
f563a741ca Improve local cache and prefer local reads ()
* update WIP list

* prefer local max_frame_no

this assumes that cache is always up to date and uses that instead
of calling the storage server. later we will add replication and make
sure that cache is upto date.

* Prefer local reads and also save page versions locally

Let's store `page_no` along with the `frame_no`. And then while reading,
we will do a range read, read frame which is less than txn's
`max_frame_no`

* minor improvements: index creation, fix max_frame_num query

* update local cache on inserts

* avoid unnecessary call to ss in `find_frame`

* remove unused `get_frame`

* eliminiate all calls to storage server during read path
2024-07-12 06:39:37 +00:00
80605905d9 fix: minor bug issues with the cache tables ()
- Changed transaction table to use `(txn_id, page_no)` as composite
  primary key
- Updated `insert_frame` to ignore unique constraint violation since
  frames are immutable
- Change `insert_page` method to upsert
2024-07-01 13:08:48 +00:00
aeb9a9c538 Use max_frame_no for transaction reads and writes ()
* Add basic tonic error handling

Added a simple error to handle `WriteConflict`s

* Improve the way we handle Foundation DB keys

Foundation DB keys support tuples. Earlier we used plain strings. For
example to store page 5, which had frame no 8, we did `ns/f/5/8`.
However this breaks lexicographic sorting. For e.g. we want `ns/f/5/8`
to be smaller than `ns/f/5/18`, but since we store as a plain string
the comparison breaks.

So we let FDB handle encoding with the `pack` API which encodes the
key properly as tuple `(ns, f, 5, 8)`

* Send `max_frame_no` while doing inserts and find frame

Whenever a txn is started, we keep the current `max_frame_no` in the
transaction's state. For the subsequent find and insert requests, we
send this value to storage server.

For a read txn, it should not read any frames greater than it's
max_frame_no. For a write txn, if the max_frame_no has changed
meanwhile, then txn should be aborted.

* Allow multiple writers at the storage server

This patch has two important changes:
- Storage server now uses `max_frame_no` from the txn to read frames
  It will make sure to not read any frames beyond the `max_frame_no`
  of the transaction. This fixes the bug in isolation level.
- Storage server now checks `max_frame_no` before inserting. If it
  has changed meanwhile, then it rejects the insertion request.

This lets us have multiple (non concurrent) writers or even multiple
logical primary instances.

* minor cargo fmt fixes
2024-06-28 13:38:02 +00:00
5f425e1ada Move in-memory cache to disk ()
* replace in-memory cache with local sqlite db

Previously, `libsql-storage` stored all the data in-memory. It kept a
in-memory frame cache and also cached all the transient transaction
writes in-memory. This patch changes it to store the data on local disk.
This data is transient in nature, disk loss should not cause any issues.

* fix: remove unnecessary `namespace` column in local cache

Each namespace gets its own local cache. So there is no need of
namespace column at all.

* Add some explainer about how we use the local cache

We use LocalCache to cache frames and transaction state. Each namespace gets its own cache
which is currently stored in a SQLite DB file, along with the main database file.

Frames Cache:
    Frames are immutable. So we can cache all the frames locally, and it does not require them
    to be fetched from the storage server. We cache the frame data with frame_no being the key.

Transaction State:
    Whenever a transaction reads any pages from storage server, we cache them in the transaction
    state. Since we want to provide a consistent view of the database, for the next reads we can
    serve the pages from the cache. Any writes a transaction makes are cached too. At the time of
    commit they are removed from the cache and sent to the storage server.
2024-06-28 12:53:33 +00:00
fbce426619 Use the namespace resolver to extract namespace ()
* Move `NamespaceName` from `libsql-wal` to `libsql-sys`

* Use the namespace resolver in durable WAL
2024-06-14 17:01:01 +00:00
d765413f5f Refactor and update storage server proto ()
* Update proto to send `max_frame_no` while inserting frames

We plan to allow multiple (non concurrent) writers. If a transaction's
`max_frame_no` does not match the server's `max_frame_no`, then it
has missed some new writes and we can abort the transaction

* Updates storage trait's insert_frames definition

- Change parameter type `FrameData` to `Frame` from rpc def, to
  avoid unnecessary copying
- Take `max_frame_no` param

* Use `insert_frames` method

* cleanup: remove `insert_frame` method and impl

* Remove `FrameData`, use `Frame` from proto instead
2024-06-10 07:33:53 +00:00
3460edce12 Add storage server RPC client ()
* Add storage server RPC client

* Address review comments

- Use `#[tracing::instrument]` wherever appropriate
- Remove `Mutex` for `client` and `clone` it wherever required
- Avoid reading env variable inside the lib, rather take a config object
- Make the private methods of `DurableWal` async
- Don't try to create a runtime, instead assume it always exists. Let the caller create it
- Update proto:
	- remove `max_frame_no` from `InsertFramesRequest`
	- make `page_no` to `u32` in the proto
- Update storage server to have `page_no` as `u32`
2024-06-04 11:26:50 +00:00
4c60f36232 Add storage server proto definition () 2024-05-30 08:39:36 +00:00