/*
* Copyright 2009 Red Hat, Inc.
* Red Hat licenses this file to you under the Apache License, version
* 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* 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.hornetq.tests.unit.util;
import java.util.concurrent.CountDownLatch;
import junit.framework.Assert;
import org.hornetq.tests.util.UnitTestCase;
import org.hornetq.utils.ConcurrentHashSet;
import org.hornetq.utils.TimeAndCounterIDGenerator;
/**
* A TimeAndCounterIDGeneratorTest
*
* @author <a href="mailto:clebert.suconic@jboss.org">Clebert Suconic</a> Created 24-Sep-08 3:42:25 PM
*/
public class TimeAndCounterIDGeneratorTest extends UnitTestCase
{
// Constants -----------------------------------------------------
// Attributes ----------------------------------------------------
// Static --------------------------------------------------------
// Constructors --------------------------------------------------
// Public --------------------------------------------------------
public void testCalculation()
{
TimeAndCounterIDGenerator seq = new TimeAndCounterIDGenerator();
long max = 11000;
long lastNr = 0;
for (long i = 0; i < max; i++)
{
long seqNr = seq.generateID();
Assert.assertTrue("The sequence generator should aways generate crescent numbers", seqNr > lastNr);
lastNr = seqNr;
}
}
public void testCalculationRefresh()
{
TimeAndCounterIDGenerator seq = new TimeAndCounterIDGenerator();
long id1 = seq.generateID();
Assert.assertEquals(1, id1 & 0xffff);
Assert.assertEquals(2, seq.generateID() & 0xffff);
seq.refresh();
long id2 = seq.generateID();
Assert.assertTrue(id2 > id1);
Assert.assertEquals(1, id2 & 0xffff);
}
public void testCalculationOnMultiThread() throws Throwable
{
final ConcurrentHashSet<Long> hashSet = new ConcurrentHashSet<Long>();
final TimeAndCounterIDGenerator seq = new TimeAndCounterIDGenerator();
System.out.println("Time = " + TimeAndCounterIDGeneratorTest.hex(System.currentTimeMillis()) + ", " + seq);
final int NUMBER_OF_THREADS = 100;
final int NUMBER_OF_IDS = 10;
final CountDownLatch latchAlign = new CountDownLatch(NUMBER_OF_THREADS);
final CountDownLatch latchStart = new CountDownLatch(1);
class T1 extends Thread
{
Throwable e;
@Override
public void run()
{
try
{
latchAlign.countDown();
latchStart.await();
long lastValue = 0l;
for (int i = 0; i < NUMBER_OF_IDS; i++)
{
long value = seq.generateID();
Assert.assertTrue(TimeAndCounterIDGeneratorTest.hex(value) + " should be greater than " +
TimeAndCounterIDGeneratorTest.hex(lastValue) +
" on seq " +
seq.toString(), value > lastValue);
lastValue = value;
hashSet.add(value);
}
}
catch (Throwable e)
{
this.e = e;
}
}
};
T1[] arrays = new T1[NUMBER_OF_THREADS];
for (int i = 0; i < arrays.length; i++)
{
arrays[i] = new T1();
arrays[i].start();
}
latchAlign.await();
latchStart.countDown();
for (T1 t : arrays)
{
t.join();
if (t.e != null)
{
throw t.e;
}
}
Assert.assertEquals(NUMBER_OF_THREADS * NUMBER_OF_IDS, hashSet.size());
hashSet.clear();
}
public void testWrapID() throws Throwable
{
final ConcurrentHashSet<Long> hashSet = new org.hornetq.utils.ConcurrentHashSet<Long>();
TimeAndCounterIDGenerator seq = new TimeAndCounterIDGenerator();
System.out.println("Current Time = " + TimeAndCounterIDGeneratorTest.hex(System.currentTimeMillis()) + " " + seq);
seq.setInternalDate(System.currentTimeMillis() + 10000l); // 10 seconds in the future
seq.setInternalID(TimeAndCounterIDGenerator.ID_MASK); // 1 ID about to explode
try
{
// This is simulating a situation where we generated more than 268 million messages on the same time interval
seq.generateID();
Assert.fail("It was supposed to throw an exception, as the counter was set to explode on this test");
}
catch (Exception e)
{
}
seq = new TimeAndCounterIDGenerator();
seq.setInternalDate(System.currentTimeMillis() - 10000l); // 10 seconds in the past
long timeMark = seq.getInternalTimeMark();
seq.setInternalID(TimeAndCounterIDGenerator.ID_MASK); // 1 ID about to explode
// This is ok... the time portion would be added to the next one generated 10 seconds ago
seq.generateID();
Assert.assertTrue(TimeAndCounterIDGeneratorTest.hex(timeMark) + " < " +
TimeAndCounterIDGeneratorTest.hex(seq.getInternalTimeMark()),
timeMark < seq.getInternalTimeMark());
}
private static String hex(final long value)
{
return String.format("%1$X", value);
}
}