flatsql 3.1.0 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/PARTITION-STORE.md +101 -1
- package/package.json +1 -1
- package/wasm/flatsql-ps-threads.wasm +0 -0
- package/wasm/integrity.json +3 -3
package/docs/PARTITION-STORE.md
CHANGED
|
@@ -5,7 +5,9 @@ partition logs, one writer per partition on a pinned pool, durable acks,
|
|
|
5
5
|
per-commit indexes, type owners, and durable-tail open. Part II (§12–§21) is
|
|
6
6
|
T2: reader instances and lanes, the snapshot protocol, the SQL surface, the
|
|
7
7
|
fan-out merge, admission and results. Part III (§23–§30) is T3: compaction,
|
|
8
|
-
reclamation, meta-segment retirement, disk accounting and quota.
|
|
8
|
+
reclamation, meta-segment retirement, disk accounting and quota. Part IV
|
|
9
|
+
(§31–) is T3b: store-migrate gseqs, the entry-size setting, hot-partition
|
|
10
|
+
splitting and arrivals compaction. The design is
|
|
9
11
|
the stack's `docs/architecture/flatsql-partition-store.md` (§22 overrides
|
|
10
12
|
§0–§21; §22.4 holds the owner rulings). This file records what was built, how
|
|
11
13
|
to run it, the measured acceptance, and every place the build departs from the
|
|
@@ -978,3 +980,101 @@ checkout at the landed commit; the test enforces the 1.5× bounds on such a box:
|
|
|
978
980
|
```
|
|
979
981
|
cpp/build/flatsql_ps_test --test=compaction_half_dead_T3_1_full --dir=<ext4 dir>
|
|
980
982
|
```
|
|
983
|
+
|
|
984
|
+
# Part IV: T3b
|
|
985
|
+
|
|
986
|
+
## 31. store-migrate gseqs, the entry-size setting, tag conditions
|
|
987
|
+
|
|
988
|
+
store-migrate (T6, design §16.1-5) gives every migrated FIRST copy gseq = its
|
|
989
|
+
legacy `sdn_record_index.rowid`, so per-schema MaxRowID and the FTS rowids
|
|
990
|
+
carry over.
|
|
991
|
+
|
|
992
|
+
- **Input.** `RecordAttr.migrated_gseq` (`ulong`, field 6, appended to
|
|
993
|
+
`schemas/flatsql_attr.fbs`; absent = 0, so older attributes are
|
|
994
|
+
unchanged byte for byte). `buildRecordAttr(..., migratedGseq)` writes it.
|
|
995
|
+
- **Row.** A new PUT whose attribute carries one gets row flag
|
|
996
|
+
`MIGRATED_GSEQ` (0x80). The gseq stays in the attribute (in the same meta
|
|
997
|
+
batch, `ATTR_IN_M`): the RecRow has no spare u64 (offsets 108–127 hold
|
|
998
|
+
`supersedeHash`, `tagHash` and `aux`), and the attribute is as durable as
|
|
999
|
+
the row. Deviation from the T6 proposal "(b) the RecRow reserved u64 at
|
|
1000
|
+
offset 116", which T1's layout had already given to `tagHash`.
|
|
1001
|
+
- **Labeling.** The type owner reads the flagged rows' attributes in windows
|
|
1002
|
+
over the chunk it labels (one read per chunk of up to 4,096 rows when the
|
|
1003
|
+
attributes fit in 1 MiB). A flagged copy labeled FIRST keeps its gseq when it
|
|
1004
|
+
is above the type's committed `gseq_hi` and no arrival of the same type
|
|
1005
|
+
commit holds it; the engine's gseq counter is then raised to at least gseq
|
|
1006
|
+
+ 1. Otherwise it gets an allocated gseq and counts a fallback; a flagged
|
|
1007
|
+
copy labeled REPEAT counts a fallback too. A type commit's new arrivals are
|
|
1008
|
+
sorted by gseq before they are appended, so arrivals stay strictly
|
|
1009
|
+
increasing whatever order partitions are labeled in.
|
|
1010
|
+
- **Counters.** `EngineStats::migratedGseqs` and `migratedGseqFallbacks`,
|
|
1011
|
+
appended to `flatsql_ps_stats` (entries 24 and 25). store-migrate's
|
|
1012
|
+
verification (§16.1-7) needs fallbacks = 0; they are counted per labeling
|
|
1013
|
+
decision, so a type commit that fails and is relabeled counts again.
|
|
1014
|
+
- **Crash.** The gseq is read from durable rows and attributes, so a crash
|
|
1015
|
+
that loses the type commit relabels the same copies with the same gseqs.
|
|
1016
|
+
An allocated fallback gseq that was never published can be reassigned
|
|
1017
|
+
(as for every allocated gseq).
|
|
1018
|
+
- **What T6 must do** (its (d)): feed each type's FIRST copies in rowid
|
|
1019
|
+
order and wait for `labeled_through` before crossing partitions, and run
|
|
1020
|
+
with fallbacks = 0. gseqs are unique per type; across types a fallback could
|
|
1021
|
+
reuse a legacy rowid another type migrates later, which is one more reason
|
|
1022
|
+
a fallback fails the migration.
|
|
1023
|
+
- **Entry size.** Writer TLV 19 = `maxEntryBytes` (u64; default 1 MiB +
|
|
1024
|
+
4 KiB, clamped to [64 KiB, 1 GiB]): the largest ring entry (header,
|
|
1025
|
+
RecordAttr and frame). Each writer's arena grows to at least 4 ×
|
|
1026
|
+
(maxEntryBytes + 4 KiB), so the frames half holds two entries. Frames
|
|
1027
|
+
larger than a segment (A27 jumbo segments) are still not built.
|
|
1028
|
+
|
|
1029
|
+
Tests: `type_migrated_gseq_preserved_fallback_and_stats` (kept, fallback
|
|
1030
|
+
below `gseq_hi`, REPEAT copy, ordinary allocation continues above, flags on
|
|
1031
|
+
disk, reopen), `type_migrated_gseq_one_commit_sorted_and_crash_reopen` (two
|
|
1032
|
+
partitions' interleaved gseqs in one type commit come out sorted; a crash
|
|
1033
|
+
before and after the type commit gives the same arrivals),
|
|
1034
|
+
`writer_max_entry_bytes_configurable` (a 9 MiB frame refused by default,
|
|
1035
|
+
stored and read back at 10 MiB), `writer_capi_tlv19_max_entry_and_stats`
|
|
1036
|
+
(tag 19 through `flatsql_ps_init`, the 26-entry stats array).
|
|
1037
|
+
|
|
1038
|
+
### 31.1 Tag conditions match any live tag instance (A2)
|
|
1039
|
+
|
|
1040
|
+
`_provider`, `_batch`, `_peer_id`, `_source` and `_source_name` conditions
|
|
1041
|
+
have the legacy tag table's ANY-row semantics (`indexedRecordWindowSQL`: a
|
|
1042
|
+
CID matches when one of its tag rows satisfies every requested condition).
|
|
1043
|
+
In format 2 a record's tag instances are its PUT's own tag and its RETAG rows
|
|
1044
|
+
(A2). As T2 built it, the vtab scanned tag postings (which name every
|
|
1045
|
+
instance, RETAGs included) but left each constraint for SQLite to re-check
|
|
1046
|
+
against the projected column, which shows only the PUT's own tag, so every
|
|
1047
|
+
record matched through a RETAG was dropped (T6 #7 on a migrated copy: a
|
|
1048
|
+
provider window of 200 read as 100; a source + batch window lost the
|
|
1049
|
+
re-tagged records).
|
|
1050
|
+
|
|
1051
|
+
Now `xBestIndex` consumes every tag condition (`omit = 1`) and the vtab
|
|
1052
|
+
evaluates them all on one instance:
|
|
1053
|
+
|
|
1054
|
+
- A tag or source posting scan (the plan's key) checks the remaining
|
|
1055
|
+
conditions on the instance the posting names (its RecordAttr), then emits
|
|
1056
|
+
the instance's record. A single condition that is the scanned key needs no
|
|
1057
|
+
attribute read unless the key was capped (over 512 bytes).
|
|
1058
|
+
- Any other plan (CID, column index, epoch, arrivals order, full scan)
|
|
1059
|
+
keeps a record when one of its live tag instances matches every condition
|
|
1060
|
+
(`RowFilter::hasLiveTag`, the TAG_OF postings), as the alias table's source
|
|
1061
|
+
filter already did.
|
|
1062
|
+
- An untagged record matches no tag condition (as the index-driven plans
|
|
1063
|
+
already behaved, T2 deviation 8), and conditions that contradict each other
|
|
1064
|
+
(two sources) return no rows.
|
|
1065
|
+
- `_source = '<TYPE>@<name>'` is compared as the column projects it: the type
|
|
1066
|
+
prefix is case-sensitive (a lower-case prefix returned no rows before
|
|
1067
|
+
either, after SQLite's re-check).
|
|
1068
|
+
- `_peer_id` conditions match the tag's producer peer (the TAG_PEER postings
|
|
1069
|
+
the T2 plan scanned); the `_peer_id` column still projects the storing
|
|
1070
|
+
call's `RecordAttr.peer_id`. Before, SQLite compared that BLOB column with
|
|
1071
|
+
the argument, so a text argument never matched.
|
|
1072
|
+
- `<TYPE>_current` groups first and filters after, as SQL says: its tag
|
|
1073
|
+
conditions stay SQLite's (the current version's own tag).
|
|
1074
|
+
- Projected columns are unchanged: they show the PUT's own tag.
|
|
1075
|
+
|
|
1076
|
+
Test: `lane_tag_conditions_match_any_instance_A2` (two partitions, PUT tags,
|
|
1077
|
+
RETAGs and REPEAT copies; eleven condition sets at type and partition level
|
|
1078
|
+
against an ANY-instance oracle, the full `_source` form, the alias, an
|
|
1079
|
+
epoch-ordered window, column and CID plans). With `omit = 0` restored it
|
|
1080
|
+
fails 18 checks.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flatsql",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "SQL queries over raw FlatBuffer storage: the SQLite-backed wasm engine and the multithreaded partition store (flatsql-ps-threads.wasm)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "wasm/index.js",
|
|
Binary file
|
package/wasm/integrity.json
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"size": 2139350,
|
|
6
6
|
"files": {
|
|
7
7
|
"flatsql-ps-threads.wasm": {
|
|
8
|
-
"sha256": "
|
|
9
|
-
"sri": "sha384-
|
|
10
|
-
"size":
|
|
8
|
+
"sha256": "a90d9488187e527bccd3f02ce3f68be6443690bc1a2ee6c6786c64c907376e36",
|
|
9
|
+
"sri": "sha384-zzvS8qbCe33AJCklxaZX4xr1+QajJAaz0G0FuBv9WyEXh2rSKAz9+Rq4o2XksFaF",
|
|
10
|
+
"size": 2261085
|
|
11
11
|
},
|
|
12
12
|
"flatsql-wasi-noeh.wasm": {
|
|
13
13
|
"sha256": "fd744d4c502310669bc74ab555a36de1692030a0fa6e22fdb1df744809eeacbe",
|