Commit graph

661 commits

Author SHA1 Message Date
Jussi Saurio
64ef3f1343 simplify condition 2025-05-25 10:22:46 +03:00
Jussi Saurio
20e65c0125 bump max_loops to 100k 2025-05-25 10:21:41 +03:00
Jussi Saurio
fc45e0ec0d Reconstruct WAL frame cache when WAL is opened
Currently we are simply unable to read any WAL frames from disk
once a fresh process w/ Limbo is opened, since we never try to read
anything from disk unless we already have it in our in-memory
frame cache.

This commit implements a crude way of reading entire WAL into memory
as a single buffer and reconstructing the frame cache.
2025-05-24 18:29:44 +03:00
Jussi Saurio
70433e100d Merge 'btree: fix infinite looping in backwards iteration of btree table' from Jussi Saurio
Closes #1562
Existing "fuzz test" (not really fuzz, but kinda) didn't catch this due
to `LIMIT 3` clause

Closes #1563
2025-05-23 21:46:16 +03:00
Jussi Saurio
1a937462b3 Merge 'core/pragma: Add support for update user_version' from Diego Reis
It also changes the type from u32 to i32 since
sqlite supports negative values

Closes #1559
2025-05-23 17:00:55 +03:00
Jussi Saurio
cbb56a182e Fix bug: backwards iteration of table btree hangs 2025-05-23 14:23:18 +03:00
Diego Reis
2f8042da22 core/pragma: Add support for update user_version
It also changes the type from u32 to i32 since
sqlite supports negative values
2025-05-22 20:38:27 -03:00
Zaid Humayun
4312d371fb addresses comment https://github.com/tursodatabase/limbo/pull/1548#discussion_r2102606810 by @jussisaurio
this commit changes the btree_destroy() signature to return an Option<usize>. This more closely resembles Rust semantics instead of passing a pointer to a usize.
However, I'm unsure if I'm handling the cursor result correctly
2025-05-23 00:46:05 +05:30
Zaid Humayun
4072a41c9c Drop Table now uses an ephemeral table as a scratch table
Now when dropping a table, an ephemeral table is created as a scratch table. If a root page of some other table is moved into the page occupied by the root page of the table being dropped, that row is first written into an ephemeral table. Then on a next pass, it is deleted from the schema table and then re-inserted with the new root page.

This happens during AUTOVACUUM when deleting a root page will force the last root page to move into the slot being vacated by the root page of the table being deleted
2025-05-22 19:39:46 +05:30
Pere Diaz Bou
b135bf449f reduce attempts for fuzz_long overflow 2025-05-21 15:40:42 +02:00
Pere Diaz Bou
7143e43dd4 clippy 2025-05-21 15:27:15 +02:00
Pere Diaz Bou
a69f85be84 cacheflush clear cache 2025-05-21 14:20:11 +02:00
Pere Diaz Bou
4704cdd24f validate_btree pin pages 2025-05-21 14:20:11 +02:00
Pere Diaz Bou
ddb166f0f0 custom hashmap for page cache 2025-05-21 14:19:56 +02:00
Pere Diaz Bou
c365d79cb1 minimum capacity 10 in page cache 2025-05-21 14:19:56 +02:00
Pere Diaz Bou
b76961ce35 balance mark dirty from start 2025-05-21 14:19:56 +02:00
Pere Diaz Bou
591c674e86 Introduce PageRef wrapper BTreePage.
One problem we have with PageRef, is that this Page reference can be
unloaded, this means if we read the page again instead of loading the
page onto the same reference, we will have split brain of references.

