|
@@ -412,12 +412,62 @@ func (p *Puller) handleFile(file protocol.FileInfo, copyChan chan<- copyBlocksSt
|
|
|
tempName := filepath.Join(p.dir, defTempNamer.TempName(file.Name))
|
|
tempName := filepath.Join(p.dir, defTempNamer.TempName(file.Name))
|
|
|
realName := filepath.Join(p.dir, 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{
|
|
s := sharedPullerState{
|
|
|
file: file,
|
|
file: file,
|
|
|
folder: p.folder,
|
|
folder: p.folder,
|
|
|
tempName: tempName,
|
|
tempName: tempName,
|
|
|
realName: realName,
|
|
realName: realName,
|
|
|
pullNeeded: len(pullBlocks),
|
|
pullNeeded: len(pullBlocks),
|
|
|
|
|
+ reuse: reuse,
|
|
|
}
|
|
}
|
|
|
if len(copyBlocks) > 0 {
|
|
if len(copyBlocks) > 0 {
|
|
|
s.copyNeeded = 1
|
|
s.copyNeeded = 1
|
|
@@ -628,12 +678,14 @@ func (p *Puller) finisherRoutine(in <-chan *sharedPullerState) {
|
|
|
|
|
|
|
|
// clean deletes orphaned temporary files
|
|
// clean deletes orphaned temporary files
|
|
|
func (p *Puller) clean() {
|
|
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 {
|
|
filepath.Walk(p.dir, func(path string, info os.FileInfo, err error) error {
|
|
|
if err != nil {
|
|
if err != nil {
|
|
|
return err
|
|
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)
|
|
os.Remove(path)
|
|
|
}
|
|
}
|
|
|
|
|
|