Skip to content

Commit 4a2872e

Browse files
authored
Merge pull request #480 from tidesdb/reference-docs-updates
update ffi library references to align with their current versions
2 parents 4b07776 + 8235c15 commit 4a2872e

10 files changed

Lines changed: 210 additions & 14 deletions

File tree

public/analysis-tidesql-v4-3-0-mariadb-v11-8-6-tpc-c/iibench-results-2026-04-23/bench_batch_sweep.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def start_mariadbd():
8181

8282

8383
def patch_header(bulk_ops, idx_batch):
84-
"""Rewrite the two batch constants in ha_tidesdb.h. Idempotent always starts
84+
"""Rewrite the two batch constants in ha_tidesdb.h. Idempotent - always starts
8585
from the pristine header backup."""
8686
with open(HEADER_BAK) as f:
8787
src = f.read()

src/content/docs/reference/cplusplus.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,18 @@ txn.del(cf, "key");
231231
txn.commit();
232232
```
233233

234+
#### Single Delete
235+
236+
`singleDelete` emits a single-delete tombstone. When the tombstone meets exactly one prior put for the same key during compaction, both records are dropped, so the tombstone does not persist past its matching put. Use it only when the caller guarantees at most one put precedes the delete; otherwise prefer `del`.
237+
238+
```cpp
239+
auto cf = db.getColumnFamily("my_cf");
240+
241+
auto txn = db.beginTransaction();
242+
txn.singleDelete(cf, "key");
243+
txn.commit();
244+
```
245+
234246
#### Multi-Operation Transactions
235247

236248
```cpp
@@ -1093,7 +1105,7 @@ Use `ObjectStoreConfig::defaultConfig()` for sensible defaults, then override fi
10931105

10941106
### Per-CF Object Store Tuning
10951107

1096-
Column family configurations include three object store tuning fields.
1108+
Column family configurations include two object store tuning fields.
10971109

10981110
- `objectLazyCompaction` · 1 to compact less aggressively for remote storage (default: 0)
10991111
- `objectPrefetchCompaction` · 1 to download all inputs before compaction merge (default: 1)

src/content/docs/reference/csharp.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ You **must** have the TidesDB shared C library installed on your system. You can
1919

2020
### Installation
2121

22+
Install the package from NuGet:
23+
24+
```bash
25+
dotnet add package TidesDB
26+
```
27+
28+
Or build from source:
29+
2230
```bash
2331
git clone https://github.com/tidesdb/tidesdb-cs.git
2432
cd tidesdb-cs
@@ -326,6 +334,26 @@ txn.Delete(cf, Encoding.UTF8.GetBytes("key"));
326334
txn.Commit();
327335
```
328336

337+
#### Single-Delete
338+
339+
`Transaction.SingleDelete` writes a tombstone with the same read semantics as `Delete`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
340+
341+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
342+
343+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key.
344+
345+
```csharp
346+
var cf = db.GetColumnFamily("my_cf")!;
347+
348+
using var txn = db.BeginTransaction();
349+
350+
txn.SingleDelete(cf, Encoding.UTF8.GetBytes("key"));
351+
352+
txn.Commit();
353+
```
354+
355+
When in doubt, prefer `Transaction.Delete`.
356+
329357
#### Multi-Operation Transactions
330358

331359
```csharp
@@ -1236,6 +1264,7 @@ using TidesDB;
12361264
// -- ColumnFamily.UpdateRuntimeConfig(ColumnFamilyConfig config, bool persistToDisk)
12371265
// -- ColumnFamily.Purge()
12381266
// -- ColumnFamily.SyncWal()
1267+
// -- Transaction.SingleDelete(ColumnFamily cf, ReadOnlySpan<byte> key)
12391268
// -- Iterator.KeyValue()
12401269
12411270
// Enums

src/content/docs/reference/go.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,39 @@ if err != nil {
408408
}
409409
```
410410

411+
#### Single-Delete
412+
413+
`SingleDelete` writes a tombstone with the same read semantics as `Delete`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
414+
415+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
416+
417+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key.
418+
419+
```go
420+
cf, err := db.GetColumnFamily("my_cf")
421+
if err != nil {
422+
log.Fatal(err)
423+
}
424+
425+
txn, err := db.BeginTxn()
426+
if err != nil {
427+
log.Fatal(err)
428+
}
429+
defer txn.Free()
430+
431+
err = txn.SingleDelete(cf, []byte("key"))
432+
if err != nil {
433+
log.Fatal(err)
434+
}
435+
436+
err = txn.Commit()
437+
if err != nil {
438+
log.Fatal(err)
439+
}
440+
```
441+
442+
Returns `nil` on success or a non-nil error on failure. When in doubt, prefer `Delete`.
443+
411444
#### Multi-Operation Transactions
412445

413446
```go
@@ -1807,4 +1840,7 @@ go test -v -run TestCfConfigIni
18071840

18081841
# Run error code readonly test
18091842
go test -v -run TestErrorCodeReadonly
1843+
1844+
# Run single-delete transaction test
1845+
go test -v -run TestTransactionSingleDelete
18101846
```

src/content/docs/reference/java.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,25 @@ try (Transaction txn = db.beginTransaction()) {
192192
}
193193
```
194194

195+
#### Single-Delete
196+
197+
`txn.singleDelete` writes a tombstone with the same read semantics as `txn.delete`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
198+
199+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
200+
201+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key.
202+
203+
```java
204+
ColumnFamily cf = db.getColumnFamily("my_cf");
205+
206+
try (Transaction txn = db.beginTransaction()) {
207+
txn.singleDelete(cf, "key".getBytes());
208+
txn.commit();
209+
}
210+
```
211+
212+
When in doubt, prefer `txn.delete`.
213+
195214
#### Transaction Rollback
196215

197216
```java
@@ -748,7 +767,7 @@ try (TidesDB db = TidesDB.open(config)) {
748767

749768
### Per-CF Object Store Tuning
750769

751-
Column family configurations include three object store tuning fields:
770+
Column family configurations include two object store tuning fields:
752771

753772
```java
754773
ColumnFamilyConfig cfConfig = ColumnFamilyConfig.builder()

src/content/docs/reference/lua.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,27 @@ txn:commit()
270270
txn:free()
271271
```
272272

273+
#### Single-Delete
274+
275+
`txn:single_delete(cf, key)` writes a tombstone with the same read semantics as `txn:delete`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
276+
277+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
278+
279+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key.
280+
281+
```lua
282+
local cf = db:get_column_family("my_cf")
283+
284+
local txn = db:begin_txn()
285+
286+
txn:single_delete(cf, "mykey")
287+
288+
txn:commit()
289+
txn:free()
290+
```
291+
292+
When in doubt, prefer `txn:delete`.
293+
273294
#### Multi-Operation Transactions
274295

275296
```lua
@@ -1401,6 +1422,7 @@ lua test_tidesdb.lua
14011422
| `txn:put(cf, key, value, ttl)` | Put a key-value pair |
14021423
| `txn:get(cf, key)` | Get a value by key |
14031424
| `txn:delete(cf, key)` | Delete a key |
1425+
| `txn:single_delete(cf, key)` | Delete a key with at-most-one-put promise (see Single-Delete) |
14041426
| `txn:commit()` | Commit the transaction |
14051427
| `txn:rollback()` | Rollback the transaction |
14061428
| `txn:reset(isolation)` | Reset transaction for reuse with new isolation level |

src/content/docs/reference/python.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,24 @@ with db.begin_txn() as txn:
202202
txn.commit()
203203
```
204204

205+
### Single-Delete
206+
207+
`single_delete` writes a tombstone with the same read semantics as `delete`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
208+
209+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
210+
211+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key.
212+
213+
```python
214+
cf = db.get_column_family("my_cf")
215+
216+
with db.begin_txn() as txn:
217+
txn.single_delete(cf, b"mykey")
218+
txn.commit()
219+
```
220+
221+
When in doubt, prefer `delete`.
222+
205223
### Transaction Reset
206224

207225
`reset()` resets a committed or aborted transaction for reuse with a new isolation level. This avoids the overhead of freeing and reallocating transaction resources in hot loops.

src/content/docs/reference/rust.md

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ The easiest way to add TidesDB to your project is via [crates.io](https://crates
4040

4141
```toml
4242
[dependencies]
43-
tidesdb = "0.6"
43+
tidesdb = "0.7"
4444
```
4545

4646
Or using `cargo add`:
@@ -65,22 +65,22 @@ Each crate release defaults to a specific TidesDB C library version. You can sel
6565

6666
```toml
6767
[dependencies]
68-
# Uses the default version (currently v9.0.6)
69-
tidesdb = "0.6"
68+
# Uses the default version (currently v9.1.0)
69+
tidesdb = "0.7"
7070

7171
# Pin to a specific TidesDB version
72-
tidesdb = { version = "0.6", default-features = false, features = ["v9_0_5"] }
72+
tidesdb = { version = "0.7", default-features = false, features = ["v9_0_5"] }
7373
```
7474

75-
Only one version feature can be enabled at a time. The version feature (e.g., `v9_0_6`) maps directly to the TidesDB C library release tag (e.g., `v9.0.6`).
75+
Only one version feature can be enabled at a time. The version feature (e.g., `v9_1_0`) maps directly to the TidesDB C library release tag (e.g., `v9.1.0`).
7676

7777
### Object Store Support
7878

7979
To enable S3 object store support, enable the `objectstore` feature:
8080

8181
```toml
8282
[dependencies]
83-
tidesdb = { version = "0.6", features = ["objectstore"] }
83+
tidesdb = { version = "0.7", features = ["objectstore"] }
8484
```
8585

8686
This requires additional dependencies:
@@ -369,6 +369,41 @@ fn main() -> tidesdb::Result<()> {
369369
}
370370
```
371371

372+
#### Single-Delete
373+
374+
`Transaction::single_delete` writes a tombstone with the same read semantics as `Transaction::delete`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
375+
376+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
377+
378+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key. When in doubt, prefer `Transaction::delete`.
379+
380+
Requires tidesdb >= 9.1.0 (the `v9_1_0` Cargo feature, enabled by default in `tidesdb` 0.7).
381+
382+
```rust
383+
use tidesdb::{TidesDB, Config, ColumnFamilyConfig};
384+
385+
fn main() -> tidesdb::Result<()> {
386+
let db = TidesDB::open(Config::new("./mydb"))?;
387+
db.create_column_family("my_cf", ColumnFamilyConfig::default())?;
388+
389+
let cf = db.get_column_family("my_cf")?;
390+
391+
let mut txn = db.begin_transaction()?;
392+
txn.single_delete(&cf, b"key")?;
393+
txn.commit()?;
394+
395+
Ok(())
396+
}
397+
```
398+
399+
Signature:
400+
401+
```rust
402+
pub fn single_delete(&self, cf: &ColumnFamily, key: &[u8]) -> Result<()>;
403+
```
404+
405+
Returns `Ok(())` on success or an `Error` on failure.
406+
372407
#### Multi-Operation Transactions
373408

374409
```rust

src/content/docs/reference/tidesql.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -208,20 +208,20 @@ The engine supports Index Condition Pushdown for secondary index scans. When the
208208

209209
### Multi-Range Read (MRR)
210210

211-
The engine implements a custom MRR path for point-lookup batches such as `WHERE col IN (v1, v2, ..., vN)` on a primary or full-key unique index. When every range the optimizer hands the engine is a full-key point equality (`UNIQUE_RANGE | EQ_RANGE`) and there are at least two ranges, the engine buffers them, converts each key into comparable bytes, and sorts by those bytes so the LSM sees a monotone stream of seeks much friendlier to the block cache and the merge-heap than N scattered seeks in user-supplied order. Primary-key lookups bypass the iterator entirely via `fetch_row_by_pk`; secondary-index lookups reuse a single cached iterator and do one seek per entry. Ranges whose rows have been deleted concurrently are silently skipped.
211+
The engine implements a custom MRR path for point-lookup batches such as `WHERE col IN (v1, v2, ..., vN)` on a primary or full-key unique index. When every range the optimizer hands the engine is a full-key point equality (`UNIQUE_RANGE | EQ_RANGE`) and there are at least two ranges, the engine buffers them, converts each key into comparable bytes, and sorts by those bytes so the LSM sees a monotone stream of seeks - much friendlier to the block cache and the merge-heap than N scattered seeks in user-supplied order. Primary-key lookups bypass the iterator entirely via `fetch_row_by_pk`; secondary-index lookups reuse a single cached iterator and do one seek per entry. Ranges whose rows have been deleted concurrently are silently skipped.
212212

213213
The engine deliberately declines MRR in three cases, falling back to the base handler's default implementation:
214214

215-
- Single-range scans (`count < 2`) MRR has no sorting win for one key, and the eq_ref path is where pessimistic row locking engages.
216-
- Non-point ranges true `BETWEEN`/`<`/`>` scans stay on `read_range_first`.
217-
- Partitioned tables `ha_partition` already dispatches MRR across children using its own DS-MRR logic.
215+
- Single-range scans (`count < 2`) - MRR has no sorting win for one key, and the eq_ref path is where pessimistic row locking engages.
216+
- Non-point ranges - true `BETWEEN`/`<`/`>` scans stay on `read_range_first`.
217+
- Partitioned tables - `ha_partition` already dispatches MRR across children using its own DS-MRR logic.
218218

219219

220220
## Auto-Increment
221221

222222
Auto-increment works in a similar way to InnoDB. The engine calls MariaDB's built-in `update_auto_increment()` mechanism during `write_row()`. Rather than calling `index_last()` on every INSERT (which would create and destroy a TidesDB merge-heap iterator each time), the engine maintains an in-memory atomic counter on the shared table descriptor. The counter is seeded once at table open time by seeking to the last key in the primary key column family, and is atomically incremented via a CAS loop on each INSERT - making auto-increment assignment O(1). When a user inserts an explicit value larger than the current counter, `write_row()` bumps the counter to match.
223223

224-
`TRUNCATE TABLE` and `ALTER TABLE ... AUTO_INCREMENT=N` both reset the counter via the engine's `reset_auto_increment` handler hook the next generated ID equals `N` (or `1` after a bare `TRUNCATE`). This applies to both user-defined AUTO_INCREMENT columns and hidden-PK tables.
224+
`TRUNCATE TABLE` and `ALTER TABLE ... AUTO_INCREMENT=N` both reset the counter via the engine's `reset_auto_increment` handler hook - the next generated ID equals `N` (or `1` after a bare `TRUNCATE`). This applies to both user-defined AUTO_INCREMENT columns and hidden-PK tables.
225225

226226
```sql
227227
CREATE TABLE tickets (

src/content/docs/reference/typescript.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ You **must** have the TidesDB shared C library installed on your system. You ca
2323
npm install git+https://github.com/tidesdb/tidesdb-node.git
2424
```
2525

26+
```bash
27+
npm i @tidesdb/tidesdb
28+
```
29+
2630
Or clone and install locally:
2731

2832
```bash
@@ -208,6 +212,27 @@ txn.commit();
208212
txn.free();
209213
```
210214

215+
#### Single-Delete
216+
217+
`txn.singleDelete()` writes a tombstone with the same read semantics as `txn.delete()`, but carries a caller-provided promise that lets compaction drop the put and the tombstone together as soon as both appear in the same merge input, rather than carrying the tombstone forward until it reaches the largest active level.
218+
219+
Between any two single-deletes on the same key, and between the start of the key's history and its first single-delete, the key has been put **at most once**. The engine does not and cannot verify this at runtime; violating the contract can leave older puts visible after the single-delete and is a bug in the caller.
220+
221+
This is the right choice for workloads that insert each key exactly once and then delete it exactly once (classic insert-benchmark patterns, secondary-index entries on columns that are never updated, log-style tables with scheduled purges). It is **not** safe for tables that issue repeated updates to the same key.
222+
223+
```typescript
224+
const cf = db.getColumnFamily('my_cf');
225+
226+
const txn = db.beginTransaction();
227+
228+
txn.singleDelete(cf, Buffer.from('key'));
229+
230+
txn.commit();
231+
txn.free();
232+
```
233+
234+
When in doubt, prefer `txn.delete()`.
235+
211236
#### Multi-Operation Transactions
212237

213238
```typescript

0 commit comments

Comments
 (0)