Make opening a torrent in storage an explicit method

This is storage types where opening can fail, like mmap
This commit is contained in:
Matt Joiner 2016-03-28 22:40:29 +11:00
parent 775cf53809
commit a5b54f21a1
8 changed files with 69 additions and 50 deletions

View File

@ -1949,9 +1949,9 @@ func (cl *Client) AddTorrentSpec(spec *TorrentSpec) (T Torrent, new bool, err er
if spec.ChunkSize != 0 {
t.chunkSize = pp.Integer(spec.ChunkSize)
}
t.storage = spec.Storage
if t.storage == nil {
t.storage = cl.defaultStorage
t.storageOpener = spec.Storage
if t.storageOpener == nil {
t.storageOpener = cl.defaultStorage
}
}
if spec.DisplayName != "" {

View File

@ -92,7 +92,7 @@ func TestTorrentInitialState(t *testing.T) {
return
}())
tor.chunkSize = 2
tor.storage = storage.NewFile(dir)
tor.storageOpener = storage.NewFile(dir)
// Needed to lock for asynchronous piece verification.
tor.cl = new(Client)
err := tor.setMetadata(&mi.Info.Info, mi.Info.Bytes)
@ -464,6 +464,14 @@ func TestMergingTrackersByAddingSpecs(t *testing.T) {
type badStorage struct{}
func (me badStorage) OpenTorrent(*metainfo.InfoEx) (storage.Torrent, error) {
return me, nil
}
func (me badStorage) Close() error {
return nil
}
func (me badStorage) Piece(p metainfo.Piece) storage.Piece {
return badStoragePiece{p}
}

View File

@ -2,6 +2,7 @@ package mmap_span
import (
"io"
"log"
"github.com/edsrzf/mmap-go"
)
@ -22,10 +23,14 @@ func (me *MMapSpan) Append(mmap mmap.MMap) {
me.span = append(me.span, segment{&mmap})
}
func (me MMapSpan) Close() {
func (me MMapSpan) Close() error {
for _, mMap := range me.span {
mMap.(segment).Unmap()
err := mMap.(segment).Unmap()
if err != nil {
log.Print(err)
}
}
return nil
}
func (me MMapSpan) Size() (ret int64) {

View File

@ -21,6 +21,14 @@ func NewFile(baseDir string) I {
}
}
func (me *fileStorage) OpenTorrent(info *metainfo.InfoEx) (Torrent, error) {
return fileTorrentStorage{me}, nil
}
type fileTorrentStorage struct {
*fileStorage
}
func (me *fileStorage) Piece(p metainfo.Piece) Piece {
_io := &fileStorageTorrent{
p.Info,
@ -34,6 +42,10 @@ func (me *fileStorage) Piece(p metainfo.Piece) Piece {
}
}
func (me *fileStorage) Close() error {
return nil
}
type fileStoragePiece struct {
*fileStorage
p metainfo.Piece

View File

@ -19,7 +19,7 @@ func TestShortFile(t *testing.T) {
td, err := ioutil.TempDir("", "")
require.NoError(t, err)
defer os.RemoveAll(td)
data := NewFile(td)
s := NewFile(td)
info := &metainfo.InfoEx{
Info: metainfo.Info{
Name: "a",
@ -27,12 +27,14 @@ func TestShortFile(t *testing.T) {
PieceLength: missinggo.MiB,
},
}
ts, err := s.OpenTorrent(info)
assert.NoError(t, err)
f, err := os.Create(filepath.Join(td, "a"))
err = f.Truncate(1)
f.Close()
var buf bytes.Buffer
p := info.Piece(0)
n, err := io.Copy(&buf, io.NewSectionReader(data.Piece(p), 0, p.Length()))
n, err := io.Copy(&buf, io.NewSectionReader(ts.Piece(p), 0, p.Length()))
assert.EqualValues(t, 1, n)
assert.Equal(t, io.ErrUnexpectedEOF, err)
}

View File

@ -6,11 +6,18 @@ import (
"github.com/anacrolix/torrent/metainfo"
)
// Represents data storage for a Torrent.
// Represents data storage for an unspecified torrent.
type I interface {
Piece(metainfo.Piece) Piece
OpenTorrent(info *metainfo.InfoEx) (Torrent, error)
}
// Data storage bound to a torrent.
type Torrent interface {
Piece(metainfo.Piece) Piece
Close() error
}
// Interacts with torrent piece data.
type Piece interface {
// Should return io.EOF only at end of torrent. Short reads due to missing
// data should return io.ErrUnexpectedEOF.
@ -23,20 +30,3 @@ type Piece interface {
// Returns true if the piece is complete.
GetIsComplete() bool
}
// type PieceStorage interface {
// ReadAt(metainfo.Piece, []byte, int64) (int, error)
// WriteAt(metainfo.Piece, []byte, int64) (int, error)
// MarkComplete(metainfo.Piece) error
// GetIsComplete(metainfo.Piece) bool
// }
// type wrappedPieceStorage struct {
// ps PieceStorage
// }
// func WrapPieceStorage(ps PieceStorage) I {
// return wrappedPieceStorage{ps}
// }
// func (me wrappedPieceStorage) Piece(metainfo.Piece)

View File

@ -14,9 +14,7 @@ import (
)
type mmapStorage struct {
baseDir string
spans map[metainfo.InfoHash]mmap_span.MMapSpan
completed map[metainfo.InfoHash]bool
baseDir string
}
func NewMMap(baseDir string) I {
@ -25,36 +23,35 @@ func NewMMap(baseDir string) I {
}
}
func (me *mmapStorage) lazySpan(info *metainfo.InfoEx) error {
if me.spans == nil {
me.spans = make(map[metainfo.InfoHash]mmap_span.MMapSpan)
}
if _, ok := me.spans[*info.Hash]; ok {
return nil
}
func (me *mmapStorage) OpenTorrent(info *metainfo.InfoEx) (t Torrent, err error) {
span, err := MMapTorrent(&info.Info, me.baseDir)
if err != nil {
return err
t = &mmapTorrentStorage{
span: span,
}
me.spans[*info.Hash] = span
return nil
return
}
func (me *mmapStorage) Piece(p metainfo.Piece) Piece {
err := me.lazySpan(p.Info)
if err != nil {
panic(err)
}
type mmapTorrentStorage struct {
span mmap_span.MMapSpan
completed map[metainfo.InfoHash]bool
}
func (me *mmapTorrentStorage) Piece(p metainfo.Piece) Piece {
return mmapStoragePiece{
storage: me,
p: p,
ReaderAt: io.NewSectionReader(me.spans[*p.Info.Hash], p.Offset(), p.Length()),
WriterAt: missinggo.NewSectionWriter(me.spans[*p.Info.Hash], p.Offset(), p.Length()),
ReaderAt: io.NewSectionReader(me.span, p.Offset(), p.Length()),
WriterAt: missinggo.NewSectionWriter(me.span, p.Offset(), p.Length()),
}
}
func (me *mmapTorrentStorage) Close() error {
me.span.Close()
return nil
}
type mmapStoragePiece struct {
storage *mmapStorage
storage *mmapTorrentStorage
p metainfo.Piece
io.ReaderAt
io.WriterAt

View File

@ -54,7 +54,8 @@ type torrent struct {
// get this from the info dict.
length int64
storage storage.I
storageOpener storage.I
storage storage.Torrent
// The info dict. Nil if we don't have it (yet).
Info *metainfo.InfoEx
@ -230,6 +231,10 @@ func (t *torrent) setMetadata(md *metainfo.Info, infoBytes []byte) (err error) {
Bytes: infoBytes,
Hash: &t.InfoHash,
}
t.storage, err = t.storageOpener.OpenTorrent(t.Info)
if err != nil {
return
}
t.length = 0
for _, f := range t.Info.UpvertedFiles() {
t.length += f.Length