]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Return errors from Reader if data downloading won't occur
authorMatt Joiner <anacrolix@gmail.com>
Tue, 27 Oct 2020 03:10:17 +0000 (14:10 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Tue, 27 Oct 2020 03:10:17 +0000 (14:10 +1100)
Chunk write errors to storage can disable data download. Previously Readers would wait indefinitely for the data to become available. This change returns an error instead of stalling.

reader.go
test/issue377_test.go
torrent.go

index 1f68fdbe6c94e658acbc44a5a37048748e47ddf4..1e1c36e120eaa8df583869cd3ed2a0898998fbd3 100644 (file)
--- a/reader.go
+++ b/reader.go
@@ -199,6 +199,10 @@ func (r *reader) waitAvailable(pos, wanted int64, ctxErr *error, wait bool) (ava
                        err = *ctxErr
                        return
                }
+               if r.t.dataDownloadDisallowed || !r.t.networkingEnabled {
+                       err = errors.New("downloading disabled and data not already available")
+                       return
+               }
                if !wait {
                        return
                }
index abc57a9051b1841534ff213b19bc5ff11af12fc5..05ef14292c3d75c8afa91ea0b31d642943de4a5b 100644 (file)
@@ -2,6 +2,8 @@ package test
 
 import (
        "errors"
+       "io"
+       "io/ioutil"
        "os"
        "sync"
        "testing"
@@ -73,7 +75,27 @@ func testReceiveChunkStorageFailure(t *testing.T, seederFast bool) {
        // Tell the seeder to find the leecher. Is it guaranteed seeders will always try to do this?
        seederTorrent.AddClientPeer(leecherClient)
        <-leecherTorrent.GotInfo()
-       assertReadAllGreeting(t, leecherTorrent.NewReader())
+       r := leecherTorrent.Files()[0].NewReader()
+       defer r.Close()
+       // We can't use assertReadAllGreeting here, because the default storage write error handler
+       // disables data downloads, which now causes Readers to error when they're blocked.
+       if false {
+               assertReadAllGreeting(t, leecherTorrent.NewReader())
+       } else {
+               for func() bool {
+                       // We don't seem to need to seek, but that's probably just because the storage failure is
+                       // happening on the first read.
+                       r.Seek(0, io.SeekStart)
+                       output, err := ioutil.ReadAll(r)
+                       if err != nil {
+                               t.Logf("got error while reading: %v", err)
+                               return true
+                       }
+                       assert.EqualValues(t, testutil.GreetingFileContents, output)
+                       return false
+               }() {
+               }
+       }
        // TODO: Check that PeerConns fastEnabled matches seederFast?
        //select {}
 }
index ace386eb3fce410cde0a57bf9742fea57e21ee0e..561d3d60bbd9ef265af1f748d19f6b5ca1a9dd24 100644 (file)
@@ -2024,6 +2024,7 @@ func (t *Torrent) onWriteChunkErr(err error) {
                go t.userOnWriteChunkErr(err)
                return
        }
+       t.logger.WithDefaultLevel(log.Critical).Printf("default chunk write error handler: disabling data download")
        t.disallowDataDownloadLocked()
 }
 
@@ -2038,12 +2039,14 @@ func (t *Torrent) disallowDataDownloadLocked() {
        t.iterPeers(func(c *peer) {
                c.updateRequests()
        })
+       t.tickleReaders()
 }
 
 func (t *Torrent) AllowDataDownload() {
        t.cl.lock()
        defer t.cl.unlock()
        t.dataDownloadDisallowed = false
+       t.tickleReaders()
        t.iterPeers(func(c *peer) {
                c.updateRequests()
        })