]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/immutable/downloader/node.py
fix #1223, crash+inefficiency during repair due to read overrun
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / immutable / downloader / node.py
index 33c16cfaa5487fae6bd2d9c69588389a5a6c3774..04482e630b1609d412ef7fbfad08379e4d4babfe 100644 (file)
@@ -130,8 +130,9 @@ class DownloadNode:
         # for concurrent operations: each gets its own Segmentation manager
         if size is None:
             size = self._verifycap.size
-        # clip size so offset+size does not go past EOF
-        size = min(size, self._verifycap.size-offset)
+        # ignore overruns: clip size so offset+size does not go past EOF, and
+        # so size is not negative (which indicates that offset >= EOF)
+        size = max(0, min(size, self._verifycap.size-offset))
         if read_ev is None:
             read_ev = self._download_status.add_read_event(offset, size, now())
 
@@ -143,6 +144,10 @@ class DownloadNode:
             sp = self._history.stats_provider
             sp.count("downloader.files_downloaded", 1) # really read() calls
             sp.count("downloader.bytes_downloaded", size)
+        if size == 0:
+            read_ev.finished(now())
+            # no data, so no producer, so no register/unregisterProducer
+            return defer.succeed(consumer)
         s = Segmentation(self, offset, size, consumer, read_ev, lp)
         # this raises an interesting question: what segments to fetch? if
         # offset=0, always fetch the first segment, and then allow