All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.l4.commons.id.SequenceLongIdGenerator Maven / Gradle / Ivy

The newest version!
package se.l4.commons.id;

import java.time.Clock;
import java.util.Objects;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import edu.umd.cs.findbugs.annotations.NonNull;

/**
 * {@link LongIdGenerator} that uses the current time and a local sequence
 * to create identifiers. This generator guarantees that identifiers are
 * always increasing, but is not suitable for distributed usage.
 *
 * @author Andreas Holstenson
 *
 */
public class SequenceLongIdGenerator
	implements LongIdGenerator
{
	public static final int MAX_SEQUENCE = (int) Math.pow(2, 21);

	private int sequence;
	private long lastTime;

	private final Clock clock;
	private final Lock lock;

	public SequenceLongIdGenerator()
	{
		this(Clock.systemUTC());
	}

	public SequenceLongIdGenerator(@NonNull Clock clock)
	{
		this(clock, new ReentrantLock());
	}

	public SequenceLongIdGenerator(@NonNull Clock clock, @NonNull Lock lock)
	{
		this.clock = Objects.requireNonNull(clock);
		this.lock = Objects.requireNonNull(lock);
	}

	@Override
	public long next()
	{
		lock.lock();
		try
		{
			long time = clock.millis() - SimpleLongIdGenerator.EPOCH_START;
			if(lastTime > time)
			{
				// Time is moving backwards, refuse to generate anything
				throw new Error("Time on system is moving backwards, please update system configuration");
			}

			if(sequence >= MAX_SEQUENCE)
			{
				// We have reached our maximum number of ids for this ms
				// This is very unlikely so this is pretty untested
				long timeRightNow;
				do
				{
					try
					{
						Thread.sleep(1);
					}
					catch(InterruptedException e)
					{
						Thread.currentThread().interrupt();
						throw new RuntimeException("Interrupted id generation; " + e.getMessage(), e);
					}

					timeRightNow = clock.millis() - SimpleLongIdGenerator.EPOCH_START;
				}
				while(timeRightNow == time);

				time = timeRightNow;
			}

			if(lastTime != time)
			{
				lastTime = time;
				sequence = 0;
			}

			sequence++;

			return (time << 22) | sequence;
		}
		finally
		{
			lock.unlock();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy