Changeset 4dcfe3e


Ignore:
Timestamp:
Jun 18, 2012 6:06:47 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
4b3ccab
Parents:
273d739
Message:
  • i2psnark:
    • Improve torrent shutdown handling to maximize chance of announces getting to tracker
    • Clean up delete-torrent messages
    • Remove redundant shutdown hook
    • Avoid NPE in PEX message handling
    • Log tweaks
Location:
apps/i2psnark/java/src/org/klomp/snark
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java

    r273d739 r4dcfe3e  
    311311            BEValue bev = dec.bdecodeMap();
    312312            Map<String, BEValue> map = bev.getMap();
    313             byte[] ids = map.get("added").getBytes();
     313            bev = map.get("added");
     314            if (bev == null)
     315                return;
     316            byte[] ids = bev.getBytes();
    314317            if (ids.length < HASH_LENGTH)
    315318                return;
  • apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java

    r273d739 r4dcfe3e  
    270270        _manager = null;
    271271        _shitlist.clear();
    272         mgr.destroySocketManager();
     272        if (mgr != null) {
     273            if (_log.shouldLog(Log.DEBUG))
     274                _log.debug("Disconnecting from I2P", new Exception("I did it"));
     275            mgr.destroySocketManager();
     276        }
    273277        // this will delete a .torrent file d/l in progress so don't do that...
    274278        FileUtil.rmdir(_tmpDir, false);
  • apps/i2psnark/java/src/org/klomp/snark/Snark.java

    r273d739 r4dcfe3e  
    573573    }
    574574  }
     575
    575576  /**
    576577   * Stop contacting the tracker and talking with peers
    577578   */
    578579  public void stopTorrent() {
     580      stopTorrent(false);
     581  }
     582
     583  /**
     584   * Stop contacting the tracker and talking with peers
     585   * @param fast if true, limit the life of the unannounce threads
     586   * @since 0.9.1
     587   */
     588  public void stopTorrent(boolean fast) {
    579589    stopped = true;
    580590    TrackerClient tc = trackerclient;
    581591    if (tc != null)
    582         tc.halt();
     592        tc.halt(fast);
    583593    PeerCoordinator pc = coordinator;
    584594    if (pc != null)
  • apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java

    r273d739 r4dcfe3e  
    3535import net.i2p.util.SecureDirectory;
    3636import net.i2p.util.SecureFileOutputStream;
     37import net.i2p.util.SimpleScheduler;
     38import net.i2p.util.SimpleTimer;
    3739
    3840/**
     
    146148        _monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
    147149        _monitor.start();
    148         _context.addShutdownTask(new SnarkManagerShutdown());
    149     }
    150 
     150        // Not required, Jetty has a shutdown hook
     151        //_context.addShutdownTask(new SnarkManagerShutdown());
     152    }
     153
     154    /*
     155     *  Called by the webapp at Jetty shutdown.
     156     *  Stops all torrents. Does not close the tunnel, so the announces have a chance.
     157     *  Fix this so an individual webaapp stop will close the tunnel.
     158     *  Runs inline.
     159     */
    151160    public void stop() {
    152161        _running = false;
    153162        _monitor.interrupt();
    154163        _connectionAcceptor.halt();
    155         (new SnarkManagerShutdown()).run();
     164        stopAllTorrents(true);
    156165    }
    157166   
     
    15911600    }
    15921601
    1593     public class SnarkManagerShutdown extends I2PAppThread {
    1594         @Override
    1595         public void run() {
    1596             Set names = listTorrentFiles();
    1597             for (Iterator iter = names.iterator(); iter.hasNext(); ) {
    1598                 Snark snark = getTorrent((String)iter.next());
    1599                 if ( (snark != null) && (!snark.isStopped()) ) {
    1600                     snark.stopTorrent();
    1601                     try { Thread.sleep(50); } catch (InterruptedException ie) {}
    1602                 }
    1603             }
    1604         }
    1605     }
    1606 
     1602    /**
     1603     * Stop all running torrents, and close the tunnel after a delay
     1604     * to allow for announces.
     1605     * If called at router shutdown via Jetty shutdown hook -> webapp destroy() -> stop(),
     1606     * the tunnel won't actually be closed as the SimpleScheduler is already shutdown
     1607     * or will be soon, so we delay a few seconds inline.
     1608     * @param finalShutdown if true, sleep at the end if any torrents were running
     1609     * @since 0.9.1
     1610     */
     1611    public void stopAllTorrents(boolean finalShutdown) {
     1612        if (finalShutdown && _log.shouldLog(Log.WARN))
     1613            _log.warn("SnarkManager final shutdown");
     1614        int count = 0;
     1615        for (Snark snark : _snarks.values()) {
     1616            if (!snark.isStopped()) {
     1617                if (count == 0)
     1618                    addMessage(_("Stopping all torrents and closing the I2P tunnel."));
     1619                count++;
     1620                if (finalShutdown)
     1621                    snark.stopTorrent(true);
     1622                else
     1623                    stopTorrent(snark, false);
     1624                // Throttle since every unannounce is now threaded.
     1625                // How to do this without creating a ton of threads?
     1626                try { Thread.sleep(20); } catch (InterruptedException ie) {}
     1627            }
     1628        }
     1629        if (_util.connected()) {
     1630            if (count > 0) {
     1631                // Schedule this even for final shutdown, as there's a chance
     1632                // that it's just this webapp that is stopping.
     1633                SimpleScheduler.getInstance().addEvent(new Disconnector(), 60*1000);
     1634                addMessage(_("Closing I2P tunnel after announces to trackers."));
     1635                if (finalShutdown) {
     1636                    try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
     1637                }
     1638            } else {
     1639                _util.disconnect();
     1640                addMessage(_("I2P tunnel closed."));
     1641            }
     1642        }
     1643    }
     1644
     1645    /** @since 0.9.1 */
     1646    private class Disconnector implements SimpleTimer.TimedEvent {
     1647        public void timeReached() {
     1648            if (_util.connected()) {
     1649                _util.disconnect();
     1650                addMessage(_("I2P tunnel closed."));
     1651            }
     1652        }
     1653    }
     1654   
    16071655    /**
    16081656     *  ignore case, current locale
  • apps/i2psnark/java/src/org/klomp/snark/SnarkShutdown.java

    r273d739 r4dcfe3e  
    2727/**
    2828 * Makes sure everything ends correctly when shutting down.
     29 * @deprecated unused
    2930 */
    3031public class SnarkShutdown extends I2PAppThread
     
    6263    //Snark.debug("Halting TrackerClient...", Snark.INFO);
    6364    if (trackerclient != null)
    64       trackerclient.halt();
     65      trackerclient.halt(true);
    6566
    6667    //Snark.debug("Halting PeerCoordinator...", Snark.INFO);
  • apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java

    r273d739 r4dcfe3e  
    2929import java.util.ArrayList;
    3030import java.util.Collections;
     31import java.util.Date;
    3132import java.util.Iterator;
    3233import java.util.List;
     
    9899  private volatile boolean runStarted;
    99100  private volatile  int consecutiveFails;
     101  private volatile boolean _fastUnannounce;
    100102
    101103  private final List<Tracker> trackers;
     
    135137      consecutiveFails = 0;
    136138      runStarted = false;
     139      _fastUnannounce = false;
    137140      _thread = new I2PAppThread(this, _threadName + " #" + (++_runCount), true);
    138141      _thread.start();
     
    145148  /**
    146149   * Interrupts this Thread to stop it.
    147    */
    148   public synchronized void halt() {
     150   * @param fast if true, limit the life of the unannounce threads
     151   */
     152  public synchronized void halt(boolean fast) {
    149153    boolean wasStopped = stop;
    150154    if (wasStopped) {
     
    169173        t.interrupt();
    170174    }
     175    _fastUnannounce = true;
    171176    if (!wasStopped)
    172177        unannounce();
     
    416421                    }
    417422                  }
     423              } else {
     424                  _util.debug("Not announcing to " + tr.announce + " last announce was " +
     425                               new Date(tr.lastRequestTime) + " interval is " + DataHelper.formatDuration(tr.interval), Snark.INFO);
    418426              }
    419427              if ((!tr.stop) && maxSeenPeers < tr.seenPeers)
     
    440448                    }
    441449                }
     450            } else {
     451                _util.debug("Not getting PEX peers", Snark.INFO);
    442452            }
    443453
     
    476486                    }
    477487                }
     488            } else {
     489                _util.debug("Not getting DHT peers", Snark.INFO);
    478490            }
    479491
     
    534546              tr.started && (!tr.stop) && tr.trackerProblems == null) {
    535547              try {
    536                   (new I2PAppThread(new Unannouncer(tr), _threadName + " Unannounce " + (++i), true)).start();
     548                  (new I2PAppThread(new Unannouncer(tr), _threadName + " U" + (++i), true)).start();
    537549              } catch (OutOfMemoryError oom) {
    538550                  // probably ran out of threads, ignore
     
    611623     
    612624    tr.lastRequestTime = System.currentTimeMillis();
    613     // Don't wait for a response to stopped.
    614     File fetched = _util.get(s, true, event.equals(STOPPED_EVENT) ? -1 : 0);
     625    // Don't wait for a response to stopped when shutting down
     626    boolean fast = _fastUnannounce && event.equals(STOPPED_EVENT);
     627    File fetched = _util.get(s, true, fast ? -1 : 0);
    615628    if (fetched == null) {
    616629        throw new IOException("Error fetching " + s);
  • apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java

    r273d739 r4dcfe3e  
    7575        _log = _context.logManager().getLog(I2PSnarkServlet.class);
    7676        _nonce = _context.random().nextLong();
     77        // FIXME instantiate new one every time
    7778        _manager = SnarkManager.instance();
    7879        String configFile = _context.getProperty(PROP_CONFIG_FILE);
     
    323324        String peerParam = req.getParameter("p");
    324325
    325         List snarks = getSortedSnarks(req);
     326        List<Snark> snarks = getSortedSnarks(req);
    326327        boolean isForm = _manager.util().connected() || !snarks.isEmpty();
    327328        if (isForm) {
     
    645646                                // each of those lists just contain a single file afaict...
    646647                                File df = Storage.getFileFromNames(f, files.get(i));
    647                                 if (df.delete())
    648                                     _manager.addMessage(_("Data file deleted: {0}", df.getAbsolutePath()));
    649                                 else
     648                                if (df.delete()) {
     649                                    //_manager.addMessage(_("Data file deleted: {0}", df.getAbsolutePath()));
     650                                } else {
    650651                                    _manager.addMessage(_("Data file could not be deleted: {0}", df.getAbsolutePath()));
     652                                }
    651653                            }
    652654                            // step 2 make Set of dirs with reverse sort
     
    660662                            for (File df : dirs) {
    661663                                if (df.delete()) {
    662                                     _manager.addMessage(_("Data dir deleted: {0}", df.getAbsolutePath()));
    663                                 } else if (_log.shouldLog(Log.WARN)) {
    664                                     _log.warn("Could not delete dir " + df);
     664                                    //_manager.addMessage(_("Data dir deleted: {0}", df.getAbsolutePath()));
     665                                } else {
     666                                    _manager.addMessage(_("Directory could not be deleted: {0}", df.getAbsolutePath()));
     667                                    if (_log.shouldLog(Log.WARN))
     668                                        _log.warn("Could not delete dir " + df);
    665669                                }
    666670                            }
    667671                            // step 4 delete base
    668672                            if (f.delete()) {
    669                                 _manager.addMessage(_("Data dir deleted: {0}", f.getAbsolutePath()));
    670                             } else if (_log.shouldLog(Log.WARN)) {
    671                                 _log.warn("Could not delete dir " + f);
     673                                _manager.addMessage(_("Directory deleted: {0}", f.getAbsolutePath()));
     674                            } else {
     675                                _manager.addMessage(_("Directory could not be deleted: {0}", f.getAbsolutePath()));
     676                                if (_log.shouldLog(Log.WARN))
     677                                    _log.warn("Could not delete dir " + f);
    672678                            }
    673679                            break;
     
    740746            }
    741747        } else if ("StopAll".equals(action)) {
    742             _manager.addMessage(_("Stopping all torrents and closing the I2P tunnel."));
    743             List snarks = getSortedSnarks(req);
    744             for (int i = 0; i < snarks.size(); i++) {
    745                 Snark snark = (Snark)snarks.get(i);
    746                 if (!snark.isStopped()) {
    747                     _manager.stopTorrent(snark, false);
    748                     try { Thread.sleep(50); } catch (InterruptedException ie) {}
    749                 }
    750             }
    751             if (_manager.util().connected()) {
    752                 // Give the stopped announces time to get out
    753                 try { Thread.sleep(2000); } catch (InterruptedException ie) {}
    754                 _manager.util().disconnect();
    755                 _manager.addMessage(_("I2P tunnel closed."));
    756             }
     748            _manager.stopAllTorrents(false);
    757749        } else if ("StartAll".equals(action)) {
    758750            _manager.addMessage(_("Opening the I2P tunnel and starting all torrents."));
    759             List snarks = getSortedSnarks(req);
     751            List<Snark> snarks = getSortedSnarks(req);
    760752            for (int i = 0; i < snarks.size(); i++) {
    761                 Snark snark = (Snark)snarks.get(i);
     753                Snark snark = snarks.get(i);
    762754                if (snark.isStopped())
    763755                    snark.startTorrent();
Note: See TracChangeset for help on using the changeset viewer.