From: Matt Joiner Date: Mon, 28 Mar 2016 11:40:29 +0000 (+1100) Subject: Make opening a torrent in storage an explicit method X-Git-Tag: v1.0.0~813 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=a5b54f21a1a0a28c8fe596a3bc2c233c60b82597;p=btrtrc.git Make opening a torrent in storage an explicit method This is storage types where opening can fail, like mmap --- diff --git a/client.go b/client.go index 7f0d5484..d470ceac 100644 --- a/client.go +++ b/client.go @@ -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 != "" { diff --git a/client_test.go b/client_test.go index 6a33f3b8..faded767 100644 --- a/client_test.go +++ b/client_test.go @@ -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} } diff --git a/mmap_span/mmap_span.go b/mmap_span/mmap_span.go index 43e5458f..58d86732 100644 --- a/mmap_span/mmap_span.go +++ b/mmap_span/mmap_span.go @@ -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) { diff --git a/storage/file.go b/storage/file.go index 7f9d61b3..10df2637 100644 --- a/storage/file.go +++ b/storage/file.go @@ -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 diff --git a/storage/file_test.go b/storage/file_test.go index 0297c389..6e1d055e 100644 --- a/storage/file_test.go +++ b/storage/file_test.go @@ -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) } diff --git a/storage/interface.go b/storage/interface.go index 0662ebd2..71b34abd 100644 --- a/storage/interface.go +++ b/storage/interface.go @@ -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 { + 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) diff --git a/storage/mmap.go b/storage/mmap.go index e24c9c69..07faa191 100644 --- a/storage/mmap.go +++ b/storage/mmap.go @@ -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 diff --git a/torrent.go b/torrent.go index 228135c3..a7aa57e0 100644 --- a/torrent.go +++ b/torrent.go @@ -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