Browse Source

Add shortcut for syncing identical files

Jakob Borg 11 years ago
parent
commit
61e3daaead
2 changed files with 34 additions and 4 deletions
  1. 11 4
      model/blockqueue.go
  2. 23 0
      model/puller.go

+ 11 - 4
model/blockqueue.go

@@ -16,6 +16,7 @@ type bqBlock struct {
 	file  scanner.File
 	block scanner.Block   // get this block from the network
 	copy  []scanner.Block // copy these blocks from the old version of the file
+	first bool
 	last  bool
 }
 
@@ -47,24 +48,30 @@ func (q *blockQueue) addBlock(a bqAdd) {
 			return
 		}
 	}
+
+	l := len(a.need)
+
 	if len(a.have) > 0 {
 		// First queue a copy operation
 		q.queued = append(q.queued, bqBlock{
-			file: a.file,
-			copy: a.have,
+			file:  a.file,
+			copy:  a.have,
+			first: true,
+			last:  l == 0,
 		})
 	}
+
 	// Queue the needed blocks individually
-	l := len(a.need)
 	for i, b := range a.need {
 		q.queued = append(q.queued, bqBlock{
 			file:  a.file,
 			block: b,
+			first: len(a.have) == 0 && i == 0,
 			last:  i == l-1,
 		})
 	}
 
-	if l == 0 {
+	if len(a.need)+len(a.have) == 0 {
 		// If we didn't have anything to fetch, queue an empty block with the "last" flag set to close the file.
 		q.queued = append(q.queued, bqBlock{
 			file: a.file,

+ 23 - 0
model/puller.go

@@ -373,6 +373,29 @@ func (p *puller) handleBlock(b bqBlock) bool {
 		return true
 	}
 
+	if len(b.copy) > 0 && len(b.copy) == len(b.file.Blocks) && b.last {
+		// We are supposed to copy the entire file, and then fetch nothing.
+		// We don't actually need to make the copy.
+		if debug {
+			l.Debugln("taking shortcut:", f)
+		}
+		fp := filepath.Join(p.repoCfg.Directory, f.Name)
+		t := time.Unix(f.Modified, 0)
+		err := os.Chtimes(fp, t, t)
+		if debug && err != nil {
+			l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
+		}
+		if !p.repoCfg.IgnorePerms && protocol.HasPermissionBits(f.Flags) {
+			err = os.Chmod(fp, os.FileMode(f.Flags&0777))
+			if debug && err != nil {
+				l.Debugf("pull: error: %q / %q: %v", p.repoCfg.ID, f.Name, err)
+			}
+		}
+
+		p.model.updateLocal(p.repoCfg.ID, f)
+		return true
+	}
+
 	of, ok := p.openFiles[f.Name]
 	of.done = b.last