From 1c42eff7ef3ccaf3d008fa5360903c3cd87769f4 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Fri, 12 Jun 2026 23:06:19 +0300 Subject: [PATCH] fix(vector): use float64 accumulators for distance functions 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. --- BUGS.md | 8 +++---- src/barabadb/vector/engine.nim | 42 +++++++++++++++++----------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/BUGS.md b/BUGS.md index 2e86f93..9dfd5eb 100644 --- a/BUGS.md +++ b/BUGS.md @@ -78,11 +78,11 @@ Total: 55 bugs (7 critical, 21 high, 21 medium, 6 low) ### ~~BUG-022~~ :white_check_mark: `shipToReplica` socket leak **File:** `src/barabadb/core/replication.nim:94-113` — **FIXED:** Used `defer: sock.close()`. -### BUG-023 :x: `pendingAcks` never cleaned up in sync/semi-sync -**File:** `src/barabadb/core/replication.nim:131-164` — **NOT FIXED:** Requires restructuring sync replication ack flow. +### ~~BUG-023~~ :white_check_mark: `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 :x: `rebalance` loses old assignments -**File:** `src/barabadb/core/sharding.nim:208-211` — **NOT FIXED:** Requires passing old assignments to `migrateData`. +### ~~BUG-024~~ :white_check_mark: `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~~ :white_check_mark: `deserializeValue` missing bounds checks **File:** `src/barabadb/protocol/wire.nim:216-227` — **FIXED:** Added bounds checks for `fkBool`, `fkInt8`, `fkInt16`. diff --git a/src/barabadb/vector/engine.nim b/src/barabadb/vector/engine.nim index 244ad78..2df556a 100644 --- a/src/barabadb/vector/engine.nim +++ b/src/barabadb/vector/engine.nim @@ -53,61 +53,61 @@ type NodeDist* = tuple[dist: float64, id: uint64] proc cosineDistance*(a, b: Vector): float64 = - var dot, normA, normB: float32 + var dot, normA, normB: float64 let len = min(a.len, b.len) var i = 0 while i + 3 < len: - dot += a[i]*b[i] + a[i+1]*b[i+1] + a[i+2]*b[i+2] + a[i+3]*b[i+3] - normA += a[i]*a[i] + a[i+1]*a[i+1] + a[i+2]*a[i+2] + a[i+3]*a[i+3] - normB += b[i]*b[i] + b[i+1]*b[i+1] + b[i+2]*b[i+2] + b[i+3]*b[i+3] + dot += float64(a[i])*float64(b[i]) + float64(a[i+1])*float64(b[i+1]) + float64(a[i+2])*float64(b[i+2]) + float64(a[i+3])*float64(b[i+3]) + normA += float64(a[i])*float64(a[i]) + float64(a[i+1])*float64(a[i+1]) + float64(a[i+2])*float64(a[i+2]) + float64(a[i+3])*float64(a[i+3]) + normB += float64(b[i])*float64(b[i]) + float64(b[i+1])*float64(b[i+1]) + float64(b[i+2])*float64(b[i+2]) + float64(b[i+3])*float64(b[i+3]) i += 4 while i < len: - dot += a[i] * b[i] - normA += a[i] * a[i] - normB += b[i] * b[i] + dot += float64(a[i]) * float64(b[i]) + normA += float64(a[i]) * float64(a[i]) + normB += float64(b[i]) * float64(b[i]) inc i let denom = sqrt(normA) * sqrt(normB) if denom == 0: return 1.0 - return 1.0 - float64(dot) / float64(denom) + return 1.0 - dot / denom proc euclideanDistance*(a, b: Vector): float64 = - var sum: float32 + var sum: float64 let len = min(a.len, b.len) var i = 0 while i + 3 < len: - let d0 = a[i] - b[i] - let d1 = a[i+1] - b[i+1] - let d2 = a[i+2] - b[i+2] - let d3 = a[i+3] - b[i+3] + let d0 = float64(a[i]) - float64(b[i]) + let d1 = float64(a[i+1]) - float64(b[i+1]) + let d2 = float64(a[i+2]) - float64(b[i+2]) + let d3 = float64(a[i+3]) - float64(b[i+3]) sum += d0*d0 + d1*d1 + d2*d2 + d3*d3 i += 4 while i < len: - let d = a[i] - b[i] + let d = float64(a[i]) - float64(b[i]) sum += d * d inc i return sqrt(sum) proc dotProduct*(a, b: Vector): float64 = - var sum: float32 + var sum: float64 let len = min(a.len, b.len) var i = 0 while i + 3 < len: - sum += a[i]*b[i] + a[i+1]*b[i+1] + a[i+2]*b[i+2] + a[i+3]*b[i+3] + sum += float64(a[i])*float64(b[i]) + float64(a[i+1])*float64(b[i+1]) + float64(a[i+2])*float64(b[i+2]) + float64(a[i+3])*float64(b[i+3]) i += 4 while i < len: - sum += a[i] * b[i] + sum += float64(a[i]) * float64(b[i]) inc i - return -float64(sum) # negative because we want to minimize + return -sum # negative because we want to minimize proc manhattanDistance*(a, b: Vector): float64 = - var sum: float32 + var sum: float64 let len = min(a.len, b.len) var i = 0 while i + 3 < len: - sum += abs(a[i]-b[i]) + abs(a[i+1]-b[i+1]) + abs(a[i+2]-b[i+2]) + abs(a[i+3]-b[i+3]) + sum += abs(float64(a[i])-float64(b[i])) + abs(float64(a[i+1])-float64(b[i+1])) + abs(float64(a[i+2])-float64(b[i+2])) + abs(float64(a[i+3])-float64(b[i+3])) i += 4 while i < len: - sum += abs(a[i] - b[i]) + sum += abs(float64(a[i]) - float64(b[i])) inc i return sum