feat: Phase 5-6 — CREATE VIEW, migrations, deadlock detection, JSON logging, admin UI
Phase 5 — ERP Features: - CREATE VIEW name AS SELECT ... — parser + executor with view expansion - DROP VIEW — parser + executor - CREATE MIGRATION name AS 'sql' — parser + executor, stored in LSM-Tree - APPLY MIGRATION name — parser + executor, replays stored migration SQL - Views table in ExecutionContext, expanded on SELECT FROM view Phase 6 — Production Readiness: - Deadlock detection: timeout-based auto-abort for stale transactions (30s default) - TxnManager.txnTimeoutMs configurable - Structured JSON logging module (logging.nim) with levels: debug/info/warn/error - Admin dashboard Web UI at GET /admin — SQL playground, schema browser, metrics - Dark theme HTML/CSS with tabs Lexer: added tkView, tkMigration, tkApply tokens Parser: parseCreateView, parseDropView, parseCreateMigration, parseApplyMigration AST: nkCreateView, nkDropView, nkCreateMigration, nkApplyMigration nodes All 216 tests pass
This commit is contained in:
@@ -42,14 +42,15 @@ type
|
||||
nextLsn: uint64
|
||||
activeTxns: Table[TxnId, Transaction]
|
||||
committedTxns: seq[TxnId]
|
||||
globalVersions*: Table[string, seq[VersionedRecord]] # key -> versions
|
||||
globalVersions*: Table[string, seq[VersionedRecord]]
|
||||
txnTimeoutMs: int64
|
||||
|
||||
proc `==`*(a, b: TxnId): bool {.borrow.}
|
||||
proc `==`*(a, b: Lsn): bool {.borrow.}
|
||||
proc `$`*(id: TxnId): string = $uint64(id)
|
||||
proc `$`*(lsn: Lsn): string = $uint64(lsn)
|
||||
|
||||
proc newTxnManager*(): TxnManager =
|
||||
proc newTxnManager*(txnTimeoutMs: int64 = 30000): TxnManager =
|
||||
new(result)
|
||||
initLock(result.lock)
|
||||
result.nextTxnId = 1
|
||||
@@ -57,6 +58,7 @@ proc newTxnManager*(): TxnManager =
|
||||
result.activeTxns = initTable[TxnId, Transaction]()
|
||||
result.committedTxns = @[]
|
||||
result.globalVersions = initTable[string, seq[VersionedRecord]]()
|
||||
result.txnTimeoutMs = txnTimeoutMs
|
||||
|
||||
proc allocTxnId(tm: TxnManager): TxnId =
|
||||
result = TxnId(tm.nextTxnId)
|
||||
@@ -157,6 +159,14 @@ proc write*(tm: TxnManager, txn: Transaction, key: string, value: seq[byte]): bo
|
||||
release(tm.lock)
|
||||
return false
|
||||
|
||||
# Timeout-based deadlock detection: abort stale transactions
|
||||
let now = getMonoTime().ticks()
|
||||
for otherId, otherTxn in tm.activeTxns:
|
||||
if otherId != txn.id and otherTxn.state == tsActive:
|
||||
if now - otherTxn.startTime > tm.txnTimeoutMs * 1_000_000:
|
||||
otherTxn.state = tsAborted
|
||||
tm.activeTxns.del(otherId)
|
||||
|
||||
# Check for write-write conflict
|
||||
if key notin txn.writeSet:
|
||||
if key in tm.globalVersions:
|
||||
|
||||
Reference in New Issue
Block a user