Files
syncthing-arm/lib/scanner/blockqueue.go
T

124 lines
2.8 KiB
Go
Raw Normal View History

2014-11-16 21:13:20 +01:00
// Copyright (C) 2014 The Syncthing Authors.
2014-09-29 21:43:32 +02:00
//
2015-03-07 21:36:35 +01:00
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
2014-07-30 20:10:46 +02:00
package scanner
import (
"errors"
2014-07-30 20:10:46 +02:00
"os"
"path/filepath"
2015-09-22 19:38:46 +02:00
"github.com/syncthing/syncthing/lib/protocol"
2015-08-06 11:29:25 +02:00
"github.com/syncthing/syncthing/lib/sync"
2014-07-30 20:10:46 +02:00
)
2016-05-08 10:54:22 +00:00
// The parallel hasher reads FileInfo structures from the inbox, hashes the
2014-07-30 20:10:46 +02:00
// file to populate the Blocks element and sends it to the outbox. A number of
// workers are used in parallel. The outbox will become closed when the inbox
// is closed and all items handled.
2015-11-17 21:08:36 +01:00
func newParallelHasher(dir string, blockSize, workers int, outbox, inbox chan protocol.FileInfo, counter Counter, done, cancel chan struct{}) {
2015-04-22 23:54:31 +01:00
wg := sync.NewWaitGroup()
2014-07-30 20:10:46 +02:00
wg.Add(workers)
for i := 0; i < workers; i++ {
go func() {
2015-11-13 15:00:32 +01:00
hashFiles(dir, blockSize, outbox, inbox, counter, cancel)
2014-07-30 20:10:46 +02:00
wg.Done()
}()
}
go func() {
wg.Wait()
2015-08-26 23:49:06 +01:00
if done != nil {
close(done)
}
2014-07-30 20:10:46 +02:00
close(outbox)
}()
}
func HashFile(path string, blockSize int, counter Counter) ([]protocol.BlockInfo, error) {
2014-10-03 23:15:54 +01:00
fd, err := os.Open(path)
if err != nil {
l.Debugln("open:", err)
return nil, err
2014-10-03 23:15:54 +01:00
}
2015-08-26 23:49:06 +01:00
defer fd.Close()
2014-07-30 20:10:46 +02:00
// Get the size and modtime of the file before we start hashing it.
fi, err := fd.Stat()
if err != nil {
l.Debugln("stat before:", err)
return nil, err
}
size := fi.Size()
modTime := fi.ModTime()
// Hash the file. This may take a while for large files.
blocks, err := Blocks(fd, blockSize, size, counter)
if err != nil {
l.Debugln("blocks:", err)
return nil, err
}
// Recheck the size and modtime again. If they differ, the file changed
// while we were reading it and our hash results are invalid.
fi, err = fd.Stat()
if err != nil {
l.Debugln("stat after:", err)
return nil, err
}
if size != fi.Size() || !modTime.Equal(fi.ModTime()) {
return nil, errors.New("file changed during hashing")
2014-10-03 23:15:54 +01:00
}
2015-08-26 23:49:06 +01:00
return blocks, nil
2014-10-03 23:15:54 +01:00
}
2014-07-30 20:10:46 +02:00
2015-11-17 21:08:36 +01:00
func hashFiles(dir string, blockSize int, outbox, inbox chan protocol.FileInfo, counter Counter, cancel chan struct{}) {
2015-11-13 15:00:32 +01:00
for {
select {
case f, ok := <-inbox:
if !ok {
return
}
2014-07-30 20:10:46 +02:00
2015-11-13 15:00:32 +01:00
if f.IsDirectory() || f.IsDeleted() {
panic("Bug. Asked to hash a directory or a deleted file.")
}
2014-07-30 20:10:46 +02:00
blocks, err := HashFile(filepath.Join(dir, f.Name), blockSize, counter)
2015-11-13 15:00:32 +01:00
if err != nil {
l.Debugln("hash error:", f.Name, err)
continue
}
f.Blocks = blocks
// The size we saw when initially deciding to hash the file
// might not have been the size it actually had when we hashed
// it. Update the size from the block list.
f.Size = 0
for _, b := range blocks {
f.Size += int64(b.Size)
}
2015-11-13 15:00:32 +01:00
select {
case outbox <- f:
case <-cancel:
return
}
case <-cancel:
return
}
2014-07-30 20:10:46 +02:00
}
}