[jboss-cvs] JBoss Messaging SVN: r4206 - in trunk/src/main/org/jboss/messaging: util and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu May 15 10:25:42 EDT 2008


Author: jmesnil
Date: 2008-05-15 10:25:42 -0400 (Thu, 15 May 2008)
New Revision: 4206

Added:
   trunk/src/main/org/jboss/messaging/util/UUID.java
   trunk/src/main/org/jboss/messaging/util/UUIDGenerator.java
   trunk/src/main/org/jboss/messaging/util/UUIDTimer.java
Modified:
   trunk/src/main/org/jboss/messaging/jms/client/JBossMessageProducer.java
Log:
used our custom UUID to generate JMS Message IDs in JBossMessageProducer.
the UUID is generated in JBossMessageProducer ctor and a sequence number is appended and incremented for every JMS message sent

Modified: trunk/src/main/org/jboss/messaging/jms/client/JBossMessageProducer.java
===================================================================
--- trunk/src/main/org/jboss/messaging/jms/client/JBossMessageProducer.java	2008-05-15 13:02:45 UTC (rev 4205)
+++ trunk/src/main/org/jboss/messaging/jms/client/JBossMessageProducer.java	2008-05-15 14:25:42 UTC (rev 4206)
@@ -21,7 +21,10 @@
   */
 package org.jboss.messaging.jms.client;
 
+import java.net.InetAddress;
+import java.net.UnknownHostException;
 import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
 
 import javax.jms.BytesMessage;
 import javax.jms.DeliveryMode;
@@ -45,6 +48,7 @@
 import org.jboss.messaging.core.logging.Logger;
 import org.jboss.messaging.jms.JBossDestination;
 import org.jboss.messaging.util.SimpleString;
