fix(raft): multi-stmt write gate, rich apply, delete kv convention
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
- Reject follower writes if any statement in the batch is DML/COMMIT (not only stmts[0]). - COMMIT always emits empty-valued kvPairs for isDelete entries. - applyCommand updates LSM plus secondary B-tree/FTS/HNSW indexes (applyReplicatedPut/Delete) so follower index scans see replicated rows. - Tests: not-leader append, commit timeout, index apply unit, E2E index-backed SELECT on follower.
This commit is contained in:
@@ -211,14 +211,15 @@ proc runWritesScenario() =
|
||||
return
|
||||
echo "leader elected: ", nodes[leaderIdx].id, " (term ", leaderTerm, ")"
|
||||
|
||||
# Schema: CREATE TABLE is not a raft write (DML only is), and its _schema
|
||||
# keys are not replicated — create the table locally on every node.
|
||||
# Schema: CREATE TABLE / INDEX are not raft writes (no kvPairs), and
|
||||
# _schema keys are not replicated — create them locally on every node.
|
||||
for i in 0 ..< nodes.len:
|
||||
let db = openClient(nodes[i].clientPort)
|
||||
try:
|
||||
db.exec(sql"CREATE TABLE rw_test (id INT PRIMARY KEY, name STRING)")
|
||||
db.exec(sql"CREATE INDEX idx_rw_name ON rw_test (name)")
|
||||
except CatchableError as e:
|
||||
echo "CREATE TABLE failed on ", nodes[i].id, ": ", e.msg
|
||||
echo "CREATE TABLE/INDEX failed on ", nodes[i].id, ": ", e.msg
|
||||
dumpAll(nodes)
|
||||
fail()
|
||||
return
|
||||
@@ -250,6 +251,31 @@ proc runWritesScenario() =
|
||||
return
|
||||
echo "row replicated to follower ", nodes[followerIdx].id
|
||||
|
||||
# Index path: rich apply must have updated the follower B-tree so a
|
||||
# filtered SELECT (planner prefers secondary index) still finds the row.
|
||||
block:
|
||||
let db = openClient(nodes[followerIdx].clientPort)
|
||||
var saw = false
|
||||
try:
|
||||
let rows = db.getAllRows(
|
||||
sql"SELECT id, name FROM rw_test WHERE name = 'raft-row'")
|
||||
for row in rows:
|
||||
if row.len >= 2 and row[1] == "raft-row":
|
||||
saw = true
|
||||
except CatchableError as e:
|
||||
echo "follower index SELECT failed: ", e.msg
|
||||
dumpAll(nodes)
|
||||
fail()
|
||||
return
|
||||
db.close()
|
||||
if not saw:
|
||||
echo "follower ", nodes[followerIdx].id,
|
||||
" index-backed SELECT missed the replicated row"
|
||||
dumpAll(nodes)
|
||||
fail()
|
||||
return
|
||||
echo "follower index-backed SELECT saw the row"
|
||||
|
||||
# Follower rejection: DML on a follower must fail with "not leader".
|
||||
block:
|
||||
let db = openClient(nodes[followerIdx].clientPort)
|
||||
|
||||
Reference in New Issue
Block a user