To solve this we wrap PageRef in `BTreePage` so that if a page is seen
as unloaded, we will replace BTreePage::page with the newest version of
the page.
2025-05-21 14:19:41 +02:00
Pere Diaz Bou
35f7317724 add default page cache 2025-05-21 14:11:21 +02:00
Pere Diaz Bou
15d24bd818 Start transactions in fuzz tests to flush pages
Previously, fuzz tests increase the size of page cache indefinitely,
therefore the was no problem of reaching the capacity of a page cache.
By adding transactions to fuzz tests we allow pages to remove dirty
flags once insert is finished.
2025-05-21 14:11:20 +02:00
Pere Diaz Bou
adf72f2bf8 allow updating a page id in page cache 2025-05-21 14:09:39 +02:00
Pere Diaz Bou
35e2088b7e cacheflush move dirty page to new snapshot
After inserting a page into the wal, we dispose of the modified page.
This is unnecessary as we can simply move new page to the newest
snapshot where this page can be read.
2025-05-21 14:09:39 +02:00
Pere Diaz Bou
9677997c63 fix page cache fuzz
to test whether a key is in the cache, we must use peek without touching
the value in order to not promote and change the order of values in lru
cache
2025-05-21 14:09:39 +02:00
Pere Diaz Bou
04323f95a5 increase cache size in empty_btree 2025-05-21 14:09:39 +02:00
Pere Diaz Bou
67e260ff71 allow delete of dirty page in cacheflush
Dirty pages can be deleted in `cacheflush`. Furthermore, there could be
multiple live references in the stack of a cursor so let's allow them to
exist while deleting.
2025-05-21 14:09:39 +02:00
Alecco
e2f99a1ad2 page_cache: implement resize 2025-05-21 14:09:39 +02:00
Alecco
e808a28c98 WIP (squash) adapt pager and btree to page cache error handling 2025-05-21 14:09:39 +02:00
Alecco
4ef3c1d04d page_cache: fix insert and evict logic
insert() fails if key exists (there shouldn't be two) and panics if
it's different pages, and also fails if it can't make room for the page.

Replaced the limited pop_if_not_dirty() function with make_room_for().
It tries to evict many pages as requested spare capacity. It should come
handy later by resize() and Pager. make_room_for() tries to make room or
fails if it can't evict enough entries.

For make_room_for() I also tried with an all-or-nothing approach, so if
say a query requests a lot more than possible to make room for, it
doesn't evict a bunch of pages from the cache that might be useful. But
implementing this approach got very complicated since it needs to keep
exclusive PageRefs and collecting this caused segfaults. Might be worth
trying again in the future. But beware the rabbit hole.

Updated page cache test logic for new insert rules.

Updated Pager.allocate_page() to handle failure logic but needs further
work. This is to show new cache insert handling. There are many places
to update.

Left comments on callers of pager and page cache needing to update
error handling, for now.
2025-05-21 14:09:39 +02:00
Alecco
bdf427c329 page_cache: proper error handling for deletions
Add error handling and results for insert(), delete(), _delete(),
_detach(), pop_if_not_dirty(), and clear.

Now these functions fail if a page is dirty, locked, or has other
references.

insert() makes room with pop_if_not_dirty() beforehand to handle
cache full and un-evictable, else it would evict this page
silently.

_delete() returns Ok when key is not present in cache and it tries
first to detach the cache entry and clean its page *before*
removing the entry from the map.

detach() checks firstt if it's possible to evict the page and if
there are no other references to the page before taking its
contents.

test_detach_via_delete() and test_detach_via_insert() fixed by
properly checking before and after dropping the page reference.

test_page_cache_fuzz() fixed by reordering and moving reference to
the page into insert.

Other page cache tests fixed to check new function results.

All page cache tests pass.

Error handling and test fixes for Pager and BTree will be added in
a subsequent commit.
2025-05-21 14:09:39 +02:00
Alecco
c8beddab09 page_cache: split unlink() out of detach()
The unlink function removes an entry from the LRU.

The detach function removes an entry in the cache and clears page
contents.
2025-05-21 14:09:39 +02:00
Alecco
6763aa0cd5 page_cache: tests: helper functions and more tests
test_detach_via_insert fails as it repros insert not removing duplicate
page entries with same cache key (id, frame) issue #1348
2025-05-21 14:09:39 +02:00
Alecco
7e898eb8ca page_cache: tests: move helper function up 2025-05-21 14:09:39 +02:00
Jussi Saurio
e4334dcfdf Add enum CursorHasRecord to remove assumption that all btrees have rowid 2025-05-20 14:22:17 +03:00
Jussi Saurio
35350a2368 Add IndexKeyInfo to btree 2025-05-20 14:22:17 +03:00
Pekka Enberg
e102cd0be5 Merge 'Add support for DISTINCT aggregate functions' from Jussi Saurio
Reviewable commit by commit. CI failures are not related.
Adds support for e.g. `select first_name, sum(distinct age),
count(distinct age), avg(distinct age) from users group by 1`
Implementation details:
- Creates an ephemeral index per distinct aggregate, and jumps over the
accumulation step if a duplicate is found

Closes #1507
2025-05-20 13:58:57 +03:00
pedrocarlo
52533cab40 only pass collations for index in cursor + adhere to order of columns in index 2025-05-19 15:22:55 -03:00
pedrocarlo
22b6b88f68 fix rebase type errors 2025-05-19 15:22:55 -03:00
pedrocarlo
4a3119786e refactor BtreeCursor and Sorter to accept Vec of collations 2025-05-19 15:22:55 -03:00
pedrocarlo
f28ce2b757 add collations to btree cursor 2025-05-19 15:22:55 -03:00
pedrocarlo
5bd47d7462 post rebase adjustments to accomodate new instructions that were created before the merge conflicts 2025-05-19 15:22:15 -03:00
Pere Diaz Bou
f2d0d61962 copilot nice suggestions :) 2025-05-19 09:59:28 +02:00
Pere Diaz Bou
5eab588115 improve debug build validation speed
Various things:
* remove unnecessary debug_validate_cell calls
* Add SortedVec for keys in fuzz tests
* Validate btree's depth in fuzz test every 1K inserts to not overload
test with validations. We add `VALIDATE_BTREE`  env variable to enable
validation on every insert in case it is needed.
2025-05-19 09:53:15 +02:00
Jussi Saurio
092462fa74 fix build 2025-05-19 07:29:02 +03:00
Jussi Saurio
7c6a4410d2 Merge '(btree): Implement support for handling offset-based payload access with overflow support' from Krishna Vishal
This PR adds a new function `read_write_payload_with_offset` to support
reading and writing payload data at specific offsets, handling both
local content and overflow pages. This is a port of SQLite's
`accessPayload` function in `btree.c` and will be essential for
supporting incremental blob I/O in the coming PRs.
- Added a state machine called `PayloadOverflowWithOffset` to make the
procedure reentrant.
- Correctly processes both local payload data and payload stored in
overflow pages
Testing:
- Reading and writing to a column with no overflow pages.
- Reading and writing at an offset with overflow pages (spanning 10
pages)

Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #1476
2025-05-18 22:58:10 +03:00
pedrocarlo
fd51c0a970 invalidate records not necessary for fix 2025-05-18 16:43:25 -03:00
pedrocarlo
af1f9492ef fix updating single value 2025-05-17 19:43:24 -03:00
Jussi Saurio
02d8e329ba Fix debug_validate_cells_core() not accepting cells below 4 bytes 2025-05-17 15:33:55 +03:00
Pere Diaz Bou
82e5597b00 long fuzz tests ci on btree changes
The idea is simple, if you modify the btree, we should verify fuzz tests
with long number of iterations to decrease the chance of a regression
2025-05-16 11:26:00 +02:00
Pekka Enberg
a6270e8a6c Merge 'Add libsql_wal_frame_count() API' from Pekka Enberg
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>

Closes #1489
2025-05-15 12:01:45 +03:00
Pekka Enberg
2127de3422 cargo fmt 2025-05-15 12:00:55 +03:00
Pekka Enberg
524a523036 sqlite3: Add libsql_wal_frame_count() API 2025-05-15 11:43:44 +03:00