+import org.jboss.messaging.util.UUIDGenerator;
 
 /**
  * @author <a href="mailto:ovidiu at feodorov.com">Ovidiu Feodorov</a>
@@ -75,7 +79,11 @@
    
    private int defaultDeliveryMode = DeliveryMode.PERSISTENT;
    
-   private JBossDestination defaultDestination;   
+   private JBossDestination defaultDestination;
+   
+   private final String messageIDPrefix;
+   
+   private final AtomicLong sequenceNumber = new AtomicLong(0);
 
    // Constructors --------------------------------------------------
    
@@ -84,6 +92,19 @@
       this.producer = producer;     
       
       this.defaultDestination = defaultDestination;
+      
+      //TODO the UUID should be generated at the JMS Connection level, 
+      // then session, producers & messages ID could be created using simple sequences
+      String uuid = null;
+      try
+      {
+         UUIDGenerator gen = UUIDGenerator.getInstance();
+         uuid = gen.generateTimeBasedUUID(InetAddress.getLocalHost()).toString();
+      } catch (UnknownHostException e)
+      {
+         uuid = java.util.UUID.randomUUID().toString();
+      }      
+      messageIDPrefix = "ID:" + uuid + ":";
    }
    
    // MessageProducer implementation --------------------------------
@@ -396,10 +417,7 @@
       if (!disableMessageID)
       {
          // Generate an id
-
-         String id = UUID.randomUUID().toString();
-
-         jbm.setJMSMessageID("ID:" + id);
+         jbm.setJMSMessageID(messageIDPrefix + sequenceNumber.incrementAndGet());
       }
 
       if (foreign)

Added: trunk/src/main/org/jboss/messaging/util/UUID.java
===================================================================
--- trunk/src/main/org/jboss/messaging/util/UUID.java	                        (rev 0)
+++ trunk/src/main/org/jboss/messaging/util/UUID.java	2008-05-15 14:25:42 UTC (rev 4206)
@@ -0,0 +1,217 @@
+/* JUG Java Uuid Generator
+ *
+ * Copyright (c) 2002- Tatu Saloranta, tatu.saloranta at iki.fi
+ *
+ * Licensed under the License specified in the file LICENSE which is
+ * included with the source code.
+ * You may not use this file except in compliance with the License.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.messaging.util;
+
+
+/**
+ * UUID represents Universally Unique Identifiers (aka Global UID in Windows
+ * world). UUIDs are usually generated via UUIDGenerator (or in case of 'Null
+ * UUID', 16 zero bytes, via static method getNullUUID()), or received from
+ * external systems.
+ * 
+ * By default class caches the string presentations of UUIDs so that description
+ * is only created the first time it's needed. For memory stingy applications
+ * this caching can be turned off (note though that if uuid.toString() is never
+ * called, desc is never calculated so only loss is the space allocated for the
+ * desc pointer... which can of course be commented out to save memory).
+ * 
+ * Similarly, hash code is calculated when it's needed for the first time, and
+ * from thereon that value is just returned. This means that using UUIDs as keys
+ * should be reasonably efficient.
+ * 
+ * UUIDs can be compared for equality, serialized, cloned and even sorted.
+ * Equality is a simple bit-wise comparison. Ordering (for sorting) is done by
+ * first ordering based on type (in the order of numeric values of types),
+ * secondarily by time stamp (only for time-based time stamps), and finally by
+ * straight numeric byte-by-byte comparison (from most to least significant
+ * bytes).
+ */
+
+public class UUID
+{
+   private final static String kHexChars = "0123456789abcdefABCDEF";
+
+   public final static byte INDEX_CLOCK_HI = 6;
+   public final static byte INDEX_CLOCK_MID = 4;
+   public final static byte INDEX_CLOCK_LO = 0;
+
+   public final static byte INDEX_TYPE = 6;
+   // Clock seq. & variant are multiplexed...
+   public final static byte INDEX_CLOCK_SEQUENCE = 8;
+   public final static byte INDEX_VARIATION = 8;
+
+   public final static byte TYPE_NULL = 0;
+   public final static byte TYPE_TIME_BASED = 1;
+   public final static byte TYPE_DCE = 2; // Not used
+   public final static byte TYPE_NAME_BASED = 3;
+   public final static byte TYPE_RANDOM_BASED = 4;
+
+   /*
+    * 'Standard' namespaces defined (suggested) by UUID specs:
+    */
+   public final static String NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";
+   public final static String NAMESPACE_URL = "6ba7b811-9dad-11d1-80b4-00c04fd430c8";
+   public final static String NAMESPACE_OID = "6ba7b812-9dad-11d1-80b4-00c04fd430c8";
+   public final static String NAMESPACE_X500 = "6ba7b814-9dad-11d1-80b4-00c04fd430c8";
+
+   /*
+    * By default let's cache desc, can be turned off. For hash code there's no
+    * point in turning it off (since the int is already part of the instance
+    * memory allocation); if you want to save those 4 bytes (or possibly bit
+    * more if alignment is bad) just comment out hash caching.
+    */
+   private static boolean sDescCaching = true;
+
+   private final byte[] mId = new byte[16];
+   // Both string presentation and hash value may be cached...
+   private transient String mDesc = null;
+   private transient int mHashCode = 0;
+
+   /**
+    * Protected constructor used by UUIDGenerator
+    * 
+    * @param type
+    *           UUID type
+    * @param data
+    *           16 byte UUID contents
+    */
+   UUID(int type, byte[] data)
+   {
+      for (int i = 0; i < 16; ++i)
+      {
+         mId[i] = data[i];
+      }
+      // Type is multiplexed with time_hi:
+      mId[INDEX_TYPE] &= (byte) 0x0F;
+      mId[INDEX_TYPE] |= (byte) (type << 4);
+      // Variant masks first two bits of the clock_seq_hi:
+      mId[INDEX_VARIATION] &= (byte) 0x3F;
+      mId[INDEX_VARIATION] |= (byte) 0x80;
+   }
+
+   /**
+    * Could use just the default hash code, but we can probably create a better
+    * identity hash (ie. same contents generate same hash) manually, without
+    * sacrificing speed too much. Although multiplications with modulos would
+    * generate better hashing, let's use just shifts, and do 2 bytes at a time.
+    * <p>
+    * Of course, assuming UUIDs are randomized enough, even simpler approach
+    * might be good enough?
+    * <p>
+    * Is this a good hash? ... one of these days I better read more about basic
+    * hashing techniques I swear!
+    */
+   private final static int[] kShifts = { 3, 7, 17, 21, 29, 4, 9 };
+
+   public int hashCode()
+   {
+      if (mHashCode == 0)
+      {
+         // Let's handle first and last byte separately:
+         int result = mId[0] & 0xFF;
+
+         result |= (result << 16);
+         result |= (result << 8);
+
+         for (int i = 1; i < 15; i += 2)
+         {
+            int curr = (mId[i] & 0xFF) << 8 | (mId[i + 1] & 0xFF);
+            int shift = kShifts[i >> 1];
+
+            if (shift > 16)
+            {
+               result ^= (curr << shift) | (curr >>> (32 - shift));
+            } else
+            {
+               result ^= (curr << shift);
+            }
+         }
+
+         // and then the last byte:
+         int last = mId[15] & 0xFF;
+         result ^= (last << 3);
+         result ^= (last << 13);
+
+         result ^= (last << 27);
+         // Let's not accept hash 0 as it indicates 'not hashed yet':
+         if (result == 0)
+         {
+            mHashCode = -1;
+         } else
+         {
+            mHashCode = result;
+         }
+      }
+      return mHashCode;
+   }
+
+   public String toString()
+   {
+      /*
+       * Could be synchronized, but there isn't much harm in just taking our
+       * chances (ie. in the worst case we'll form the string more than once...
+       * but result is the same)
+       */
+
+      if (mDesc == null)
+      {
+         StringBuffer b = new StringBuffer(36);
+
+         for (int i = 0; i < 16; ++i)
+         {
+            // Need to bypass hyphens:
+            switch (i)
+            {
+            case 4:
+            case 6:
+            case 8:
+            case 10:
+               b.append('-');
+            }
+            int hex = mId[i] & 0xFF;
+            b.append(kHexChars.charAt(hex >> 4));
+            b.append(kHexChars.charAt(hex & 0x0f));
+         }
+         if (!sDescCaching)
+         {
+            return b.toString();
+         }
+         mDesc = b.toString();
+      }
+      return mDesc;
+   }
+
+   /**
+    * Checking equality of UUIDs is easy; just compare the 128-bit number.
+    */
+   public boolean equals(Object o)
+   {
+      if (!(o instanceof UUID))
+      {
+         return false;
+      }
+      byte[] otherId = ((UUID) o).mId;
+      byte[] thisId = mId;
+      for (int i = 0; i < 16; ++i)
+      {
+         if (otherId[i] != thisId[i])
+         {
+            return false;
+         }
+      }
+      return true;
+   }
+}

