fix: критични бъгове в storage, MVCC, auth, Raft, query executor
Поправени проблеми: - MVCC: aborted транзакции вече не стават видими (добавено abortedTxns множество) - LSM-Tree: поправена загуба на данни при immutable memtable overwrite - LSM-Tree: поправена SSTable search order (сортиране по id вместо minKey) - WAL: sync()/close() вече извикват posix.fsync() - Auth: simpleHash (djb2) заменен с HMAC-SHA256 - Recovery: summary() вече не мутира базата данни - Raft: поправена majority calculation за четен брой нодове - Query: EXISTS subqueries вече изпълняват подзаявката - Nimble: поправен build (-d:ssl) и bench task Добавен BUG_AUDIT.md с пълен доклад и план за подобрения. 292 теста, 0 failure-а.
This commit is contained in:
@@ -43,6 +43,8 @@ type
|
||||
nextLsn: uint64
|
||||
activeTxns: Table[TxnId, Transaction]
|
||||
committedTxns: seq[TxnId]
|
||||
committedTxnsSet: HashSet[TxnId]
|
||||
abortedTxns: HashSet[TxnId]
|
||||
globalVersions*: Table[string, seq[VersionedRecord]]
|
||||
txnTimeoutMs: int64
|
||||
deadlockDetector*: DeadlockDetector
|
||||
@@ -59,6 +61,8 @@ proc newTxnManager*(txnTimeoutMs: int64 = 30000): TxnManager =
|
||||
result.nextLsn = 1
|
||||
result.activeTxns = initTable[TxnId, Transaction]()
|
||||
result.committedTxns = @[]
|
||||
result.committedTxnsSet = initHashSet[TxnId]()
|
||||
result.abortedTxns = initHashSet[TxnId]()
|
||||
result.globalVersions = initTable[string, seq[VersionedRecord]]()
|
||||
result.txnTimeoutMs = txnTimeoutMs
|
||||
result.deadlockDetector = newDeadlockDetector()
|
||||
@@ -112,8 +116,13 @@ proc isVisible(tm: TxnManager, txn: Transaction, version: VersionedRecord): bool
|
||||
return false
|
||||
if creator in txn.snapshotTxns:
|
||||
return false
|
||||
if creator in tm.abortedTxns:
|
||||
return false
|
||||
if creator in tm.activeTxns and tm.activeTxns[creator].state != tsCommitted:
|
||||
return false
|
||||
# If creator is not active and not committed, it must be aborted
|
||||
if creator notin tm.activeTxns and creator notin tm.committedTxnsSet:
|
||||
return false
|
||||
|
||||
# Deleter must not be a visible committed txn
|
||||
if deleter != TxnId(0):
|
||||
@@ -246,6 +255,7 @@ proc commit*(tm: TxnManager, txn: Transaction): bool =
|
||||
|
||||
txn.state = tsCommitted
|
||||
tm.committedTxns.add(txn.id)
|
||||
tm.committedTxnsSet.incl(txn.id)
|
||||
tm.activeTxns.del(txn.id)
|
||||
tm.deadlockDetector.removeTxn(uint64(txn.id))
|
||||
release(tm.lock)
|
||||
@@ -258,6 +268,7 @@ proc abortTxn*(tm: TxnManager, txn: Transaction): bool =
|
||||
return false
|
||||
txn.state = tsAborted
|
||||
tm.activeTxns.del(txn.id)
|
||||
tm.abortedTxns.incl(txn.id)
|
||||
tm.deadlockDetector.removeTxn(uint64(txn.id))
|
||||
release(tm.lock)
|
||||
return true
|
||||
|
||||
@@ -290,7 +290,7 @@ proc handleAppendReply*(node: RaftNode, peerId: string, reply: RaftMessage) =
|
||||
matchIndices.add(idx)
|
||||
matchIndices.sort()
|
||||
|
||||
let medianIdx = matchIndices[matchIndices.len div 2]
|
||||
let medianIdx = matchIndices[(matchIndices.len - 1) div 2]
|
||||
if medianIdx > node.commitIndex:
|
||||
if medianIdx <= node.lastLogIndex and
|
||||
node.log[medianIdx - 1].term == node.currentTerm:
|
||||
|
||||
Reference in New Issue
Block a user