Skip to content

Commit 45d1375

Browse files
committed
Merge branch 'main' into pr/rescore
2 parents 69f7b65 + 69ccb24 commit 45d1375

8 files changed

Lines changed: 122 additions & 27 deletions

File tree

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ ifndef OMIT_SIMD
4343
CFLAGS += -mcpu=apple-m1 -DSQLITE_VEC_ENABLE_NEON
4444
endif
4545
ifeq ($(shell uname -s),Linux)
46+
ifeq ($(findstring android,$(CC)),)
4647
ifneq ($(filter avx,$(shell grep -o 'avx[^ ]*' /proc/cpuinfo 2>/dev/null | head -1)),)
4748
CFLAGS += -mavx -DSQLITE_VEC_ENABLE_AVX
4849
endif
4950
endif
51+
endif
5052
endif
5153

5254
ifdef USE_BREW_SQLITE

TODO.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# TODO: `ann` base branch + consolidated benchmarks
2+
3+
## 1. Create `ann` branch with shared code
4+
5+
### 1.1 Branch setup
6+
- [x] `git checkout -B ann origin/main`
7+
- [x] Cherry-pick `624f998` (vec0_distance_full shared distance dispatch)
8+
- [x] Cherry-pick stdint.h fix for test header
9+
- [ ] Pull NEON cosine optimization from ivf-yolo3 into shared code
10+
- Currently only in ivf branch but is general-purpose (benefits all distance calcs)
11+
- Lives in `distance_cosine_float()`~57 lines of ARM NEON vectorized cosine
12+
13+
### 1.2 Benchmark infrastructure (`benchmarks-ann/`)
14+
- [x] Seed data pipeline (`seed/Makefile`, `seed/build_base_db.py`)
15+
- [x] Ground truth generator (`ground_truth.py`)
16+
- [x] Results schema (`schema.sql`)
17+
- [x] Benchmark runner with `INDEX_REGISTRY` extension point (`bench.py`)
18+
- Baseline configs (float, int8-rescore, bit-rescore) implemented
19+
- Index branches register their types via `INDEX_REGISTRY` dict
20+
- [x] Makefile with baseline targets
21+
- [x] README
22+
23+
### 1.3 Rebase feature branches onto `ann`
24+
- [x] Rebase `diskann-yolo2` onto `ann` (1 commit: DiskANN implementation)
25+
- [x] Rebase `ivf-yolo3` onto `ann` (1 commit: IVF implementation)
26+
- [x] Rebase `annoy-yolo2` onto `ann` (2 commits: Annoy implementation + schema fix)
27+
- [x] Verify each branch has only its index-specific commits remaining
28+
- [ ] Force-push all 4 branches to origin
29+
30+
---
31+
32+
## 2. Per-branch: register index type in benchmarks
33+
34+
Each index branch should add to `benchmarks-ann/` when rebased onto `ann`:
35+
36+
### 2.1 Register in `bench.py`
37+
38+
Add an `INDEX_REGISTRY` entry. Each entry provides:
39+
- `defaults` — default param values
40+
- `create_table_sql(params)` — CREATE VIRTUAL TABLE with INDEXED BY clause
41+
- `insert_sql(params)` — custom insert SQL, or None for default
42+
- `post_insert_hook(conn, params)` — training/building step, returns time
43+
- `run_query(conn, params, query, k)` — custom query, or None for default MATCH
44+
- `describe(params)` — one-line description for report output
45+
46+
### 2.2 Add configs to `Makefile`
47+
48+
Append index-specific config variables and targets. Example pattern:
49+
50+
```makefile
51+
DISKANN_CONFIGS = \
52+
"diskann-R48-binary:type=diskann,R=48,L=128,quantizer=binary" \
53+
...
54+
55+
ALL_CONFIGS += $(DISKANN_CONFIGS)
56+
57+
bench-diskann: seed
58+
$(BENCH) --subset-size 10000 -k 10 -o runs/diskann $(BASELINES) $(DISKANN_CONFIGS)
59+
...
60+
```
61+
62+
### 2.3 Migrate existing benchmark results/docs
63+
64+
- Move useful results docs (RESULTS.md, etc.) into `benchmarks-ann/results/`
65+
- Delete redundant per-branch benchmark directories once consolidated infra is proven
66+
67+
---
68+
69+
## 3. Future improvements
70+
71+
- [ ] Reporting script (`report.py`) — query results.db, produce markdown comparison tables
72+
- [ ] Profiling targets in Makefile (lift from ivf-yolo3's Instruments/perf wrappers)
73+
- [ ] Pre-computed ground truth integration (use GT DB files instead of on-the-fly brute-force)

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.8
1+
0.1.9

benchmarks-ann/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ bench-rescore: seed
4949
$(BENCH) --subset-size 10000 -k 10 -o runs/rescore \
5050
$(RESCORE_CONFIGS)
5151

52+
5253
# --- Standard sizes ---
5354
bench-10k: seed
5455
$(BENCH) --subset-size 10000 -k 10 -o runs/10k $(ALL_CONFIGS)

sqlite-vec.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2553,6 +2553,7 @@ struct Vec0RescoreConfig {
25532553
};
25542554
#endif
25552555

2556+
25562557
struct VectorColumnDefinition {
25572558
char *name;
25582559
int name_length;
@@ -8899,11 +8900,17 @@ int vec0Update_Delete_ClearMetadata(vec0_vtab *p, int metadata_idx, i64 rowid, i
88998900
}
89008901
sqlite3_bind_int64(stmt, 1, rowid);
89018902
rc = sqlite3_step(stmt);
8903+
sqlite3_finalize(stmt);
89028904
if(rc != SQLITE_DONE) {
89038905
rc = SQLITE_ERROR;
89048906
goto done;
89058907
}
8906-
sqlite3_finalize(stmt);
8908+
// Fix for https://github.com/asg017/sqlite-vec/issues/274
8909+
// sqlite3_step returns SQLITE_DONE (101) on DML success, but the
8910+
// `done:` epilogue treats anything other than SQLITE_OK as an error.
8911+
// Without this, SQLITE_DONE propagates up to vec0Update_Delete,
8912+
// which aborts the DELETE scan and silently drops remaining rows.
8913+
rc = SQLITE_OK;
89078914
}
89088915
break;
89098916
}

