Reuse temporary files (fixes #4)

This commit is contained in:
Audrius Butkevicius
2014-10-03 23:15:54 +01:00
parent 41b8dd2863
commit 69e385e4cd
6 changed files with 87 additions and 23 deletions

View File

@@ -412,12 +412,62 @@ func (p *Puller) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocksSt
tempName := filepath.Join(p.dir, defTempNamer.TempName(file.Name))
realName := filepath.Join(p.dir, file.Name)
var reuse bool
// Check for an old temporary file which might have some blocks we could
// reuse.
tempBlocks, err := scanner.HashFile(tempName, protocol.BlockSize)
if err == nil {
// Check for any reusable blocks in the temp file
tempCopyBlocks, _ := scanner.BlockDiff(tempBlocks, file.Blocks)
// block.String() returns a string unique to the block
existingBlocks := make(map[string]bool, len(tempCopyBlocks))
for _, block := range tempCopyBlocks {
existingBlocks[block.String()] = true
}
// Since the blocks are already there, we don't need to copy them
// nor we need to pull them, hence discard blocks which are already
// there, if they are exactly the same...
var newCopyBlocks []protocol.BlockInfo
for _, block := range copyBlocks {
_, ok := existingBlocks[block.String()]
if !ok {
newCopyBlocks = append(newCopyBlocks, block)
}
}
var newPullBlocks []protocol.BlockInfo
for _, block := range pullBlocks {
_, ok := existingBlocks[block.String()]
if !ok {
newPullBlocks = append(newPullBlocks, block)
}
}
// If any blocks could be reused, let the sharedpullerstate know
// which flags it is expected to set on the file.
// Also update the list of work for the routines.
if len(copyBlocks) != len(newCopyBlocks) || len(pullBlocks) != len(newPullBlocks) {
reuse = true
copyBlocks = newCopyBlocks
pullBlocks = newPullBlocks
} else {
// Otherwise, discard the file ourselves in order for the
// sharedpuller not to panic when it fails to exlusively create a
// file which already exists
os.Remove(tempName)
}
}
s := sharedPullerState{
file: file,
folder: p.folder,
tempName: tempName,
realName: realName,
pullNeeded: len(pullBlocks),
reuse: reuse,
}
if len(copyBlocks) > 0 {
s.copyNeeded = 1
@@ -628,12 +678,14 @@ func (p *Puller) finisherRoutine(in <-chan *sharedPullerState) {
// clean deletes orphaned temporary files
func (p *Puller) clean() {
keep := time.Duration(p.model.cfg.Options.KeepTemporariesH) * time.Hour
now := time.Now()
filepath.Walk(p.dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.Mode().IsRegular() && defTempNamer.IsTemporary(path) {
if info.Mode().IsRegular() && defTempNamer.IsTemporary(path) && info.ModTime().Add(keep).Before(now) {
os.Remove(path)
}