Return errors from Reader if data downloading won't occur

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.
This commit is contained in:
Matt Joiner 2020-10-27 14:10:17 +11:00
parent 2a7352aad2
commit 43891309ad
3 changed files with 30 additions and 1 deletions

View File

@ -199,6 +199,10 @@ func (r *reader) waitAvailable(pos, wanted int64, ctxErr *error, wait bool) (ava
err = *ctxErr err = *ctxErr
return return
} }
if r.t.dataDownloadDisallowed || !r.t.networkingEnabled {
err = errors.New("downloading disabled and data not already available")
return
}
if !wait { if !wait {
return return
} }

View File

@ -2,6 +2,8 @@ package test
import ( import (
"errors" "errors"
"io"
"io/ioutil"
"os" "os"
"sync" "sync"
"testing" "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? // Tell the seeder to find the leecher. Is it guaranteed seeders will always try to do this?
seederTorrent.AddClientPeer(leecherClient) seederTorrent.AddClientPeer(leecherClient)
<-leecherTorrent.GotInfo() <-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? // TODO: Check that PeerConns fastEnabled matches seederFast?
//select {} //select {}
} }

View File

@ -2024,6 +2024,7 @@ func (t *Torrent) onWriteChunkErr(err error) {
go t.userOnWriteChunkErr(err) go t.userOnWriteChunkErr(err)
return return
} }
t.logger.WithDefaultLevel(log.Critical).Printf("default chunk write error handler: disabling data download")
t.disallowDataDownloadLocked() t.disallowDataDownloadLocked()
} }
@ -2038,12 +2039,14 @@ func (t *Torrent) disallowDataDownloadLocked() {
t.iterPeers(func(c *peer) { t.iterPeers(func(c *peer) {
c.updateRequests() c.updateRequests()
}) })
t.tickleReaders()
} }
func (t *Torrent) AllowDataDownload() { func (t *Torrent) AllowDataDownload() {
t.cl.lock() t.cl.lock()
defer t.cl.unlock() defer t.cl.unlock()
t.dataDownloadDisallowed = false t.dataDownloadDisallowed = false
t.tickleReaders()
t.iterPeers(func(c *peer) { t.iterPeers(func(c *peer) {
c.updateRequests() c.updateRequests()
}) })