浏览代码

lib/db: Don't whack blocks when putting truncated file (#6434)

As of the latest database checker we are again putting files without
blocks. I'm not 100% convinced that's a great idea, but we also do it
for ignored files apparently so it looks like we probably should support
it. This adds an escape hatch that must be manually enabled...
Jakob Borg 5 年之前
父节点
当前提交
c4abe6f815
共有 4 个文件被更改,包括 25 次插入15 次删除
  1. 11 7
      lib/db/db_test.go
  2. 4 4
      lib/db/lowlevel.go
  3. 1 1
      lib/db/schemaupdater.go
  4. 9 3
      lib/db/transactions.go

+ 11 - 7
lib/db/db_test.go

@@ -261,11 +261,11 @@ func TestRepairSequence(t *testing.T) {
 	short := protocol.LocalDeviceID.Short()
 
 	files := []protocol.FileInfo{
-		{Name: "fine"},
-		{Name: "duplicate"},
-		{Name: "missing"},
-		{Name: "overwriting"},
-		{Name: "inconsistent"},
+		{Name: "fine", Blocks: genBlocks(1)},
+		{Name: "duplicate", Blocks: genBlocks(2)},
+		{Name: "missing", Blocks: genBlocks(3)},
+		{Name: "overwriting", Blocks: genBlocks(4)},
+		{Name: "inconsistent", Blocks: genBlocks(5)},
 	}
 	for i, f := range files {
 		files[i].Version = f.Version.Update(short)
@@ -282,7 +282,7 @@ func TestRepairSequence(t *testing.T) {
 		if err != nil {
 			t.Fatal(err)
 		}
-		if err := trans.putFile(dk, f); err != nil {
+		if err := trans.putFile(dk, f, false); err != nil {
 			t.Fatal(err)
 		}
 		sk, err := trans.keyer.GenerateSequenceKey(nil, folder, seq)
@@ -399,16 +399,20 @@ func TestRepairSequence(t *testing.T) {
 	}
 	defer it.Release()
 	for it.Next() {
-		fi, ok, err := ro.getFileTrunc(it.Value(), true)
+		intf, ok, err := ro.getFileTrunc(it.Value(), false)
 		if err != nil {
 			t.Fatal(err)
 		}
+		fi := intf.(protocol.FileInfo)
 		seq := ro.keyer.SequenceFromSequenceKey(it.Key())
 		if !ok {
 			t.Errorf("Sequence entry %v points at nothing", seq)
 		} else if fi.SequenceNo() != seq {
 			t.Errorf("Inconsistent sequence entry for %v: %v != %v", fi.FileName(), fi.SequenceNo(), seq)
 		}
+		if len(fi.Blocks) == 0 {
+			t.Error("Missing blocks in", fi.FileName())
+		}
 	}
 	if err := it.Error(); err != nil {
 		t.Fatal(err)

+ 4 - 4
lib/db/lowlevel.go

@@ -114,7 +114,7 @@ func (db *Lowlevel) updateRemoteFiles(folder, device []byte, fs []protocol.FileI
 		meta.addFile(devID, f)
 
 		l.Debugf("insert; folder=%q device=%v %v", folder, devID, f)
-		if err := t.putFile(dk, f); err != nil {
+		if err := t.putFile(dk, f, false); err != nil {
 			return err
 		}
 
@@ -201,7 +201,7 @@ func (db *Lowlevel) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
 		meta.addFile(protocol.LocalDeviceID, f)
 
 		l.Debugf("insert (local); folder=%q %v", folder, f)
-		if err := t.putFile(dk, f); err != nil {
+		if err := t.putFile(dk, f, false); err != nil {
 			return err
 		}
 
@@ -643,7 +643,7 @@ func (db *Lowlevel) getMetaAndCheck(folder string) *metadataTracker {
 		var fixed int
 		fixed, err = db.repairSequenceGCLocked(folder, meta)
 		if fixed != 0 {
-			l.Infoln("Repaired %v sequence entries in database", fixed)
+			l.Infof("Repaired %d sequence entries in database", fixed)
 		}
 	}
 
@@ -790,7 +790,7 @@ func (db *Lowlevel) repairSequenceGCLocked(folderStr string, meta *metadataTrack
 			if err := t.Put(sk, it.Key()); err != nil {
 				return 0, err
 			}
-			if err := t.putFile(it.Key(), fi.copyToFileInfo()); err != nil {
+			if err := t.putFile(it.Key(), fi.copyToFileInfo(), true); err != nil {
 				return 0, err
 			}
 		}

+ 1 - 1
lib/db/schemaupdater.go

@@ -465,7 +465,7 @@ func (db *schemaUpdater) updateSchemato9(prev int) error {
 		if fi.Blocks == nil {
 			continue
 		}
-		if err := t.putFile(it.Key(), fi); err != nil {
+		if err := t.putFile(it.Key(), fi, false); err != nil {
 			return err
 		}
 		if err := t.Checkpoint(); err != nil {

+ 9 - 3
lib/db/transactions.go

@@ -432,13 +432,19 @@ func (t readWriteTransaction) close() {
 	t.WriteTransaction.Release()
 }
 
-func (t readWriteTransaction) putFile(fkey []byte, fi protocol.FileInfo) error {
+// putFile stores a file in the database, taking care of indirected fields.
+// Set the truncated flag when putting a file that deliberatly can have an
+// empty block list but a non-empty block list hash. This should normally be
+// false.
+func (t readWriteTransaction) putFile(fkey []byte, fi protocol.FileInfo, truncated bool) error {
 	var bkey []byte
 
-	// Always set the blocks hash when there are blocks.
+	// Always set the blocks hash when there are blocks. Leave the blocks
+	// hash alone when there are no blocks and we might be putting a
+	// "truncated" FileInfo (no blocks, but the hash reference is live).
 	if len(fi.Blocks) > 0 {
 		fi.BlocksHash = protocol.BlocksHash(fi.Blocks)
-	} else {
+	} else if !truncated {
 		fi.BlocksHash = nil
 	}