/** * An object that generates IDs. * This is broken into a separate class in case * we ever want to support multiple worker threads * per process */ classIdWorker( val workerId: Long, val datacenterId: Long, private val reporter: Reporter, var sequence: Long = 0L) extendsSnowflake.Iface{ private[this] defgenCounter(agent: String) = { Stats.incr("ids_generated") Stats.incr("ids_generated_%s".format(agent)) } private[this] val exceptionCounter = Stats.getCounter("exceptions") private[this] val log = Logger.get private[this] val rand = newRandom
val twepoch = 1288834974657L
private[this] val workerIdBits = 5L private[this] val datacenterIdBits = 5L private[this] val maxWorkerId = -1L ^ (-1L << workerIdBits) private[this] val maxDatacenterId = -1L ^ (-1L << datacenterIdBits) private[this] val sequenceBits = 12L
private[this] val workerIdShift = sequenceBits private[this] val datacenterIdShift = sequenceBits + workerIdBits private[this] val timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits private[this] val sequenceMask = -1L ^ (-1L << sequenceBits)
private[this] var lastTimestamp = -1L
// sanity check for workerId if (workerId > maxWorkerId || workerId < 0) { exceptionCounter.incr(1) thrownewIllegalArgumentException("worker Id can't be greater than %d or less than 0".format(maxWorkerId)) }
if (datacenterId > maxDatacenterId || datacenterId < 0) { exceptionCounter.incr(1) thrownewIllegalArgumentException("datacenter Id can't be greater than %d or less than 0".format(maxDatacenterId)) }
log.info("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId)
defget_id(useragent: String): Long = { if (!validUseragent(useragent)) { exceptionCounter.incr(1) thrownewInvalidUserAgentError }
val id = nextId() genCounter(useragent)
reporter.report(newAuditLogEntry(id, useragent, rand.nextLong)) id }
defget_worker_id(): Long = workerId defget_datacenter_id(): Long = datacenterId defget_timestamp() = System.currentTimeMillis
protected[snowflake] defnextId(): Long = synchronized { var timestamp = timeGen()
if (timestamp < lastTimestamp) { exceptionCounter.incr(1) log.error("clock is moving backwards. Rejecting requests until %d.", lastTimestamp); thrownewInvalidSystemClock("Clock moved backwards. Refusing to generate id for %d milliseconds".format( lastTimestamp - timestamp)) }
publicIdWorker(long workerId, long datacenterId, long sequence){ // sanity check for workerId if (workerId > maxWorkerId || workerId < 0) { thrownewIllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0",maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { thrownewIllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0",maxDatacenterId)); } System.out.printf("worker starting. timestamp left shift %d, datacenter id bits %d, worker id bits %d, sequence bits %d, workerid %d", timestampLeftShift, datacenterIdBits, workerIdBits, sequenceBits, workerId);
if (timestamp < lastTimestamp) { System.err.printf("clock is moving backwards. Rejecting requests until %d.", lastTimestamp); thrownewRuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); }