tests/__snapshots__/test-metadata.ambr

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
OrderedDict({
2828
'chunk_id': 1,
2929
'size': 8,
30-
'validity': b'\x06',
31-
'rowids': b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
30+
'validity': b'\x02',
31+
'rowids': b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
3232
}),
3333
]),
3434
}),
@@ -37,7 +37,7 @@
3737
'rows': list([
3838
OrderedDict({
3939
'rowid': 1,
40-
'data': b'\x06',
40+
'data': b'\x02',
4141
}),
4242
]),
4343
}),
@@ -46,7 +46,7 @@
4646
'rows': list([
4747
OrderedDict({
4848
'rowid': 1,
49-
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
49+
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
5050
}),
5151
]),
5252
}),
@@ -55,7 +55,7 @@
5555
'rows': list([
5656
OrderedDict({
5757
'rowid': 1,
58-
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x99\x99\x99\x99\x99\x01@ffffff\n@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
58+
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x9a\x99\x99\x99\x99\x99\x01@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
5959
}),
6060
]),
6161
}),
@@ -64,17 +64,13 @@
6464
'rows': list([
6565
OrderedDict({
6666
'rowid': 1,
67-
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00test2\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00123456789012\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
67+
'data': b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00test2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
6868
}),
6969
]),
7070
}),
7171
'v_metadatatext03': OrderedDict({
7272
'sql': 'select * from v_metadatatext03',
7373
'rows': list([
74-
OrderedDict({
75-
'rowid': 3,
76-
'data': '1234567890123',
77-
}),
7874
]),
7975
}),
8076
'v_rowids': OrderedDict({
@@ -86,20 +82,14 @@
8682
'chunk_id': 1,
8783
'chunk_offset': 1,
8884
}),
89-
OrderedDict({
90-
'rowid': 3,
91-
'id': None,
92-
'chunk_id': 1,
93-
'chunk_offset': 2,
94-
}),
9585
]),
9686
}),
9787
'v_vector_chunks00': OrderedDict({
9888
'sql': 'select * from v_vector_chunks00',
9989
'rows': list([
10090
OrderedDict({
10191
'rowid': 1,
102-
'vectors': b'\x00\x00\x00\x00""""3333\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
92+
'vectors': b'\x00\x00\x00\x00""""\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
10393
}),
10494
]),
10595
}),
@@ -370,14 +360,6 @@
370360
'f': 2.2,
371361
't': 'test2',
372362
}),
373-
OrderedDict({
374-
'rowid': 3,
375-
'vector': b'3333',
376-
'b': 1,
377-
'n': 3,
378-
'f': 3.3,
379-
't': '1234567890123',
380-
}),
381363
]),
382364
})
383365
# ---

tests/sqlite-vec-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ struct Vec0RescoreConfig {
8282
};
8383
#endif
8484

85+
8586
struct VectorColumnDefinition {
8687
char *name;
8788
int name_length;

tests/test-metadata.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,35 @@ def test_deletes(db, snapshot):
265265
assert vec0_shadow_table_contents(db, "v") == snapshot()
266266

267267

268+
def test_delete_by_metadata_with_long_text(db):
269+
"""Regression for https://github.com/asg017/sqlite-vec/issues/274.
270+
271+
ClearMetadata left rc=SQLITE_DONE after the long-text DELETE, which
272+
propagated as an error and silently aborted the DELETE scan.
273+
"""
274+
db.execute(
275+
"create virtual table v using vec0("
276+
" tag text, embedding float[4], chunk_size=8"
277+
")"
278+
)
279+
for i in range(6):
280+
db.execute(
281+
"insert into v(tag, embedding) values (?, zeroblob(16))",
282+
[f"long_text_value_{i}"],
283+
)
284+
for i in range(4):
285+
db.execute(
286+
"insert into v(tag, embedding) values (?, zeroblob(16))",
287+
[f"long_text_value_0"],
288+
)
289+
assert db.execute("select count(*) from v").fetchone()[0] == 10
290+
291+
# DELETE by metadata WHERE — the pattern from the issue
292+
db.execute("delete from v where tag = 'long_text_value_0'")
293+
assert db.execute("select count(*) from v where tag = 'long_text_value_0'").fetchone()[0] == 0
294+
assert db.execute("select count(*) from v").fetchone()[0] == 5
295+
296+
268297
def test_knn(db, snapshot):
269298
db.execute(
270299
"create virtual table v using vec0(vector float[1], name text, chunk_size=8)"

0 commit comments

Comments
 (0)