diff --git a/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy b/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy index 3438d867..ccc9e93d 100644 --- a/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy +++ b/core/src/main/groovy/com/muwire/core/download/DownloadManager.groovy @@ -74,7 +74,7 @@ public class DownloadManager { destinations.addAll(e.sources) destinations.remove(me.destination) - Pieces pieces = getPieces(infohash, size, pieceSize) + Pieces pieces = getPieces(infohash, size, pieceSize, e.sequential) def downloader = new Downloader(eventBus, this, me, e.target, size, infohash, pieceSize, connector, destinations, @@ -122,8 +122,12 @@ public class DownloadManager { byte [] root = Base64.decode(json.hashRoot) infoHash = new InfoHash(root) } + + boolean sequential = false + if (json.sequential != null) + sequential = json.sequential - Pieces pieces = getPieces(infoHash, (long)json.length, json.pieceSizePow2) + Pieces pieces = getPieces(infoHash, (long)json.length, json.pieceSizePow2, sequential) def downloader = new Downloader(eventBus, this, me, file, (long)json.length, infoHash, json.pieceSizePow2, connector, destinations, incompletes, pieces) @@ -137,12 +141,12 @@ public class DownloadManager { } } - private Pieces getPieces(InfoHash infoHash, long length, int pieceSizePow2) { + private Pieces getPieces(InfoHash infoHash, long length, int pieceSizePow2, boolean sequential) { int pieceSize = 0x1 << pieceSizePow2 int nPieces = (int)(length / pieceSize) if (length % pieceSize != 0) nPieces++ - Mesh mesh = meshManager.getOrCreate(infoHash, nPieces) + Mesh mesh = meshManager.getOrCreate(infoHash, nPieces, sequential) mesh.pieces } @@ -188,6 +192,9 @@ public class DownloadManager { json.hashRoot = Base64.encode(infoHash.getRoot()) json.paused = downloader.paused + + json.sequential = downloader.pieces.ratio == 0f + writer.println(JsonOutput.toJson(json)) } } 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 adf17abc..2d90ca89 100644 --- a/core/src/main/groovy/com/muwire/core/download/Pieces.groovy +++ b/core/src/main/groovy/com/muwire/core/download/Pieces.groovy @@ -17,7 +17,7 @@ class Pieces { done = new BitSet(nPieces) claimed = new BitSet(nPieces) } - + synchronized int[] claim() { int claimedCardinality = claimed.cardinality() if (claimedCardinality == nPieces) { @@ -30,7 +30,7 @@ class Pieces { } // if fuller than ratio just do sequential - if ( (1.0f * claimedCardinality) / nPieces > ratio) { + if ( (1.0f * claimedCardinality) / nPieces >= ratio) { int rv = claimed.nextClearBit(0) claimed.set(rv) return [rv, partials.getOrDefault(rv, 0), 0] @@ -59,7 +59,8 @@ class Pieces { return [rv, partials.getOrDefault(rv, 0), 1] } List toList = availableCopy.toList() - Collections.shuffle(toList) + if (ratio > 0f) + Collections.shuffle(toList) int rv = toList[0] claimed.set(rv) [rv, partials.getOrDefault(rv, 0), 0] diff --git a/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy b/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy index 8e03864f..78cd4bcd 100644 --- a/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy +++ b/core/src/main/groovy/com/muwire/core/download/UIDownloadEvent.groovy @@ -10,4 +10,5 @@ class UIDownloadEvent extends Event { UIResultEvent[] result Set sources File target + boolean sequential } diff --git a/core/src/main/groovy/com/muwire/core/mesh/MeshManager.groovy b/core/src/main/groovy/com/muwire/core/mesh/MeshManager.groovy index ef12f0b9..607e6a39 100644 --- a/core/src/main/groovy/com/muwire/core/mesh/MeshManager.groovy +++ b/core/src/main/groovy/com/muwire/core/mesh/MeshManager.groovy @@ -33,11 +33,12 @@ class MeshManager { meshes.get(infoHash) } - Mesh getOrCreate(InfoHash infoHash, int nPieces) { + Mesh getOrCreate(InfoHash infoHash, int nPieces, boolean sequential) { synchronized(meshes) { if (meshes.containsKey(infoHash)) return meshes.get(infoHash) - Pieces pieces = new Pieces(nPieces, settings.downloadSequentialRatio) + float ratio = sequential ? 0f : settings.downloadSequentialRatio + Pieces pieces = new Pieces(nPieces, ratio) if (fileManager.rootToFiles.containsKey(infoHash)) { for (int i = 0; i < nPieces; i++) pieces.markDownloaded(i) diff --git a/core/src/main/groovy/com/muwire/core/upload/UploadManager.groovy b/core/src/main/groovy/com/muwire/core/upload/UploadManager.groovy index 63536258..ed157beb 100644 --- a/core/src/main/groovy/com/muwire/core/upload/UploadManager.groovy +++ b/core/src/main/groovy/com/muwire/core/upload/UploadManager.groovy @@ -92,7 +92,7 @@ public class UploadManager { pieceSize = downloader.pieceSizePow2 } else { SharedFile sharedFile = sharedFiles.iterator().next(); - mesh = meshManager.getOrCreate(request.infoHash, sharedFile.NPieces) + mesh = meshManager.getOrCreate(request.infoHash, sharedFile.NPieces, false) file = sharedFile.file pieceSize = sharedFile.pieceSize } @@ -217,7 +217,7 @@ public class UploadManager { pieceSize = downloader.pieceSizePow2 } else { SharedFile sharedFile = sharedFiles.iterator().next(); - mesh = meshManager.getOrCreate(request.infoHash, sharedFile.NPieces) + mesh = meshManager.getOrCreate(request.infoHash, sharedFile.NPieces, false) file = sharedFile.file pieceSize = sharedFile.pieceSize } diff --git a/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy b/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy index bbd4c319..1e6ca88e 100644 --- a/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy +++ b/gui/griffon-app/controllers/com/muwire/gui/SearchTabController.groovy @@ -46,7 +46,8 @@ class SearchTabController { def resultsBucket = model.hashBucket[result.infohash] def sources = model.sourcesBucket[result.infohash] - core.eventBus.publish(new UIDownloadEvent(result : resultsBucket, sources: sources, target : file)) + core.eventBus.publish(new UIDownloadEvent(result : resultsBucket, sources: sources, + target : file, sequential : view.sequentialDownloadCheckbox.model.isSelected())) mvcGroup.parentGroup.view.showDownloadsWindow.call() } diff --git a/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy b/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy index 68e7dd8d..5d96ae28 100644 --- a/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy +++ b/gui/griffon-app/views/com/muwire/gui/SearchTabView.groovy @@ -43,11 +43,13 @@ class SearchTabView { def lastSendersSortEvent def resultsTable def lastSortEvent + def sequentialDownloadCheckbox void initUI() { builder.with { def resultsTable def sendersTable + def sequentialDownloadCheckbox def pane = panel { gridLayout(rows :1, cols : 1) splitPane(orientation: JSplitPane.VERTICAL_SPLIT, continuousLayout : true, dividerLocation: 300 ) { @@ -83,7 +85,14 @@ class SearchTabView { } } panel(constraints : BorderLayout.SOUTH) { - button(text : "Download", enabled : bind {model.downloadActionEnabled}, downloadAction) + borderLayout() + panel(constraints: BorderLayout.CENTER) { + button(text : "Download", enabled : bind {model.downloadActionEnabled}, downloadAction) + } + panel(constraints: BorderLayout.EAST) { + sequentialDownloadCheckbox = checkBox(selected : false) + label(text : "Download sequentially") + } } } } @@ -95,6 +104,7 @@ class SearchTabView { this.resultsTable = resultsTable this.sendersTable = sendersTable + this.sequentialDownloadCheckbox = sequentialDownloadCheckbox def selectionModel = resultsTable.getSelectionModel() selectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION)