priority persistence
This commit is contained in:
@ -54,6 +54,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
public static final String PROP_DIR = "i2psnark.dir";
|
public static final String PROP_DIR = "i2psnark.dir";
|
||||||
public static final String PROP_META_PREFIX = "i2psnark.zmeta.";
|
public static final String PROP_META_PREFIX = "i2psnark.zmeta.";
|
||||||
public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield";
|
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";
|
private static final String CONFIG_FILE = "i2psnark.config";
|
||||||
public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops
|
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,
|
torrent = new Snark(_util, filename, null, -1, null, null, this,
|
||||||
_peerCoordinatorSet, _connectionAcceptor,
|
_peerCoordinatorSet, _connectionAcceptor,
|
||||||
false, dataDir.getPath());
|
false, dataDir.getPath());
|
||||||
|
loadSavedFilePriorities(torrent);
|
||||||
torrent.completeListener = this;
|
torrent.completeListener = this;
|
||||||
synchronized (_snarks) {
|
synchronized (_snarks) {
|
||||||
_snarks.put(filename, torrent);
|
_snarks.put(filename, torrent);
|
||||||
@ -587,6 +589,33 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
return new BitField(bitfield, len);
|
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
|
* Save the completion status of a torrent and the current time in the config file
|
||||||
* in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield".
|
* 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 time is a standard long converted to string.
|
||||||
* The status is either a bitfield converted to Base64 or "." for a completed
|
* The status is either a bitfield converted to Base64 or "." for a completed
|
||||||
* torrent to save space in the config file and in memory.
|
* 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();
|
byte[] ih = metainfo.getInfoHash();
|
||||||
String infohash = Base64.encode(ih);
|
String infohash = Base64.encode(ih);
|
||||||
infohash = infohash.replace('=', '$');
|
infohash = infohash.replace('=', '$');
|
||||||
@ -609,6 +639,34 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
bfs = Base64.encode(bf);
|
bfs = Base64.encode(bf);
|
||||||
}
|
}
|
||||||
_config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs);
|
_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();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,6 +679,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
String infohash = Base64.encode(ih);
|
String infohash = Base64.encode(ih);
|
||||||
infohash = infohash.replace('=', '$');
|
infohash = infohash.replace('=', '$');
|
||||||
_config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
|
_config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
|
||||||
|
_config.remove(PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX);
|
||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,7 +801,7 @@ public class SnarkManager implements Snark.CompleteListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateStatus(Snark snark) {
|
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) {
|
private void monitorTorrents(File dir) {
|
||||||
|
@ -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,
|
* Call setPriority() for all changed files first,
|
||||||
* then call this.
|
* then call this.
|
||||||
@ -389,7 +408,7 @@ public class Storage
|
|||||||
* @since 0.8.1
|
* @since 0.8.1
|
||||||
*/
|
*/
|
||||||
public int[] getPiecePriorities() {
|
public int[] getPiecePriorities() {
|
||||||
if (complete() || metainfo.getFiles() == null)
|
if (complete() || metainfo.getFiles() == null || priorities == null)
|
||||||
return null;
|
return null;
|
||||||
int[] rv = new int[metainfo.getPieces()];
|
int[] rv = new int[metainfo.getPieces()];
|
||||||
int file = 0;
|
int file = 0;
|
||||||
|
@ -503,7 +503,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
File torrentFile = new File(baseFile.getParent(), baseFile.getName() + ".torrent");
|
File torrentFile = new File(baseFile.getParent(), baseFile.getName() + ".torrent");
|
||||||
if (torrentFile.exists())
|
if (torrentFile.exists())
|
||||||
throw new IOException("Cannot overwrite an existing .torrent file: " + torrentFile.getPath());
|
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?
|
// DirMonitor could grab this first, maybe hold _snarks lock?
|
||||||
FileOutputStream out = new FileOutputStream(torrentFile);
|
FileOutputStream out = new FileOutputStream(torrentFile);
|
||||||
out.write(info.getTorrentData());
|
out.write(info.getTorrentData());
|
||||||
@ -1498,7 +1498,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @since 0.8.1 */
|
/** @since 0.8.1 */
|
||||||
private static void savePriorities(Snark snark, Map postParams) {
|
private void savePriorities(Snark snark, Map postParams) {
|
||||||
Set<Map.Entry> entries = postParams.entrySet();
|
Set<Map.Entry> entries = postParams.entrySet();
|
||||||
for (Map.Entry entry : entries) {
|
for (Map.Entry entry : entries) {
|
||||||
String key = (String)entry.getKey();
|
String key = (String)entry.getKey();
|
||||||
@ -1514,6 +1514,7 @@ public class I2PSnarkServlet extends Default {
|
|||||||
}
|
}
|
||||||
if (snark.coordinator != null)
|
if (snark.coordinator != null)
|
||||||
snark.coordinator.updatePiecePriorities();
|
snark.coordinator.updatePiecePriorities();
|
||||||
|
_manager.saveTorrentStatus(snark.storage.getMetaInfo(), snark.storage.getBitField(), snark.storage.getFilePriorities());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user