Changeset f14ff31


Ignore:
Timestamp:
May 30, 2012 8:03:30 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
9f1c95c
Parents:
ddc329e8
Message:
  • Timestamper:
    • Move from core to router, leave stub in core so it doesn't break compatibility. This removes a thread in app context and prevents any app context from running NTP; external clients must use the time received from the router.
    • Increase query interval
Files:
2 added
8 edited
2 moved

Legend:

Unmodified
Added
Removed
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java

    rddc329e8 rf14ff31  
    6262   
    6363    public void setSave(String moo) { _saveRequested = true; }
    64     public void setEnabletimesync(String moo) { }
    6564    public void setRecheckReachability(String moo) { _recheckReachabilityRequested = true; }
    6665    public void setRequireIntroductions(String moo) { _requireIntroductions = true; }
     
    290289            }
    291290
    292             // Time sync enable, means NOT disabled
    293             // Hmm router sets this at startup, not required here
    294             //changes.put(Timestamper.PROP_DISABLED, "false");
    295            
    296291            // Hidden in the GUI
    297292            //LoadTestManager.setEnableLoadTesting(_context, _enableLoadTesting);
  • apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java

    rddc329e8 rf14ff31  
    1010import net.i2p.router.transport.udp.UDPAddress;
    1111import net.i2p.router.transport.udp.UDPTransport;
    12 import net.i2p.time.Timestamper;
    1312import net.i2p.util.Addresses;
    1413
     
    6665    }
    6766
    68     public String getEnableTimeSyncChecked() {
    69         boolean disabled = _context.getBooleanProperty(Timestamper.PROP_DISABLED);
    70         if (disabled)
    71             return "";
    72         else
    73             return CHECKED;
    74     }
    75    
    7667    /** @param prop must default to false */
    7768    public String getChecked(String prop) {
  • core/java/src/net/i2p/time/Timestamper.java

    rddc329e8 rf14ff31  
    11package net.i2p.time;
    22
    3 import java.util.ArrayList;
    4 import java.util.List;
    5 import java.util.Locale;
    6 import java.util.StringTokenizer;
    7 import java.util.concurrent.CopyOnWriteArrayList;
    8 
    9 import net.i2p.I2PAppContext;
    10 import net.i2p.util.I2PThread;
    11 import net.i2p.util.Log;
    12 
    133/**
    14  * Periodically query a series of NTP servers and update any associated
    15  * listeners.  It tries the NTP servers in order, contacting them using
    16  * SNTP (UDP port 123).  By default, it does this every 5 minutes,
    17  * forever.
     4 * Dummy. Real thing moved to net.i2p.router.time.RouterTimestamper.
     5 * What remains here is essentially an interface,
     6 * containing only what is needed to keep external apps
     7 * compiled with old libs from breaking, since
     8 * net.i2p.util.Clock returns a Timestamper in getTimestamper()
     9 *
     10 * Deprecated outside of the router.
    1811 */
    1912public class Timestamper implements Runnable {
    20     private final I2PAppContext _context;
    21     private Log _log;
    22     private final List<String> _servers;
    23     private List<String> _priorityServers;
    24     private final List<UpdateListener> _listeners;
    25     private int _queryFrequency;
    26     private int _concurringServers;
    27     private int _consecutiveFails;
    28     private volatile boolean _disabled;
    29     private final boolean _daemon;
    30     private boolean _initialized;
    31     private boolean _wellSynced;
    32     private volatile boolean _isRunning;
    33     private Thread _timestamperThread;
    3413   
    35     private static final int MIN_QUERY_FREQUENCY = 5*60*1000;
    36     private static final int DEFAULT_QUERY_FREQUENCY = 5*60*1000;
    37     private static final String DEFAULT_SERVER_LIST = "0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org";
    38     private static final String DEFAULT_DISABLED = "true";
    39     /** how many times do we have to query if we are changing the clock? */
    40     private static final int DEFAULT_CONCURRING_SERVERS = 3;
    41     private static final int MAX_CONSECUTIVE_FAILS = 10;
     14    /** dummy */
     15    public Timestamper() {}
    4216   
    43     public static final String PROP_QUERY_FREQUENCY = "time.queryFrequencyMs";
    44     public static final String PROP_SERVER_LIST = "time.sntpServerList";
    45     public static final String PROP_DISABLED = "time.disabled";
    46     public static final String PROP_CONCURRING_SERVERS = "time.concurringServers";
    47     public static final String PROP_IP_COUNTRY = "i2np.lastCountry";
    48    
    49     /** if different SNTP servers differ by more than 10s, someone is b0rked */
    50     private static final int MAX_VARIANCE = 10*1000;
    51        
    52     public Timestamper(I2PAppContext ctx) {
    53         this(ctx, null, true);
    54     }
    55    
    56     public Timestamper(I2PAppContext ctx, UpdateListener lsnr) {
    57         this(ctx, lsnr, true);
    58     }
    59     public Timestamper(I2PAppContext ctx, UpdateListener lsnr, boolean daemon) {
    60         // moved here to prevent problems with synchronized statements.
    61         _servers = new ArrayList(3);
    62         _listeners = new CopyOnWriteArrayList();
    63         _context = ctx;
    64         _daemon = daemon;
    65         // DO NOT initialize _log here, stack overflow via LogManager init loop
    66 
    67         // Don't bother starting a thread if we are disabled.
    68         // This means we no longer check every 5 minutes to see if we got enabled,
    69         // so the property must be set at startup.
    70         // We still need to be instantiated since the router calls clock().getTimestamper().waitForInitialization()
    71         String disabled = ctx.getProperty(PROP_DISABLED, DEFAULT_DISABLED);
    72         if (Boolean.valueOf(disabled).booleanValue()) {
    73             _initialized = true;
    74             return;
    75         }
    76         if (lsnr != null)
    77             _listeners.add(lsnr);
    78         updateConfig();
    79         startTimestamper();
    80     }
    81    
    82     public int getServerCount() {
    83         synchronized (_servers) {
    84             return _servers.size();
    85         }
    86     }
    87     public String getServer(int index) {
    88         synchronized (_servers) {
    89             return _servers.get(index);
    90         }
    91     }
    92    
    93     public int getQueryFrequencyMs() { return _queryFrequency; }
    94    
    95     public boolean getIsDisabled() { return _disabled; }
    96    
    97     public void addListener(UpdateListener lsnr) {
    98             _listeners.add(lsnr);
    99     }
    100     public void removeListener(UpdateListener lsnr) {
    101             _listeners.remove(lsnr);
    102     }
    103     public int getListenerCount() {
    104             return _listeners.size();
    105     }
    106     public UpdateListener getListener(int index) {
    107             return _listeners.get(index);
    108     }
    109    
    110     private void startTimestamper() {
    111         _timestamperThread = new I2PThread(this, "Timestamper", _daemon);
    112         _timestamperThread.setPriority(I2PThread.MIN_PRIORITY);
    113         _isRunning = true;
    114         _timestamperThread.start();
    115         _context.addShutdownTask(new Shutdown());
    116     }
    117    
    118     public void waitForInitialization() {
    119         try {
    120             synchronized (this) {
    121                 if (!_initialized)
    122                     wait();
    123             }
    124         } catch (InterruptedException ie) {}
    125     }
     17    /** dummy */
     18    public void waitForInitialization() {}
    12619   
    12720    /**
    12821     *  Update the time immediately.
     22     *  Dummy
    12923     *  @since 0.8.8
    13024     */
    131     public void timestampNow() {
    132          if (_initialized && _isRunning && (!_disabled) && _timestamperThread != null)
    133              _timestamperThread.interrupt();
    134     }
     25    public void timestampNow() {}
    13526   
    136     /** @since 0.8.8 */
    137     private class Shutdown implements Runnable {
    138         public void run() {
    139              _isRunning = false;
    140              if (_timestamperThread != null)
    141                  _timestamperThread.interrupt();
    142         }
    143     }
    144    
    145     public void run() {
    146         try { Thread.sleep(1000); } catch (InterruptedException ie) {}
    147         _log = _context.logManager().getLog(Timestamper.class);
    148         if (_log.shouldLog(Log.INFO))
    149             _log.info("Starting timestamper");
    150         boolean lastFailed = false;
    151         try {
    152             while (_isRunning) {
    153                 updateConfig();
    154                 if (!_disabled) {
    155                     // first the servers for our country, if we know what country we're in...
    156                     if (_priorityServers != null) {
    157                         if (_log.shouldLog(Log.DEBUG))
    158                             _log.debug("Querying servers " + _priorityServers);
    159                         try {
    160                             lastFailed = !queryTime(_priorityServers.toArray(new String[_priorityServers.size()]));
    161                         } catch (IllegalArgumentException iae) {
    162                             if ( (!lastFailed) && (_log.shouldLog(Log.WARN)) )
    163                                 _log.warn("Unable to reach country-specific NTP servers");
    164                             lastFailed = true;
    165                         }
    166                     }
    167                     // ... and then the global list, if that failed
    168                     if (_priorityServers == null || lastFailed) {
    169                         if (_log.shouldLog(Log.DEBUG))
    170                             _log.debug("Querying servers " + _servers);
    171                         try {
    172                             lastFailed = !queryTime(_servers.toArray(new String[_servers.size()]));
    173                         } catch (IllegalArgumentException iae) {
    174                             if ( (!_initialized) && (_log.shouldLog(Log.ERROR)) ) {
    175                                 List<String> all = new ArrayList();
    176                                 if (_priorityServers != null)
    177                                     all.addAll(_priorityServers);
    178                                 all.addAll(_servers);
    179                                 _log.error("Unable to reach any of the NTP servers " + all + " - network disconnected? Or set time.sntpServerList=myserver1.com,myserver2.com in advanced configuration.");
    180                             }
    181                             lastFailed = true;
    182                         }
    183                     }
    184                 }
    185                
    186                 _initialized = true;
    187                 synchronized (this) { notifyAll(); }
    188                 long sleepTime;
    189                 if (lastFailed) {
    190                     if (++_consecutiveFails >= MAX_CONSECUTIVE_FAILS)
    191                         sleepTime = 30*60*1000;
    192                     else
    193                         sleepTime = 30*1000;
    194                 } else {
    195                     _consecutiveFails = 0;
    196                     sleepTime = _context.random().nextInt(_queryFrequency) + _queryFrequency;
    197                     if (_wellSynced)
    198                         sleepTime *= 3;
    199                 }
    200                 try { Thread.sleep(sleepTime); } catch (InterruptedException ie) {}
    201             }
    202         } catch (Throwable t) {
    203             _log.log(Log.CRIT, "Timestamper died!", t);
    204             synchronized (this) { notifyAll(); }
    205         }
    206     }
    207    
    208     /**
    209      * True if the time was queried successfully, false if it couldn't be
    210      */
    211     private boolean queryTime(String serverList[]) throws IllegalArgumentException {
    212         long found[] = new long[_concurringServers];
    213         long now = -1;
    214         int stratum = -1;
    215         long expectedDelta = 0;
    216         _wellSynced = false;
    217         for (int i = 0; i < _concurringServers; i++) {
    218             if (i > 0) {
    219                 // this delays startup when net is disconnected or the timeserver list is bad, don't make it too long
    220                 try { Thread.sleep(2*1000); } catch (InterruptedException ie) {}
    221             }
    222             long[] timeAndStratum = NtpClient.currentTimeAndStratum(serverList);
    223             now = timeAndStratum[0];
    224             stratum = (int) timeAndStratum[1];
    225             long delta = now - _context.clock().now();
    226             found[i] = delta;
    227             if (i == 0) {
    228                 if (Math.abs(delta) < MAX_VARIANCE) {
    229                     if (_log.shouldLog(Log.INFO))
    230                         _log.info("a single SNTP query was within the tolerance (" + delta + "ms)");
    231                     // If less than a half second on the first try, we're in good shape
    232                     _wellSynced = Math.abs(delta) < 500;
    233                     break;
    234                 } else {
    235                     // outside the tolerance, lets iterate across the concurring queries
    236                     expectedDelta = delta;
    237                 }
    238             } else {
    239                 if (Math.abs(delta - expectedDelta) > MAX_VARIANCE) {
    240                     if (_log.shouldLog(Log.ERROR)) {
    241                         StringBuilder err = new StringBuilder(96);
    242                         err.append("SNTP client variance exceeded at query ").append(i);
    243                         err.append(".  expected = ");
    244                         err.append(expectedDelta);
    245                         err.append(", found = ");
    246                         err.append(delta);
    247                         err.append(" all deltas: ");
    248                         for (int j = 0; j < found.length; j++)
    249                             err.append(found[j]).append(' ');
    250                         _log.error(err.toString());
    251                     }
    252                     return false;
    253                 }
    254             }
    255         }
    256         stampTime(now, stratum);
    257         if (_log.shouldLog(Log.DEBUG)) {
    258             StringBuilder buf = new StringBuilder(64);
    259             buf.append("Deltas: ");
    260             for (int i = 0; i < found.length; i++)
    261                 buf.append(found[i]).append(' ');
    262             _log.debug(buf.toString());
    263         }
    264         return true;
    265     }
    266    
    267     /**
    268      * Notify the listeners
    269      *
    270      * @since stratum param added in 0.7.12
    271      */
    272     private void stampTime(long now, int stratum) {
    273         long before = _context.clock().now();
    274         for (UpdateListener lsnr : _listeners) {
    275              lsnr.setNow(now, stratum);
    276         }
    277         if (_log.shouldLog(Log.DEBUG))
    278             _log.debug("Stamped the time as " + now + " (delta=" + (now-before) + ")");
    279     }
    280  
    281     /**
    282      * Reload all the config elements from the appContext
    283      *
    284      */
    285     private void updateConfig() {
    286         String serverList = _context.getProperty(PROP_SERVER_LIST);
    287         if ( (serverList == null) || (serverList.trim().length() <= 0) ) {
    288             serverList = DEFAULT_SERVER_LIST;
    289             String country = _context.getProperty(PROP_IP_COUNTRY);
    290             if (country == null) {
    291                 country = Locale.getDefault().getCountry();
    292                 if (country != null)
    293                     country = country.toLowerCase(Locale.US);
    294             }
    295             if (country != null &&  country.length() > 0) {
    296                 _priorityServers = new ArrayList(3);
    297                 for (int i = 0; i < 3; i++)
    298                      _priorityServers.add(i + "." + country + ".pool.ntp.org");
    299             } else {
    300                 _priorityServers = null;
    301             }
    302         } else {
    303             _priorityServers = null;
    304         }
    305         _servers.clear();
    306         StringTokenizer tok = new StringTokenizer(serverList, ", ");
    307         while (tok.hasMoreTokens()) {
    308             String val = tok.nextToken();
    309             val = val.trim();
    310             if (val.length() > 0)
    311                 _servers.add(val);
    312         }
    313        
    314         _queryFrequency = Math.max(MIN_QUERY_FREQUENCY,
    315                                    _context.getProperty(PROP_QUERY_FREQUENCY, DEFAULT_QUERY_FREQUENCY));
    316        
    317         String disabled = _context.getProperty(PROP_DISABLED, DEFAULT_DISABLED);
    318         _disabled = Boolean.valueOf(disabled).booleanValue();
    319        
    320         _concurringServers = Math.min(4, Math.max(1,
    321                               _context.getProperty(PROP_CONCURRING_SERVERS, DEFAULT_CONCURRING_SERVERS)));
    322     }
    323    
    324 /****
    325     public static void main(String args[]) {
    326         System.setProperty(PROP_DISABLED, "false");
    327         System.setProperty(PROP_QUERY_FREQUENCY, "30000");
    328         I2PAppContext.getGlobalContext();
    329         for (int i = 0; i < 5*60*1000; i += 61*1000) {
    330             try { Thread.sleep(61*1000); } catch (InterruptedException ie) {}
    331         }
    332     }
    333 ****/
     27    /** dummy */
     28    public void run() {}
    33429   
    33530    /**
  • core/java/src/net/i2p/time/package.html

    rddc329e8 rf14ff31  
    22    <body>
    33        <p>
    4             Provides classes for time synchronisation using NTP.
     4            Provides a stub class for time synchronization.
     5            Full implementation is now in net.i2p.router.time.
    56        </p>
    67    </body>
  • core/java/src/net/i2p/util/Clock.java

    rddc329e8 rf14ff31  
    2020public class Clock implements Timestamper.UpdateListener {
    2121    protected final I2PAppContext _context;
    22     private final Timestamper _timestamper;
    2322    protected long _startedOn;
    2423    protected boolean _statCreated;
     
    3029        _context = context;
    3130        _listeners = new CopyOnWriteArraySet();
    32         _timestamper = new Timestamper(context, this);
    3331        _startedOn = System.currentTimeMillis();
    3432    }
     
    3836    }
    3937   
    40     public Timestamper getTimestamper() { return _timestamper; }
     38    /**
     39     *  This is a dummy, see RouterClock and RouterTimestamper for the real thing
     40     */
     41    public Timestamper getTimestamper() { return new Timestamper(); }
    4142   
    4243    /** we fetch it on demand to avoid circular dependencies (logging uses the clock) */
  • history.txt

    rddc329e8 rf14ff31  
     12012-05-30 zzz
     2 * Graphs: Reduce log EOF error to warn
     3 * i2psnark:
     4   - Increase max upload (ticket #645)
     5   - Increase per-minute conn limit from 6 to 8
     6   - Improve rarest-first behavior
     7   - Handle URI encoding, UTF-8, and multiple trackers in magnet links
     8 * Timestamper:
     9   - Move from core to router, leave stub in core
     10     so it doesn't break compatibility. This removes a
     11     thread in app context and prevents any app context from
     12     running NTP; external clients must use the time
     13     received from the router.
     14   - Increase query interval
     15
    1162012-05-28 kytv
    2 * i2prouter: Add support so that 'i2prouter install' will work in ArchLinux
    3 * jbigi/jcpuid scripts: Improve support for ArchLinux
     17 * i2prouter: Add support so that 'i2prouter install' will work in ArchLinux
     18 * jbigi/jcpuid scripts: Improve support for ArchLinux
    419
    5202012-05-25 kytv
  • router/java/src/net/i2p/router/RouterClock.java

    rddc329e8 rf14ff31  
    55
    66import net.i2p.data.DataHelper;
     7import net.i2p.router.time.RouterTimestamper;
     8import net.i2p.time.Timestamper;
    79import net.i2p.util.Clock;
    810import net.i2p.util.Log;
     
    3941    private long _lastChanged;
    4042    private int _lastStratum;
     43    private final Timestamper _timeStamper;
    4144
    4245    /**
     
    5760        _shiftListeners = new CopyOnWriteArraySet();
    5861        _lastShiftNanos = System.nanoTime();
    59     }
     62        _timeStamper = new RouterTimestamper(context, this);
     63    }
     64
     65    /**
     66     *  The RouterTimestamper
     67     */
     68    @Override
     69    public Timestamper getTimestamper() { return _timeStamper; }
    6070
    6171    /**
  • router/java/src/net/i2p/router/RouterVersion.java

    rddc329e8 rf14ff31  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 6;
     21    public final static long BUILD = 7;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/time/NtpClient.java

    rddc329e8 rf14ff31  
    1 package net.i2p.time;
     1package net.i2p.router.time;
    22/*
    33 * Copyright (c) 2004, Adam Buckley
     
    5050 * @author Adam Buckley
    5151 * (minor refactoring by jrandom)
     52 * @since 0.9.1 moved from net.i2p.time
    5253 */
    53 public class NtpClient {
     54class NtpClient {
    5455    /** difference between the unix epoch and jan 1 1900 (NTP uses that) */
    5556    private final static double SECONDS_1900_TO_EPOCH = 2208988800.0;
  • router/java/src/net/i2p/router/time/NtpMessage.java

    rddc329e8 rf14ff31  
    1 package net.i2p.time;
     1package net.i2p.router.time;
    22/*
    33 * Copyright (c) 2004, Adam Buckley
     
    7373 *
    7474 * @author Adam Buckley
     75 * @since 0.9.1 moved from net.i2p.time
    7576 */
    76 public class NtpMessage {
     77class NtpMessage {
    7778    /**
    7879     * This is a two-bit code warning of an impending leap second to be
Note: See TracChangeset for help on using the changeset viewer.