Added: trunk/src/main/org/jboss/messaging/util/UUIDGenerator.java
===================================================================
--- trunk/src/main/org/jboss/messaging/util/UUIDGenerator.java	                        (rev 0)
+++ trunk/src/main/org/jboss/messaging/util/UUIDGenerator.java	2008-05-15 14:25:42 UTC (rev 4206)
@@ -0,0 +1,97 @@
+/* JUG Java Uuid Generator
+ *
+ * Copyright (c) 2002- Tatu Saloranta, tatu.saloranta at iki.fi
+ *
+ * Licensed under the License specified in the file LICENSE which is
+ * included with the source code.
+ * You may not use this file except in compliance with the License.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.messaging.util;
+
+import java.net.InetAddress;
+import java.security.SecureRandom;
+import java.util.Random;
+
+public final class UUIDGenerator
+{
+   private final static UUIDGenerator sSingleton = new UUIDGenerator();
+
+   /**
+    * Random-generator, used by various UUID-generation methods:
+    */
+   private Random mRnd = null;
+
+   private final Object mTimerLock = new Object();
+   private UUIDTimer mTimer = null;
+
+   /**
+    * Constructor is private to enforce singleton access.
+    */
+   private UUIDGenerator()
+   {
+   }
+
+   /**
+    * Method used for accessing the singleton generator instance.
+    */
+   public static UUIDGenerator getInstance()
+   {
+      return sSingleton;
+   }
+
+   /*
+    * ///////////////////////////////////////////////////// // Configuration
+    * /////////////////////////////////////////////////////
+    */
+
+   /**
+    * Method for getting the shared random number generator used for generating
+    * the UUIDs. This way the initialization cost is only taken once; access
+    * need not be synchronized (or in cases where it has to, SecureRandom takes
+    * care of it); it might even be good for getting really 'random' stuff to
+    * get shared access...
+    */
+   public Random getRandomNumberGenerator()
+   {
+      /*
+       * Could be synchronized, but since side effects are trivial (ie.
+       * possibility of generating more than one SecureRandom, of which all but
+       * one are dumped) let's not add synchronization overhead:
+       */
+      if (mRnd == null)
+      {
+         mRnd = new SecureRandom();
+      }
+      return mRnd;
+   }
+
+   public UUID generateTimeBasedUUID(InetAddress addr)
+   {
+      byte[] contents = new byte[16];
+      byte[] byteAddr = addr.getAddress();
+      int pos = 12;
+      for (int i = 0; i < 4; ++i)
+      {
+         contents[pos + i] = byteAddr[i];
+      }
+
+      synchronized (mTimerLock)
+      {
+         if (mTimer == null)
+         {
+            mTimer = new UUIDTimer(getRandomNumberGenerator());
+         }
+
+         mTimer.getTimestamp(contents);
+      }
+
+      return new UUID(UUID.TYPE_TIME_BASED, contents);
+   }
+}

