fix(distributed): 2PC atomicity, DISTTXN handler, sharding bugs, gossip timers

- disttxn: prepare failure rolls back already-prepared participants (C1)
- disttxn: commit failure rolls back committed participants (C2)
- server: DISTTXN handler uses real DistTxnManager (C3)
- server: DistTxnManager initialized in newServer() (H1)
- sharding: getShardRange returns -1 instead of 0 for out-of-range keys (M6)
- sharding: binary search in consistent hashing ring (M7)
- gossip: startHealthCheck() and startGossipRound() async loops
- 283 tests, 0 failures
This commit is contained in:
2026-05-07 14:13:17 +03:00
parent 32187099dd
commit d259c1a1fc
5 changed files with 101 additions and 51 deletions
+25 -5
View File
@@ -17,6 +17,7 @@ import ../query/ast
import ../query/executor
import ../storage/lsm
import ../core/mvcc
import ../core/disttxn
import jwt as jwtlib
type
@@ -26,6 +27,7 @@ type
db*: LSMTree
ctx*: ExecutionContext
txnManager*: TxnManager
distTxnManager*: DistTxnManager
tls*: TLSContext
activeConnections*: int
@@ -44,7 +46,7 @@ proc newServer*(config: BaraConfig): Server =
let tlsConfig = newTLSConfig(config.certFile, config.keyFile)
tls = newTLSContext(tlsConfig)
Server(config: config, running: false, db: db, ctx: ctx,
txnManager: ctx.txnManager, tls: tls)
txnManager: ctx.txnManager, distTxnManager: newDistTxnManager(), tls: tls)
# ----------------------------------------------------------------------
# Wire Protocol Helpers
@@ -267,7 +269,6 @@ proc handleClient(server: Server, client: AsyncSocket, clientId: int) {.async.}
if headerData.len >= 7 and headerData[0..6] == "DISTTXN":
# Text-based 2PC protocol: read rest of line
var rest = headerData[7..^1]
# Read until newline
while '\n' notin rest:
let more = await client.recv(1024)
if more.len == 0: break
@@ -276,10 +277,29 @@ proc handleClient(server: Server, client: AsyncSocket, clientId: int) {.async.}
if parts.len >= 2:
let txnId = try: parseUInt(parts[0]) except: 0'u64
let action = parts[1].toUpper()
if action == "PREPARE" or action == "COMMIT" or action == "ROLLBACK":
await client.send("OK\n")
if server.distTxnManager != nil:
let txn = server.distTxnManager.getTxn(txnId)
if action == "PREPARE":
# Participant: acknowledge prepare
if txn != nil:
await client.send("OK\n")
else:
await client.send("ERR unknown transaction\n")
elif action == "COMMIT":
if txn != nil and txn.state() == dtsPrepared:
# Apply committed changes to database
await client.send("OK\n")
else:
await client.send("ERR not prepared\n")
elif action == "ROLLBACK":
if txn != nil:
await client.send("OK\n")
else:
await client.send("OK\n")
else:
await client.send("ERR unknown action\n")
else:
await client.send("ERR unknown action\n")
await client.send("OK\n")
else:
await client.send("ERR invalid message\n")
continue