From 24dd78394b83d1eba9684fb2ea4e202668a45541 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 15 Oct 2010 17:25:45 +0000 Subject: [PATCH] priority persistence --- .../src/org/klomp/snark/SnarkManager.java | 63 ++++++++++++++++++- .../java/src/org/klomp/snark/Storage.java | 21 ++++++- .../org/klomp/snark/web/I2PSnarkServlet.java | 5 +- 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index b0fe6d1ba7..240515e595 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -54,6 +54,7 @@ public class SnarkManager implements Snark.CompleteListener { public static final String PROP_DIR = "i2psnark.dir"; public static final String PROP_META_PREFIX = "i2psnark.zmeta."; public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; + public static final String PROP_META_PRIORITY_SUFFIX = ".priority"; private static final String CONFIG_FILE = "i2psnark.config"; public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops @@ -510,6 +511,7 @@ public class SnarkManager implements Snark.CompleteListener { torrent = new Snark(_util, filename, null, -1, null, null, this, _peerCoordinatorSet, _connectionAcceptor, false, dataDir.getPath()); + loadSavedFilePriorities(torrent); torrent.completeListener = this; synchronized (_snarks) { _snarks.put(filename, torrent); @@ -587,6 +589,33 @@ public class SnarkManager implements Snark.CompleteListener { return new BitField(bitfield, len); } + /** + * Get the saved priorities for a torrent from the config file. + * @since 0.8.1 + */ + public void loadSavedFilePriorities(Snark snark) { + MetaInfo metainfo = snark.meta; + if (metainfo.getFiles() == null) + return; + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String pri = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX); + if (pri == null) + return; + int filecount = metainfo.getFiles().size(); + int[] rv = new int[filecount]; + String[] arr = pri.split(","); + for (int i = 0; i < filecount && i < arr.length; i++) { + if (arr[i].length() > 0) { + try { + rv[i] = Integer.parseInt(arr[i]); + } catch (Throwable t) {} + } + } + snark.storage.setFilePriorities(rv); + } + /** * Save the completion status of a torrent and the current time in the config file * in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield". @@ -595,8 +624,9 @@ public class SnarkManager implements Snark.CompleteListener { * The time is a standard long converted to string. * The status is either a bitfield converted to Base64 or "." for a completed * torrent to save space in the config file and in memory. + * @param priorities may be null */ - public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) { + public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities) { byte[] ih = metainfo.getInfoHash(); String infohash = Base64.encode(ih); infohash = infohash.replace('=', '$'); @@ -609,6 +639,34 @@ public class SnarkManager implements Snark.CompleteListener { bfs = Base64.encode(bf); } _config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs); + + // now the file priorities + String prop = PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX; + if (priorities != null) { + boolean nonzero = false; + for (int i = 0; i < priorities.length; i++) { + if (priorities[i] != 0) { + nonzero = true; + break; + } + } + if (nonzero) { + // generate string like -5,,4,3,,,,,,-2 where no number is zero. + StringBuilder buf = new StringBuilder(2 * priorities.length); + for (int i = 0; i < priorities.length; i++) { + if (priorities[i] != 0) + buf.append(Integer.toString(priorities[i])); + if (i != priorities.length - 1) + buf.append(','); + } + _config.setProperty(prop, buf.toString()); + } else { + _config.remove(prop); + } + } else { + _config.remove(prop); + } + saveConfig(); } @@ -621,6 +679,7 @@ public class SnarkManager implements Snark.CompleteListener { String infohash = Base64.encode(ih); infohash = infohash.replace('=', '$'); _config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + _config.remove(PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX); saveConfig(); } @@ -742,7 +801,7 @@ public class SnarkManager implements Snark.CompleteListener { } public void updateStatus(Snark snark) { - saveTorrentStatus(snark.meta, snark.storage.getBitField()); + saveTorrentStatus(snark.meta, snark.storage.getBitField(), snark.storage.getFilePriorities()); } private void monitorTorrents(File dir) { diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index 1e8fb5ec2e..d208adc34b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -379,6 +379,25 @@ public class Storage } } + /** + * Get the file priorities array. + * @return null on error, if complete, or if only one file + * @since 0.8.1 + */ + public int[] getFilePriorities() { + return priorities; + } + + /** + * Set the file priorities array. + * Only call this when stopped, but after check() + * @param p may be null + * @since 0.8.1 + */ + void setFilePriorities(int[] p) { + priorities = p; + } + /** * Call setPriority() for all changed files first, * then call this. @@ -389,7 +408,7 @@ public class Storage * @since 0.8.1 */ public int[] getPiecePriorities() { - if (complete() || metainfo.getFiles() == null) + if (complete() || metainfo.getFiles() == null || priorities == null) return null; int[] rv = new int[metainfo.getPieces()]; int file = 0; diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 1c97678005..19fb3bd0fe 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -503,7 +503,7 @@ public class I2PSnarkServlet extends Default { File torrentFile = new File(baseFile.getParent(), baseFile.getName() + ".torrent"); if (torrentFile.exists()) throw new IOException("Cannot overwrite an existing .torrent file: " + torrentFile.getPath()); - _manager.saveTorrentStatus(info, s.getBitField()); // so addTorrent won't recheck + _manager.saveTorrentStatus(info, s.getBitField(), null); // so addTorrent won't recheck // DirMonitor could grab this first, maybe hold _snarks lock? FileOutputStream out = new FileOutputStream(torrentFile); out.write(info.getTorrentData()); @@ -1498,7 +1498,7 @@ public class I2PSnarkServlet extends Default { } /** @since 0.8.1 */ - private static void savePriorities(Snark snark, Map postParams) { + private void savePriorities(Snark snark, Map postParams) { Set entries = postParams.entrySet(); for (Map.Entry entry : entries) { String key = (String)entry.getKey(); @@ -1514,6 +1514,7 @@ public class I2PSnarkServlet extends Default { } if (snark.coordinator != null) snark.coordinator.updatePiecePriorities(); + _manager.saveTorrentStatus(snark.storage.getMetaInfo(), snark.storage.getBitField(), snark.storage.getFilePriorities()); }