core/storage: Switch page cache queue to linked list

The page cache implementation uses a pre-allocated vector (`entries`)
with fixed capacity, along with a custom hash map and freelist. This
design requires expensive upfront allocation when creating a new
connection, which severely impacted performance in workloads that open
many short-lived connections (e.g., our concurrent write benchmarks that
create a new connection per transaction).

Therefore, replace the pre-allocated vector with an intrusive
doubly-linked list. This eliminates the page cache initialization
overhead from connection establishment, but also reduces memory usage to
entries that are actually used. Furthermore, the approach allows us to
grow the page cache with much less overhead.

The patch improves concurrent write throughput benchmark by 4x for
single-threaded performance.

Before:

```
$ write-throughput --threads 1 --batch-size 100 -i 1000 --mode concurrent
Running write throughput benchmark with 1 threads, 100 batch size, 1000 iterations, mode: Concurrent
Database created at: write_throughput_test.db
Thread 0: 100000 inserts in 3.82s (26173.63 inserts/sec)
```

After:

```
$ write-throughput --threads 1 --batch-size 100 -i 1000 --mode concurrent
Running write throughput benchmark with 1 threads, 100 batch size, 1000 iterations, mode: Concurrent
Database created at: write_throughput_test.db
Thread 0: 100000 inserts in 0.90s (110848.46 inserts/sec)
```
This commit is contained in:
Pekka Enberg
2025-09-30 12:36:13 +03:00
parent 6fd2ad2f5e
commit 2b168cf7b0
3 changed files with 296 additions and 614 deletions

10
Cargo.lock generated
View File

@@ -2000,6 +2000,15 @@ dependencies = [
"generic-array",
]
[[package]]
name = "intrusive-collections"
version = "0.9.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "189d0897e4cbe8c75efedf3502c18c887b05046e59d28404d4d8e46cbc4d1e86"
dependencies = [
"memoffset",
]
[[package]]
name = "io-uring"
version = "0.7.6"
@@ -4415,6 +4424,7 @@ dependencies = [
"fallible-iterator",
"getrandom 0.2.15",
"hex",
"intrusive-collections",
"io-uring",
"julian_day_converter",
"libc",

View File

@@ -81,6 +81,7 @@ aes = { version = "0.8.4"}
turso_parser = { workspace = true }
aegis = "0.9.0"
twox-hash = "2.1.1"
intrusive-collections = "0.9.7"
[build-dependencies]
chrono = { workspace = true, default-features = false }

File diff suppressed because it is too large Load Diff