diff --git a/db.go b/db.go index ab3d591..94f3b2b 100644 --- a/db.go +++ b/db.go @@ -930,20 +930,26 @@ func (db *DB) initDatabaseFile() error { // Build per-page checksum map for existing pages. The database could be // short compared to the page count in the header so just checksum what we // can. The database may recover in applyLTX() so we'll do validation then. - buf := make([]byte, db.pageSize) db.chksums.pages = make([]ltx.Checksum, db.PageN()) db.chksums.blocks = make([]ltx.Checksum, pageChksumBlock(db.PageN())) - for pgno := uint32(1); pgno <= db.PageN(); pgno++ { - offset := int64(pgno-1) * int64(db.pageSize) - if _, err := internal.ReadFullAt(f, buf, offset); err == io.EOF || err == io.ErrUnexpectedEOF { - log.Printf("database checksum ending early at page %d of %d ", pgno-1, db.PageN()) - break - } else if err != nil { - return fmt.Errorf("read database page %d: %w", pgno, err) - } - chksum := ltx.ChecksumPage(pgno, buf) - db.setDatabasePageChecksum(pgno, chksum) + lastGoodPage, err := ltx.ChecksumPages(db.DatabasePath(), db.pageSize, db.PageN(), 0, db.chksums.pages) + + // lastGoodPage tells us how far we got before the first error. Most likely + // is that we got an EOF because the db was short, in which case no + // subsequent checksums would have been written. To be cautious though, + // zero out any checksums after the last good page. + clear(db.chksums.pages[lastGoodPage:]) + + // Always overwrite the lock page as a zero checksum. + if lockPage := ltx.LockPgno(db.pageSize); len(db.chksums.pages) >= int(lockPage) { + db.chksums.pages[lockPage-1] = 0 + } + + if err == io.EOF || err == io.ErrUnexpectedEOF { + log.Printf("database checksum ending early at page %d of %d ", lastGoodPage, db.PageN()) + } else if err != nil { + return fmt.Errorf("read database page %d: %w", lastGoodPage+1, err) } return nil diff --git a/go.mod b/go.mod index a4b57c9..0274794 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.16-0.20220918133448-90900be5db1a github.com/prometheus/client_golang v1.13.0 github.com/superfly/litefs-go v0.0.0-20230227231337-34ea5dcf1e0b - github.com/superfly/ltx v0.3.13 + github.com/superfly/ltx v0.3.14-0.20250108183450-67dadffee317 golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc golang.org/x/net v0.17.0 golang.org/x/sync v0.4.0 diff --git a/go.sum b/go.sum index fc4aa9b..214139d 100644 --- a/go.sum +++ b/go.sum @@ -310,6 +310,8 @@ github.com/superfly/litefs-go v0.0.0-20230227231337-34ea5dcf1e0b h1:+WuhtZFB8fNd github.com/superfly/litefs-go v0.0.0-20230227231337-34ea5dcf1e0b/go.mod h1:h+GUx1V2s0C5nY73ZN82760eWEJrpMaiDweF31VmJKk= github.com/superfly/ltx v0.3.13 h1:IbuocKJ6sY2jYvZbpUGMYmTkvaLSGUderEZwmaIUmJ0= github.com/superfly/ltx v0.3.13/go.mod h1:ly+Dq7UVacQVEI5/b0r6j+PSNy9ibwx1yikcWAaSkhE= +github.com/superfly/ltx v0.3.14-0.20250108183450-67dadffee317 h1:GtLIOUO6vJRSUCntnhgTRRqL+F8+MH9ZAjEh53sfvos= +github.com/superfly/ltx v0.3.14-0.20250108183450-67dadffee317/go.mod h1:ly+Dq7UVacQVEI5/b0r6j+PSNy9ibwx1yikcWAaSkhE= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ= github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=