diff --git a/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy b/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy index 2dc6ddfa..2fd5c1ee 100644 --- a/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy +++ b/core/src/main/groovy/com/muwire/core/download/DownloadSession.groovy @@ -79,9 +79,10 @@ class DownloadSession { return false int piece = pieceAndPosition[0] int position = pieceAndPosition[1] + boolean steal = pieceAndPosition[2] == 1 boolean unclaim = true - log.info("will download piece $piece from position $position") + log.info("will download piece $piece from position $position steal $steal") long pieceStart = piece * pieceSize long end = Math.min(fileLength, pieceStart + pieceSize) - 1 @@ -208,7 +209,7 @@ class DownloadSession { pieces.markDownloaded(piece) unclaim = false } finally { - if (unclaim) + if (unclaim && !steal) pieces.unclaim(piece) } return true diff --git a/core/src/main/groovy/com/muwire/core/download/Pieces.groovy b/core/src/main/groovy/com/muwire/core/download/Pieces.groovy index a7e0c7e9..1915a5ce 100644 --- a/core/src/main/groovy/com/muwire/core/download/Pieces.groovy +++ b/core/src/main/groovy/com/muwire/core/download/Pieces.groovy @@ -20,14 +20,20 @@ class Pieces { synchronized int[] claim() { int claimedCardinality = claimed.cardinality() - if (claimedCardinality == nPieces) - return null + if (claimedCardinality == nPieces) { + // steal + int downloadedCardinality = done.cardinality() + if (downloadedCardinality == nPieces) + return null + int rv = done.nextClearBit(0) + return [rv, partials.getOrDefault(rv, 0), 1] + } // if fuller than ratio just do sequential if ( (1.0f * claimedCardinality) / nPieces > ratio) { int rv = claimed.nextClearBit(0) claimed.set(rv) - return [rv, partials.getOrDefault(rv, 0)] + return [rv, partials.getOrDefault(rv, 0), 0] } while(true) { @@ -35,20 +41,28 @@ class Pieces { if (claimed.get(start)) continue claimed.set(start) - return [start, partials.getOrDefault(start,0)] + return [start, partials.getOrDefault(start,0), 0] } } synchronized int[] claim(Set available) { - for (int i = claimed.nextSetBit(0); i >= 0; i = claimed.nextSetBit(i+1)) + for (int i = done.nextSetBit(0); i >= 0; i = done.nextSetBit(i+1)) available.remove(i) if (available.isEmpty()) return null + Set availableCopy = new HashSet<>(available) + for (int i = claimed.nextSetBit(0); i >= 0; i = claimed.nextSetBit(i+1)) + availableCopy.remove(i) + if (availableCopy.isEmpty()) { + // steal + int rv = available.first() + return [rv, partials.getOrDefault(rv, 0), 1] + } List toList = available.toList() Collections.shuffle(toList) int rv = toList[0] claimed.set(rv) - [rv, partials.getOrDefault(rv, 0)] + [rv, partials.getOrDefault(rv, 0), 0] } synchronized def getDownloaded() {