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...
This commit is contained in:
Jakob Borg 2020-03-20 12:07:14 +01:00 committed by GitHub
parent 4c5e9cf921
commit c4abe6f815
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 25 additions and 15 deletions

View File

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

View File

@ -114,7 +114,7 @@ func (db *Lowlevel) updateRemoteFiles(folder, device []byte, fs []protocol.FileI
meta.addFile(devID, f) meta.addFile(devID, f)
l.Debugf("insert; folder=%q device=%v %v", folder, 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 return err
} }
@ -201,7 +201,7 @@ func (db *Lowlevel) updateLocalFiles(folder []byte, fs []protocol.FileInfo, meta
meta.addFile(protocol.LocalDeviceID, f) meta.addFile(protocol.LocalDeviceID, f)
l.Debugf("insert (local); folder=%q %v", folder, 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 return err
} }
@ -643,7 +643,7 @@ func (db *Lowlevel) getMetaAndCheck(folder string) *metadataTracker {
var fixed int var fixed int
fixed, err = db.repairSequenceGCLocked(folder, meta) fixed, err = db.repairSequenceGCLocked(folder, meta)
if fixed != 0 { 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 { if err := t.Put(sk, it.Key()); err != nil {
return 0, err 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 return 0, err
} }
} }

View File

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

View File

@ -432,13 +432,19 @@ func (t readWriteTransaction) close() {
t.WriteTransaction.Release() 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 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 { if len(fi.Blocks) > 0 {
fi.BlocksHash = protocol.BlocksHash(fi.Blocks) fi.BlocksHash = protocol.BlocksHash(fi.Blocks)
} else { } else if !truncated {
fi.BlocksHash = nil fi.BlocksHash = nil
} }