_ = i
//fmt.Printf("%v %#v %v\n", i, f, p)
cmpl := me.t.getCompletion(p)
+ if cmpl.Err != nil {
+ err = fmt.Errorf("error getting completion for piece %d: %w", p, cmpl.Err)
+ return
+ }
if !cmpl.Ok || !cmpl.Complete {
continue nextFile
}
return
}
+// Rename from if exists, and if so, to must not exist.
+func (me *filePieceImpl) exclRenameIfExists(from, to string) (err error) {
+ _, err = os.Stat(from)
+ if errors.Is(err, fs.ErrNotExist) {
+ return nil
+ }
+ // We don't want anyone reading or writing to this until the rename completes.
+ f, err := os.OpenFile(to, os.O_CREATE|os.O_EXCL, 0)
+ if err != nil {
+ return fmt.Errorf("error creating destination file: %w", err)
+ }
+ f.Close()
+ return os.Rename(from, to)
+}
+
func (me *filePieceImpl) onFileNotComplete(f file) (err error) {
if me.partFiles() {
- err = os.Rename(f.safeOsPath, f.partFilePath())
- // If we get ENOENT, the file may already be in the final location.
- if err != nil && !errors.Is(err, fs.ErrNotExist) {
- err = fmt.Errorf("renaming incomplete file: %w", err)
+ err = me.exclRenameIfExists(f.safeOsPath, f.partFilePath())
+ if err != nil {
+ err = fmt.Errorf("restoring part file: %w", err)
return
}
}
if fst.fts.partFiles() {
f, err = os.Open(file.partFilePath())
}
- if errors.Is(err, fs.ErrNotExist) {
+ if err == nil && f == nil || errors.Is(err, fs.ErrNotExist) {
f, err = os.Open(file.safeOsPath)
}
if errors.Is(err, fs.ErrNotExist) {
b, ci, test_storage.DefaultPieceSize, test_storage.DefaultNumPieces, 0)
}
b.Run("File", func(b *testing.B) {
- ci := storage.NewFile(b.TempDir())
+ ci := storage.NewFileOpts(storage.NewFileClientOpts{
+ ClientBaseDir: b.TempDir(),
+ // TODO: Is the benchmark finding a bug?
+ //UsePartFiles: g.Some(false),
+ })
+ //ci := storage.NewFile(b.TempDir())
b.Cleanup(func() { ci.Close() })
bench(b, ci)
})
qt.Assert(b, qt.Equals(pi.Completion(), storage.Completion{Complete: true, Ok: true}))
n, err := pi.WriteTo(bytes.NewBuffer(readData[:0]))
b.StopTimer()
+ qt.Check(b, qt.Equals(n, int64(len(data))))
qt.Assert(b, qt.IsNil(err))
- qt.Assert(b, qt.Equals(n, int64(len(data))))
qt.Assert(b, qt.IsTrue(bytes.Equal(readData[:n], data)))
}
}
}
func (t *Torrent) getPieceRequestOrder() *request_strategy.PieceRequestOrder {
+ if t.storage == nil {
+ return nil
+ }
return t.cl.pieceRequestOrder[t.clientPieceRequestOrderKey()]
}
return
}
pro := t.getPieceRequestOrder()
- if pro != nil {
- for item := range pro.Iter() {
- t.slogger().Debug(
- "piece request order item", "infohash",
- item.Key.InfoHash, "piece",
- item.Key.Index, "state",
- item.State)
+ // This might require some optimization around Record to avoid performance issues when
+ // benchmarking.
+ if false {
+ if pro != nil {
+ for item := range pro.Iter() {
+ t.slogger().Debug("piece request order item",
+ "infohash", item.Key.InfoHash,
+ "piece", item.Key.Index,
+ "state", item.State)
+ }
}
}
}
t._completedPieces.Add(bitmap.BitIndex(i))
}
t.DownloadPieces(0, t.numPieces())
- for i := 0; i < b.N; i += 1 {
+ for b.Loop() {
t.updateAllPiecePriorities("")
}
}