Vector distance functions (cosine, euclidean, dot, manhattan) returned float64 but accumulated sums in float32, causing precision loss in SQL results (e.g. sqrt(2) truncated to float32). Use float64 accumulators and casts throughout. docs(bugs): mark BUG-023 and BUG-024 as fixed The code already cleans up pendingAcks and passes oldAssignments from rebalance to migrateData; update BUGS.md to match the implementation.
12 KiB
Bug Report — BaraDB Codebase Audit
Generated: 2026-05-21 Total: 55 bugs (7 critical, 21 high, 21 medium, 6 low) Fixed: 55/55 | Remaining: 0/55
Critical — 7/7 fixed
BUG-001 ✅ readIdent infinite loop on multi-byte UTF-8
File: src/barabadb/query/lexer.nim:523-538 — FIXED: Added discard l.advanceRune() to advance l.pos in the loop.
BUG-002 ✅ Parser.peek returns uninitialized Token at EOF
File: src/barabadb/query/parser.nim:15-18 — FIXED: Added missing return keyword.
BUG-003 ✅ flushUnsafe writes WAL without walLock
File: src/barabadb/storage/lsm.nim:808-810 — FIXED: Wrapped WAL writes in acquire(db.walLock) / release(db.walLock).
BUG-004 ✅ checkpoint calls flushUnsafe with no lock
File: src/barabadb/storage/lsm.nim:832-836 — FIXED: Entire checkpoint now runs under lock; WAL rotate uses walLock.
BUG-005 ✅ Compaction deletes source SSTables without verifying output
File: src/barabadb/storage/compaction.nim:124-128 — FIXED: Added verifySSTable check before deleting sources.
BUG-006 ✅ healthCheck leaks lock on exception
File: src/barabadb/core/replication.nim:227-248 — FIXED: Snapshot replicas under lock, release, then do network I/O.
BUG-007 ✅ hmacSha256 truncates keys > 64 bytes to hex string
File: src/barabadb/protocol/auth.nim:73-79 — FIXED: Changed k = $hash to k = cast[string](hash) for raw bytes.
High — 21/21 fixed
BUG-008 ✅ loadExistingDatabases / ensureDefaultDatabase without lock
File: src/barabadb/core/registry.nim:55-70, 78-90 — FIXED: Added lock around reg.databases modifications.
BUG-009 ✅ compactVersions modifies shared state without lock
File: src/barabadb/core/mvcc.nim:329-354 — FIXED: Made private (removed *), only called from commit which holds lock.
BUG-010 ✅ Deadlock detector edges never cleaned up
File: src/barabadb/core/mvcc.nim:191-199 — FIXED: Added removeWait before returning on conflict. Also fixed in delete.
BUG-011 ✅ close leaks WAL/SSTable on exception
File: src/barabadb/storage/lsm.nim:842-851 — FIXED: Wrapped in try/finally to guarantee cleanup.
BUG-012 ✅ B-Tree remove does not rebalance
File: src/barabadb/storage/btree.nim — FIXED: Implemented full B-tree delete rebalancing: borrowFromLeft/borrowFromRight (borrow key + child from sibling, update parent separator), mergeWithLeft/mergeWithRight (merge with sibling by pulling down parent separator), rebalanceAfterDelete (orchestrates borrow-or-merge, recursive parent rebalancing, root shrinking).
BUG-013 ✅ Compaction except: discard swallows all exceptions
File: src/barabadb/storage/compaction.nim:76-84 — FIXED: Catches CatchableError, logs, and aborts compaction without deleting sources.
BUG-014 ✅ headerSize = 36 should be 40 — wrong CRC range
File: src/barabadb/storage/lsm.nim:212,293,334 — FIXED: Changed all three occurrences from 36 to 40.
BUG-015 ✅ ** power operator tokenized but never parsed
File: src/barabadb/query/parser.nim:270-282 — FIXED: Added parsePower function (right-associative) between parsePostfix and parseMulDiv.
BUG-016 ✅ NOT a = b wrong precedence
File: src/barabadb/query/parser.nim:297-345 — FIXED: Moved NOT wrap to AFTER the comparison while loop.
BUG-017 ✅ COUNT(DISTINCT col) DISTINCT flag lost
File: src/barabadb/query/parser.nim:141-164 — FIXED: Added funcDistinct field to nkFuncCall node in AST, set in parser.
BUG-018 ✅ Expression UDFs always return null
File: src/barabadb/query/udf.nim:73-80 — FIXED: Raises descriptive error directing to use query evaluator.
BUG-019 ✅ substr crashes on out-of-bounds index
File: src/barabadb/query/udf.nim:176-188 — FIXED: Added bounds check, returns empty string for out-of-bounds.
BUG-020 ✅ Raft accepts stale term vote/append replies
File: src/barabadb/core/raft.nim:352-391 — FIXED: Added if reply.term < node.currentTerm: return in both handlers.
BUG-021 ✅ Raft becomeFollower on term >= currentTerm
File: src/barabadb/core/raft.nim:269-271 — FIXED: Changed >= to >; leaderId assignment still happens unconditionally.
BUG-022 ✅ shipToReplica socket leak
File: src/barabadb/core/replication.nim:94-113 — FIXED: Used defer: sock.close().
BUG-023 ✅ pendingAcks never cleaned up in sync/semi-sync
File: src/barabadb/core/replication.nim:131-199 — FIXED: writeLsn now removes acked replica IDs from pendingAcks and deletes the LSN entry once fully acked; ackLsn also cleans up on replica acknowledgement.
BUG-024 ✅ rebalance loses old assignments
File: src/barabadb/core/sharding.nim:221-241 — FIXED: rebalance returns the old shard assignments; callers (addNode/removeNode) pass them to migrateData for correct data migration.
BUG-025 ✅ deserializeValue missing bounds checks
File: src/barabadb/protocol/wire.nim:216-227 — FIXED: Added bounds checks for fkBool, fkInt8, fkInt16.
BUG-026 ✅ verifyToken parseInt throws on malformed claims
File: src/barabadb/protocol/auth.nim:175-177 — FIXED: Wrapped in try/except ValueError.
BUG-027 ✅ 2PC leaves participants prepared on network failure
File: src/barabadb/core/disttxn.nim:150-200 — FIXED: Added rollbackPending/commitPending flags and recovery warnings.
BUG-028 ✅ JWT DB switch never decrements old connection count
File: src/barabadb/core/server.nim:504-520 — FIXED: Decrement old DB count before incrementing new one.
Medium — 21/21 fixed
BUG-029 ✅ loadConfigFromJson silently swallows errors
File: src/barabadb/core/config.nim:121-124 — FIXED: Logs warnings instead of discard.
BUG-030 ✅ Default JWT secret hardcoded in binary
File: src/barabadb/core/config.nim:182-185 — FIXED: Returns empty string; callers must handle missing secret.
BUG-031 ✅ dropDatabase closes LSMTree before removing from registry
File: src/barabadb/core/registry.nim:133-161 — FIXED: Delete from registry first, then close/cleanup outside lock.
BUG-032 ✅ MERGE missing DELETE / DO NOTHING
File: src/barabadb/query/parser.nim:902-958 — FIXED: Added tkDo/tkNothing tokens, mergeMatchedDelete/mergeNotMatchedNothing/mergeMatchedCondition AST fields, and loop-based parser for multiple WHEN branches.
BUG-033 ✅ inferExpr miscategorizes binary operators as unary
File: src/barabadb/query/ir.nim:291-301 — FIXED: Removed binary operators from unary case, added irNeg handling.
BUG-034 ✅ codegenExpr is no-op for most expression types
File: src/barabadb/query/codegen.nim:50-67 — FIXED: Literal/field/aggregate now return proper storage ops; unary/binary propagate children.
BUG-035 ✅ readEntries leaks FileStream on early return
File: src/barabadb/storage/wal.nim:211-213 — FIXED: Wrapped in try/finally with s.close().
BUG-036 ✅ mmap reads allow negative offset
File: src/barabadb/storage/mmap.nim:83+ — FIXED: Added offset < 0 checks to all read functions.
BUG-037 ✅ Raft log index conflates entry index with array position
File: src/barabadb/core/raft.nim:287-290 — FIXED: Added findLogEntryByIndex helper that searches by logical index instead of assuming index - 1 == array_position.
BUG-038 ✅ becomeFollower doesn't clear nextIndex/matchIndex
File: src/barabadb/core/raft.nim:209-214 — FIXED: Added clear() for both tables.
BUG-039 ✅ Gossip assigns wrong port to new nodes
File: src/barabadb/core/gossip.nim:295-302 — FIXED: Extracts port from senderAddr ("host:port") instead of using local gp.gossipPort.
BUG-040 ✅ getShardRange overlapping range boundaries
File: src/barabadb/core/sharding.nim:70-74 — FIXED: Exclusive upper bound for non-last shards.
BUG-041 ✅ getShardHash divides by zero
File: src/barabadb/core/sharding.nim:66-68 — FIXED: Returns -1 if shards.len == 0.
BUG-042 ✅ connectWithTimeout missing SO_ERROR check
File: src/barabadb/core/replication.nim:80-92 — FIXED: Added getsockopt(SO_ERROR) verification.
BUG-043 ✅ Dead code: duplicate ON UPDATE in ON DELETE
File: src/barabadb/query/parser.nim:1081-1087 — FIXED: Removed duplicate branches.
BUG-044 ✅ LIMIT cost ignores offset
File: src/barabadb/query/codegen.nim:242-246 — FIXED: Cost now factors in offset + limit — high offset no longer treated as cheap.
BUG-045 ✅ contains UDF cross-type mismatch
File: src/barabadb/query/udf.nim:212-234 — FIXED: Added cross-type numeric comparison (int64/int32/float64).
BUG-046 ✅ MmapFile.close() potential infinite recursion
File: src/barabadb/storage/mmap.nim:133-137 — FIXED: Qualified close as posix.close.
BUG-047 ✅ sendDistTxnRpc socket leak
File: src/barabadb/core/disttxn.nim:93-109 — FIXED: Used defer: sock.close().
BUG-048 ✅ Saga compensation skips on failure
File: src/barabadb/core/disttxn.nim:282-293 — FIXED: Wrapped each compensate() in try/except, logs and continues.
BUG-049 ✅ SCRAM reveals user existence
File: src/barabadb/protocol/auth.nim:207-208 — FIXED: Changed error message from "Unknown user: X" to "Authentication failed".
BUG-050 ✅ isVisible doesn't check committedTxnsSet for deleter
File: src/barabadb/core/mvcc.nim:129-141 — FIXED: Added committedTxnsSet check before unconditionally hiding record.
Low — 6/6 fixed
BUG-051 ✅ recvExactWithTimeout abandoned future on timeout
File: src/barabadb/core/server.nim:313-320 — FIXED: Explicit return "" with comment explaining cleanup.
BUG-052 ✅ readNumber produces invalid float for trailing dot
File: src/barabadb/query/lexer.nim:508-521 — FIXED: Appends "0" for trailing dot (123. → 123.0).
BUG-053 ✅ substr(s, start) returns rest-of-string
File: src/barabadb/query/udf.nim:187 — FIXED: Now returns single character s[start] for 2-arg form.
BUG-054 ✅ readUint32 → int truncation on 32-bit
File: src/barabadb/protocol/wire.nim:136,147 — FIXED: Store raw uint32 before cast, check for negative result after cast.
BUG-055 ✅ PageCache put resets lastAccess to 0
File: src/barabadb/storage/compaction.nim:196-213 — FIXED: Removed unused lastAccess field entirely; LRU uses accessOrder seq.
Summary
| Status | Count |
|---|---|
| Fixed | 55 |
| Remaining | 0 |
All identified bugs have been resolved.