diff --git a/hbrdd/dbf/dbf.go b/hbrdd/dbf/dbf.go index dc834d7..1034188 100644 --- a/hbrdd/dbf/dbf.go +++ b/hbrdd/dbf/dbf.go @@ -1115,6 +1115,30 @@ func (a *DBFArea) drainPendingIndexInserts() { } func (a *DBFArea) updateHeader() { + // Shared-mode max-merge. A pgserver-style multi-connection + // scenario has every peer call Close → updateHeader in arbitrary + // order. Each peer's `a.recCount` reflects its own view at the + // time of its last Append; if the file has grown since (because + // another peer's Append took the append-intent lock and bumped + // the disk header), naively writing a.recCount back would + // roll the on-disk count BACKWARDS — and subsequent peer SELECTs + // would iterate only as far as our stale count, missing rows + // that are demonstrably on disk. + // + // Re-read the disk header and pick the max. This is correct under + // the append-intent lock invariant (the bumped count is always + // monotonic) and cheap (one stat-sized read). Single-process / + // EXCLUSIVE mode still writes its local count unconditionally, + // since no peer can have bumped it. + if a.shared { + if _, err := a.dataFile.Seek(0, 0); err == nil { + if hdr, err := ReadHeader(a.dataFile); err == nil { + if hdr.RecCount > a.recCount { + a.recCount = hdr.RecCount + } + } + } + } a.header.RecCount = a.recCount a.header.UpdateDate()