chore(db, model): simplify per hash DB lookup in copier (#10080)

This is a draft because I haven't adjusted all the tests yet, I'd like
to get feedback on the change overall first, before spending time on
that.

In my opinion the main win of this change is in it's lower complexity
resp. fewer moving parts. It should also be faster as it only does one
query instead of two, but I have no idea if that's practically
relevant.

This also mirrors the v1 DB, where a block map key had the name
appended. Not that this is an argument for the change, it was mostly
reassuring me that I might not be missing something key here
conceptually (I might still be of course, please tell me :) ).

And the change isn't mainly intrinsically motivated, instead it came
up while fixing a bug in the copier. And the nested nature of that code
makes the fix harder, and "un-nesting" it required me to understand
what's happening. This change fell out of that.
This commit is contained in:
Simon Frei
2025-05-01 13:44:25 -05:00
committed by GitHub
parent f183d1cbec
commit 6b94599467
8 changed files with 52 additions and 78 deletions
+25 -25
View File
@@ -1343,33 +1343,33 @@ func (f *sendReceiveFolder) copierRoutine(in <-chan copyBlocksState, pullChan ch
}
buf = protocol.BufferPool.Upgrade(buf, int(block.Size))
copied := false
blocks, _ := f.model.sdb.AllLocalBlocksWithHash(block.Hash)
innerBlocks:
for _, e := range blocks {
res, err := f.model.sdb.AllLocalFilesWithBlocksHashAnyFolder(e.BlocklistHash)
if err != nil {
continue
}
for folderID, files := range res {
ffs := folderFilesystems[folderID]
for _, fi := range files {
copied, err = f.copyBlock(fi.Name, e.Offset, dstFd, ffs, block, buf)
if err != nil {
state.fail(err)
break innerBlocks
}
if !copied {
continue
}
if fi.Name == state.file.Name {
state.copiedFromOrigin(block.Size)
} else {
state.copiedFromElsewhere(block.Size)
}
break innerBlocks
folders:
for folderID, ffs := range folderFilesystems {
for e, err := range itererr.Zip(f.model.sdb.AllLocalBlocksWithHash(folderID, block.Hash)) {
if err != nil {
// We just ignore this and continue pulling instead (though
// there's a good chance that will fail too, if the DB is
// unhealthy).
l.Debugf("Failed to get information from DB about block %v in copier (folderID %v, file %v): %v", block.Hash, f.folderID, state.file.Name)
break
}
copied, err = f.copyBlock(e.FileName, e.Offset, dstFd, ffs, block, buf)
if err != nil {
state.fail(err)
break folders
}
if !copied {
continue
}
if e.FileName == state.file.Name {
state.copiedFromOrigin(block.Size)
} else {
state.copiedFromElsewhere(block.Size)
}
break folders
}
}
+5 -4
View File
@@ -19,6 +19,7 @@ import (
"testing"
"time"
"github.com/syncthing/syncthing/internal/itererr"
"github.com/syncthing/syncthing/lib/build"
"github.com/syncthing/syncthing/lib/config"
"github.com/syncthing/syncthing/lib/events"
@@ -325,11 +326,11 @@ func TestCopierCleanup(t *testing.T) {
// Update index (removing old blocks)
f.updateLocalsFromScanning([]protocol.FileInfo{file})
if vals, err := m.sdb.AllLocalBlocksWithHash(blocks[0].Hash); err != nil || len(vals) > 0 {
if vals, err := itererr.Collect(m.sdb.AllLocalBlocksWithHash(f.ID, blocks[0].Hash)); err != nil || len(vals) > 0 {
t.Error("Unexpected block found")
}
if vals, err := m.sdb.AllLocalBlocksWithHash(blocks[1].Hash); err != nil || len(vals) == 0 {
if vals, err := itererr.Collect(m.sdb.AllLocalBlocksWithHash(f.ID, blocks[1].Hash)); err != nil || len(vals) == 0 {
t.Error("Expected block not found")
}
@@ -338,11 +339,11 @@ func TestCopierCleanup(t *testing.T) {
// Update index (removing old blocks)
f.updateLocalsFromScanning([]protocol.FileInfo{file})
if vals, err := m.sdb.AllLocalBlocksWithHash(blocks[0].Hash); err != nil || len(vals) == 0 {
if vals, err := itererr.Collect(m.sdb.AllLocalBlocksWithHash(f.ID, blocks[0].Hash)); err != nil || len(vals) == 0 {
t.Error("Unexpected block found")
}
if vals, err := m.sdb.AllLocalBlocksWithHash(blocks[1].Hash); err != nil || len(vals) > 0 {
if vals, err := itererr.Collect(m.sdb.AllLocalBlocksWithHash(f.ID, blocks[1].Hash)); err != nil || len(vals) > 0 {
t.Error("Expected block not found")
}
}