Changeset e71d2012


Ignore:
Timestamp:
Sep 7, 2011 1:34:54 AM (9 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
8233c4f
Parents:
b062d3b
Message:
  • TunnelDispatcher?: Change participant expire List to a Queue for efficiency and to remove global lock. Also remove separate time List for space savings.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java

    rb062d3b re71d2012  
    77import java.util.List;
    88import java.util.Map;
     9import java.util.concurrent.LinkedBlockingQueue;
    910
    1011import net.i2p.data.DataHelper;
     
    758759    public void renderStatusHTML(Writer out) throws IOException {}   
    759760   
     761    /**
     762     *  Expire participants.
     763     *  For efficiency, we keep the HopConfigs in a FIFO, and assume that
     764     *  tunnels expire (roughly) in the same order as they are added.
     765     *  As tunnels have a fixed expiration from now, that's a good assumption -
     766     *  see BuildHandler.handleReq().
     767     */
    760768    private class LeaveTunnel extends JobImpl {
    761         private List<HopConfig> _configs;
    762         private List<Long> _times;
     769        private final LinkedBlockingQueue<HopConfig> _configs;
    763770       
    764771        public LeaveTunnel(RouterContext ctx) {
    765772            super(ctx);
    766             getTiming().setStartAfter(ctx.clock().now());
    767             _configs = new ArrayList(128);
    768             _times = new ArrayList(128);
     773            _configs = new LinkedBlockingQueue();
     774            // 20 min no tunnels accepted + 10 min tunnel expiration
     775            getTiming().setStartAfter(ctx.clock().now() + 30*60*1000);
     776            getContext().jobQueue().addJob(LeaveTunnel.this);
    769777        }
    770778       
    771779        private static final int LEAVE_BATCH_TIME = 10*1000;
     780
    772781        public void add(HopConfig cfg) {
    773             Long dropTime = Long.valueOf(cfg.getExpiration() + 2*Router.CLOCK_FUDGE_FACTOR + LEAVE_BATCH_TIME);
    774             boolean noTunnels;
    775             synchronized (LeaveTunnel.this) {
    776                 noTunnels = _configs.isEmpty();
    777                 _configs.add(cfg);
    778                 _times.add(dropTime);
    779            
    780                 // Make really sure we queue or requeue the job only when we have to, or else bad things happen.
    781                 // Locking around this part may not be sufficient but there was nothing before.
    782                 // Symptom is the Leave Participant job not running for 12m, leading to seesaw participating tunnel count
    783 
    784                 long oldAfter = getTiming().getStartAfter();
    785                 long oldStart = getTiming().getActualStart();
    786                 if ( noTunnels || (oldAfter <= 0) ||
    787                      (oldAfter < getContext().clock().now() && oldAfter <= oldStart) || // if oldAfter > oldStart, it's late but it will run, so don't do this (race)
    788                      (oldAfter >= dropTime.longValue()) ) {
    789                     getTiming().setStartAfter(dropTime.longValue());
    790                     getContext().jobQueue().addJob(LeaveTunnel.this);
    791                 } else {
    792                     // already scheduled for the future, and before this expiration
     782            _configs.offer(cfg);
     783        }
     784       
     785        public String getName() { return "Expire participating tunnels"; }
     786        public void runJob() {
     787            HopConfig cur = null;
     788            long now = getContext().clock().now() + LEAVE_BATCH_TIME; // leave all expiring in next 10 sec
     789            long nextTime = now + 10*60*1000;
     790            while ((cur = _configs.peek()) != null) {
     791                long exp = cur.getExpiration() + (2 * Router.CLOCK_FUDGE_FACTOR) + LEAVE_BATCH_TIME;
     792                if (exp < now) {
     793                    _configs.poll();
     794                    remove(cur);
     795                } else if (exp < nextTime) {
     796                    nextTime = exp;
     797                    break;
    793798                }
    794799            }
    795             if (_log.shouldLog(Log.DEBUG)) {
    796                 long now = getContext().clock().now();
    797                 _log.debug("Scheduling leave in " + DataHelper.formatDuration(dropTime.longValue()-now) +": " + cfg);
    798             }
    799         }
    800        
    801         public String getName() { return "Leave participant"; }
    802         public void runJob() {
    803             HopConfig cur = null;
    804             Long nextTime = null;
    805             long now = getContext().clock().now() + LEAVE_BATCH_TIME; // leave all expiring in next 10 sec
    806             while (true) {
    807                 synchronized (LeaveTunnel.this) {
    808                     if (_configs.isEmpty())
    809                         return;
    810                     nextTime = _times.get(0);
    811                     if (nextTime.longValue() <= now) {
    812                         cur = _configs.remove(0);
    813                         _times.remove(0);
    814                         if (!_times.isEmpty())
    815                             nextTime = _times.get(0);
    816                         else
    817                             nextTime = null;
    818                     } else {
    819                         cur = null;
    820                     }
    821                 }
    822 
    823                 if (cur != null)
    824                     remove(cur);
    825                 else
    826                     break;
    827             }
    828            
    829             if (nextTime != null) {
    830                 synchronized (LeaveTunnel.this) {
    831                     getTiming().setStartAfter(nextTime.longValue());
    832                     getContext().jobQueue().addJob(LeaveTunnel.this);
    833                 }
    834             }
     800            getTiming().setStartAfter(nextTime);
     801            getContext().jobQueue().addJob(LeaveTunnel.this);
    835802        }
    836803    }
Note: See TracChangeset for help on using the changeset viewer.