* i2psnark:

- Add allocating and checking indications
   - Add bandwidth message at startup
   - More checks at torrent creation
This commit is contained in:
zzz
2012-10-06 13:41:50 +00:00
parent 0448537509
commit ddc750469c
5 changed files with 102 additions and 22 deletions

View File

@ -787,7 +787,8 @@ class PeerCoordinator implements PeerListener
}
if (record) {
if (_log.shouldLog(Log.INFO))
_log.info(peer + " is now requesting: piece " + piece + " priority " + piece.getPriority());
_log.info("Now requesting from " + peer + ": piece " + piece + " priority " + piece.getPriority() +
" peers " + piece.getPeerCount() + '/' + peers.size());
piece.setRequested(peer, true);
}
return piece;

View File

@ -688,6 +688,22 @@ public class Snark
starting = true;
}
/**
* File checking in progress.
* @since 0.9.3
*/
public boolean isChecking() {
return storage != null && storage.isChecking();
}
/**
* Disk allocation (ballooning) in progress.
* @since 0.9.3
*/
public boolean isAllocating() {
return storage != null && storage.isAllocating();
}
/**
* @since 0.8.4
*/

View File

@ -707,7 +707,7 @@ public class SnarkManager implements Snark.CompleteListener {
public Properties getConfig() { return _config; }
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
private static final int MAX_FILES_PER_TORRENT = 512;
public static final int MAX_FILES_PER_TORRENT = 512;
/**
* Set of canonical .torrent filenames that we are dealing with.
@ -1370,6 +1370,8 @@ public class SnarkManager implements Snark.CompleteListener {
} catch (Exception e) {
_log.error("Error in the DirectoryMonitor", e);
}
if (!_snarks.isEmpty())
addMessage(_("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
}
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
}

View File

@ -32,6 +32,7 @@ import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.crypto.SHA1;
import net.i2p.data.ByteArray;
@ -45,7 +46,7 @@ import net.i2p.util.SystemVersion;
*/
public class Storage
{
private MetaInfo metainfo;
private final MetaInfo metainfo;
private long[] lengths;
private RandomAccessFile[] rafs;
private String[] names;
@ -69,6 +70,8 @@ public class Storage
private final int pieces;
private final long total_length;
private boolean changed;
private volatile boolean _isChecking;
private final AtomicInteger _allocateCount = new AtomicInteger();
/** The default piece size. */
private static final int MIN_PIECE_SIZE = 256*1024;
@ -89,17 +92,15 @@ public class Storage
* Creates a new storage based on the supplied MetaInfo. This will
* try to create and/or check all needed files in the MetaInfo.
*
* @exception IOException when creating and/or checking files fails.
* Does not check storage. Caller MUST call check()
*/
public Storage(I2PSnarkUtil util, MetaInfo metainfo, StorageListener listener)
throws IOException
{
_util = util;
_log = util.getContext().logManager().getLog(Storage.class);
this.metainfo = metainfo;
this.listener = listener;
needed = metainfo.getPieces();
_probablyComplete = false;
bitfield = new BitField(needed);
piece_size = metainfo.getPieceLength(0);
pieces = needed;
@ -107,12 +108,15 @@ public class Storage
}
/**
* Creates a storage from the existing file or directory together
* with an appropriate MetaInfo file as can be announced on the
* given announce String location.
* Creates a storage from the existing file or directory.
* Creates an in-memory metainfo but does not save it to
* a file, caller must do that.
*
* Creates the metainfo, this may take a LONG time. BLOCKING.
*
* @param announce may be null
* @param listener may be null
* @throws IOException when creating and/or checking files fails.
*/
public Storage(I2PSnarkUtil util, File baseFile, String announce,
boolean privateTorrent, StorageListener listener)
@ -135,6 +139,8 @@ public class Storage
if (total <= 0)
throw new IOException("Torrent contains no data");
if (total > MAX_TOTAL_SIZE)
throw new IOException("Torrent too big (" + total + " bytes), max is " + MAX_TOTAL_SIZE);
int pc_size = MIN_PIECE_SIZE;
int pcs = (int) ((total - 1)/pc_size) + 1;
@ -170,6 +176,7 @@ public class Storage
lengthsList = null;
}
// TODO thread this so we can return and show something on the UI
byte[] piece_hashes = fast_digestCreate();
metainfo = new MetaInfo(announce, baseFile.getName(), null, files,
lengthsList, piece_size, piece_hashes, total, privateTorrent);
@ -205,6 +212,8 @@ public class Storage
private void getFiles(File base) throws IOException
{
if (base.getAbsolutePath().equals("/"))
throw new IOException("Don't seed root");
ArrayList files = new ArrayList();
addFiles(files, base);
@ -233,12 +242,15 @@ public class Storage
}
}
private void addFiles(List l, File f)
{
if (!f.isDirectory())
l.add(f);
else
{
/**
* @throws IOException if too many total files
*/
private void addFiles(List l, File f) throws IOException {
if (!f.isDirectory()) {
if (l.size() >= SnarkManager.MAX_FILES_PER_TORRENT)
throw new IOException("Too many files, limit is " + SnarkManager.MAX_FILES_PER_TORRENT + ", zip them?");
l.add(f);
} else {
File[] files = f.listFiles();
if (files == null)
{
@ -284,6 +296,23 @@ public class Storage
return changed;
}
/**
* File checking in progress.
* @since 0.9.3
*/
public boolean isChecking() {
return _isChecking;
}
/**
* Disk allocation (ballooning) in progress.
* Always false on Windows.
* @since 0.9.3
*/
public boolean isAllocating() {
return _allocateCount.get() > 0;
}
/**
* @param file canonical path (non-directory)
* @return number of bytes remaining; -1 if unknown file
@ -703,11 +732,25 @@ public class Storage
* This is called at the beginning, and at presumed completion,
* so we have to be careful about locking.
*
* TODO thread the checking so we can return and display
* something on the UI
*
* @param recheck if true, this is a check after we downloaded the
* last piece, and we don't modify the global bitfield unless
* the check fails.
*/
private void checkCreateFiles(boolean recheck) throws IOException
private void checkCreateFiles(boolean recheck) throws IOException {
synchronized(this) {
_isChecking = true;
try {
locked_checkCreateFiles(recheck);
} finally {
_isChecking = false;
}
}
}
private void locked_checkCreateFiles(boolean recheck) throws IOException
{
// Whether we are resuming or not,
// if any of the files already exists we assume we are resuming.
@ -867,10 +910,19 @@ public class Storage
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
byte[] zeros = new byte[ZEROBLOCKSIZE];
rafs[nr].seek(0);
while (remaining > 0) {
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
remaining -= size;
// don't bother setting flag for small files
if (remaining > 20*1024*1024)
_allocateCount.incrementAndGet();
try {
while (remaining > 0) {
int size = (int) Math.min(remaining, ZEROBLOCKSIZE);
rafs[nr].write(zeros, 0, size);
remaining -= size;
}
} finally {
remaining = lengths[nr];
if (remaining > 20*1024*1024)
_allocateCount.decrementAndGet();
}
isSparse[nr] = false;
}

View File

@ -743,6 +743,7 @@ public class I2PSnarkServlet extends DefaultServlet {
try {
// This may take a long time to check the storage, but since it already exists,
// it shouldn't be THAT bad, so keep it in this thread.
// TODO thread it for big torrents, perhaps a la FetchAndAdd
boolean isPrivate = _manager.getPrivateTrackers().contains(announceURL);
Storage s = new Storage(_manager.util(), baseFile, announceURL, isPrivate, null);
s.close(); // close the files... maybe need a way to pass this Storage to addTorrent rather than starting over
@ -992,7 +993,13 @@ public class I2PSnarkServlet extends DefaultServlet {
String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
String statusString;
if (err != null) {
if (snark.isChecking()) {
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" title=\"" + _("Checking") + "\"></td>" +
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Checking");
} else if (snark.isAllocating()) {
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" title=\"" + _("Allocating") + "\"></td>" +
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Allocating");
} else if (err != null) {
if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td>" +
"<td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
@ -1174,7 +1181,9 @@ public class I2PSnarkServlet extends DefaultServlet {
String b64 = Base64.encode(snark.getInfoHash());
if (showPeers)
parameters = parameters + "&p=1";
if (isRunning) {
if (snark.isChecking()) {
// show no buttons
} else if (isRunning) {
// Stop Button
if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");