Added: trunk/src/main/org/jboss/messaging/util/UUIDTimer.java
===================================================================
--- trunk/src/main/org/jboss/messaging/util/UUIDTimer.java	                        (rev 0)
+++ trunk/src/main/org/jboss/messaging/util/UUIDTimer.java	2008-05-15 14:25:42 UTC (rev 4206)
@@ -0,0 +1,317 @@
+/* JUG Java Uuid Generator
+ *
+ * Copyright (c) 2002- Tatu Saloranta, tatu.saloranta at iki.fi
+ *
+ * Licensed under the License specified in the file LICENSE which is
+ * included with the source code.
+ * You may not use this file except in compliance with the License.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jboss.messaging.util;
+
+import java.util.Random;
+
+/**
+ * UUIDTimer produces the time stamps required for time-based UUIDs. It works as
+ * outlined in the UUID specification, with following implementation:
+ * <ul>
+ * <li>Java classes can only product time stamps with maximum resolution of one
+ * millisecond (at least before JDK 1.5). To compensate, an additional counter
+ * is used, so that more than one UUID can be generated between java clock
+ * updates. Counter may be used to generate up to 10000 UUIDs for each distrinct
+ * java clock value.
+ * <li>Due to even lower clock resolution on some platforms (older Windows
+ * versions use 55 msec resolution), timestamp value can also advanced ahead of
+ * physical value within limits (by default, up 100 millisecond ahead of
+ * reported), iff necessary (ie. 10000 instances created before clock time
+ * advances).
+ * <li>As an additional precaution, counter is initialized not to 0 but to a
+ * random 8-bit number, and each time clock changes, lowest 8-bits of counter
+ * are preserved. The purpose it to make likelyhood of multi-JVM multi-instance
+ * generators to collide, without significantly reducing max. UUID generation
+ * speed. Note though that using more than one generator (from separate JVMs) is
+ * strongly discouraged, so hopefully this enhancement isn't needed. This 8-bit
+ * offset has to be reduced from total max. UUID count to preserve ordering
+ * property of UUIDs (ie. one can see which UUID was generated first for given
+ * UUID generator); the resulting 9500 UUIDs isn't much different from the
+ * optimal choice.
+ * <li>Finally, as of version 2.0 and onwards, optional external timestamp
+ * synchronization can be done. This is done similar to the way UUID
+ * specification suggests; except that since there is no way to lock the whole
+ * system, file-based locking is used. This works between multiple JVMs and Jug
+ * instances.
+ * </ul>
+ * <p>
+ * Some additional assumptions about calculating the timestamp:
+ * <ul>
+ * <li>System.currentTimeMillis() is assumed to give time offset in UTC, or at
+ * least close enough thing to get correct timestamps. The alternate route would
+ * have to go through calendar object, use TimeZone offset to get to UTC, and
+ * then modify. Using currentTimeMillis should be much faster to allow rapid
+ * UUID creation.
+ * <li>Similarly, the constant used for time offset between 1.1.1970 and start
+ * of Gregorian calendar is assumed to be correct (which seems to be the case
+ * when testing with Java calendars).
+ * </ul>
+ * <p>
+ * Note about synchronization: this class is assumed to always be called from a
+ * synchronized context (caller locks on either this object, or a similar timer
+ * lock), and so has no method synchronization.
+ */
+public class UUIDTimer
+{
+   // // // Constants
+
+   /**
+    * Since System.longTimeMillis() returns time from january 1st 1970, and
+    * UUIDs need time from the beginning of gregorian calendar (15-oct-1582),
+    * need to apply the offset:
+    */
+   private final static long kClockOffset = 0x01b21dd213814000L;
+   /**
+    * Also, instead of getting time in units of 100nsecs, we get something with
+    * max resolution of 1 msec... and need the multiplier as well
+    */
+   private final static long kClockMultiplier = 10000;
+   private final static long kClockMultiplierL = 10000L;
+
+   /**
+    * Let's allow "virtual" system time to advance at most 100 milliseconds
+    * beyond actual physical system time, before adding delays.
+    */
+   private final static long kMaxClockAdvance = 100L;
+
+   // // // Configuration
+
+   private final Random mRnd;
+
+   // // // Clock state:
+
+   /**
+    * Additional state information used to protect against anomalous cases
+    * (clock time going backwards, node id getting mixed up). Third byte is
+    * actually used for seeding counter on counter overflow.
+    */
+   private final byte[] mClockSequence = new byte[3];
+
+   /**
+    * Last physical timestamp value <code>System.currentTimeMillis()</code>
+    * returned: used to catch (and report) cases where system clock goes
+    * backwards. Is also used to limit "drifting", that is, amount timestamps
+    * used can differ from the system time value. This value is not guaranteed
+    * to be monotonically increasing.
+    */
+   private long mLastSystemTimestamp = 0L;
+
+   /**
+    * Timestamp value last used for generating a UUID (along with
+    * {@link #mClockCounter}. Usually the same as {@link #mLastSystemTimestamp},
+    * but not always (system clock moved backwards). Note that this value is
+    * guaranteed to be monotonically increasing; that is, at given absolute time
+    * points t1 and t2 (where t2 is after t1), t1 <= t2 will always hold true.
+    */
+   private long mLastUsedTimestamp = 0L;
+
+   /**
+    * Counter used to compensate inadequate resolution of JDK system timer.
+    */
+   private int mClockCounter = 0;
+
+   UUIDTimer(Random rnd)
+   {
+      mRnd = rnd;
+      initCounters(rnd);
+      mLastSystemTimestamp = 0L;
+      // This may get overwritten by the synchronizer
+      mLastUsedTimestamp = 0L;
+   }
+
+   private void initCounters(Random rnd)
+   {
+      /*
+       * Let's generate the clock sequence field now; as with counter, this
+       * reduces likelihood of collisions (as explained in UUID specs)
+       */
+      rnd.nextBytes(mClockSequence);
+      /*
+       * Ok, let's also initialize the counter... Counter is used to make it
+       * slightly less likely that two instances of UUIDGenerator (from separate
+       * JVMs as no more than one can be created in one JVM) would produce
+       * colliding time-based UUIDs. The practice of using multiple generators,
+       * is strongly discouraged, of course, but just in case...
+       */
+      mClockCounter = mClockSequence[2] & 0xFF;
+   }
+
+   public void getTimestamp(byte[] uuidData)
+   {
+      // First the clock sequence:
+      uuidData[UUID.INDEX_CLOCK_SEQUENCE] = mClockSequence[0];
+      uuidData[UUID.INDEX_CLOCK_SEQUENCE + 1] = mClockSequence[1];
+
+      long systime = System.currentTimeMillis();
+
+      /*
+       * Let's first verify that the system time is not going backwards;
+       * independent of whether we can use it:
+       */
+      if (systime < mLastSystemTimestamp)
+      {
+         // Logger.logWarning("System time going backwards! (got value
+         // "+systime+", last "+mLastSystemTimestamp);
+         // Let's write it down, still
+         mLastSystemTimestamp = systime;
+      }
+
+      /*
+       * But even without it going backwards, it may be less than the last one
+       * used (when generating UUIDs fast with coarse clock resolution; or if
+       * clock has gone backwards over reboot etc).
+       */
+      if (systime <= mLastUsedTimestamp)
+      {
+         /*
+          * Can we just use the last time stamp (ok if the counter hasn't hit
+          * max yet)
+          */
+         if (mClockCounter < kClockMultiplier)
+         { // yup, still have room
+            systime = mLastUsedTimestamp;
+         } else
+         { // nope, have to roll over to next value and maybe wait
+            long actDiff = mLastUsedTimestamp - systime;
+            long origTime = systime;
+            systime = mLastUsedTimestamp + 1L;
+
+            // Logger.logWarning("Timestamp over-run: need to reinitialize
+            // random sequence");
+
+            /*
+             * Clock counter is now at exactly the multiplier; no use just
+             * anding its value. So, we better get some random numbers
+             * instead...
+             */
+            initCounters(mRnd);
+
+            /*
+             * But do we also need to slow down? (to try to keep virtual time
+             * close to physical time; ie. either catch up when system clock has
+             * been moved backwards, or when coarse clock resolution has forced
+             * us to advance virtual timer too far)
+             */
+            if (actDiff >= kMaxClockAdvance)
+            {
+               slowDown(origTime, actDiff);
+            }
+         }
+      } else
+      {
+         /*
+          * Clock has advanced normally; just need to make sure counter is reset
+          * to a low value (need not be 0; good to leave a small residual to
+          * further decrease collisions)
+          */
+         mClockCounter &= 0xFF;
+      }
+
+      mLastUsedTimestamp = systime;
+
+      /*
+       * Now, let's translate the timestamp to one UUID needs, 100ns unit offset
+       * from the beginning of Gregorian calendar...
+       */
+      systime *= kClockMultiplierL;
+      systime += kClockOffset;
+
+      // Plus add the clock counter:
+      systime += mClockCounter;
+      // and then increase
+      ++mClockCounter;
+
+      /*
+       * Time fields are nicely split across the UUID, so can't just linearly
+       * dump the stamp:
+       */
+      int clockHi = (int) (systime >>> 32);
+      int clockLo = (int) systime;
+
+      uuidData[UUID.INDEX_CLOCK_HI] = (byte) (clockHi >>> 24);
+      uuidData[UUID.INDEX_CLOCK_HI + 1] = (byte) (clockHi >>> 16);
+      uuidData[UUID.INDEX_CLOCK_MID] = (byte) (clockHi >>> 8);
+      uuidData[UUID.INDEX_CLOCK_MID + 1] = (byte) clockHi;
+
+      uuidData[UUID.INDEX_CLOCK_LO] = (byte) (clockLo >>> 24);
+      uuidData[UUID.INDEX_CLOCK_LO + 1] = (byte) (clockLo >>> 16);
+      uuidData[UUID.INDEX_CLOCK_LO + 2] = (byte) (clockLo >>> 8);
+      uuidData[UUID.INDEX_CLOCK_LO + 3] = (byte) clockLo;
+   }
+
+   /*
+    * /////////////////////////////////////////////////////////// // Private
+    * methods ///////////////////////////////////////////////////////////
+    */
+
+   private final static int MAX_WAIT_COUNT = 50;
+
+   /**
+    * Simple utility method to use to wait for couple of milliseconds, to let
+    * system clock hopefully advance closer to the virtual timestamps used.
+    * Delay is kept to just a millisecond or two, to prevent excessive blocking;
+    * but that should be enough to eventually synchronize physical clock with
+    * virtual clock values used for UUIDs.
+    * 
+    * @param msecs
+    *           Number of milliseconds to wait for from current time point
+    */
+   private final static void slowDown(long startTime, long actDiff)
+   {
+      /*
+       * First, let's determine how long we'd like to wait. This is based on how
+       * far ahead are we as of now.
+       */
+      long ratio = actDiff / kMaxClockAdvance;
+      long delay;
+
+      if (ratio < 2L)
+      { // 200 msecs or less
+         delay = 1L;
+      } else if (ratio < 10L)
+      { // 1 second or less
+         delay = 2L;
+      } else if (ratio < 600L)
+      { // 1 minute or less
+         delay = 3L;
+      } else
+      {
+         delay = 5L;
+      }
+      // Logger.logWarning("Need to wait for "+delay+" milliseconds; virtual
+      // clock advanced too far in the future");
+      long waitUntil = startTime + delay;
+      int counter = 0;
+      do
+      {
+         try
+         {
+            Thread.sleep(delay);
+         } catch (InterruptedException ie)
+         {
+         }
+         delay = 1L;
+         /*
+          * This is just a sanity check: don't want an "infinite" loop if clock
+          * happened to be moved backwards by, say, an hour...
+          */
+         if (++counter > MAX_WAIT_COUNT)
+         {
+            break;
+         }
+      } while (System.currentTimeMillis() < waitUntil);
+   }
+}




More information about the jboss-cvs-commits mailing list