修改自Twitter的Snowflake算法

<?php
/**
 * 獲得惟一識別碼
 * 修改自Twitter的Snowflake算法
 * 此算法支持分佈式自增ID
 * @author cwsky@163.com
 */

abstract class Uniq
{
	//初始時間碼,開站設定一次,可用如下語句獲得
	//floor(microtime(true) * 1000);
	private static $twepoch = 1380553425155;

	//數據中心,8表示能夠有255個數據中心,最大取值爲8
	private static $dataCenterIDBits = 8;

	//數據中心ID最大值
	//private static $maxDatacenterID = -1 ^ (-1 << $datacenterIDBits);

	//機器標識符,13表示能夠有8191臺機器,最大取值爲13
	//當dataCenterIDBits與workerIDBits變大時,會產生負數,就很差玩了
	private static $workerIDBits = 13;

	//機器ID最大值
	//private static $maxWorkerId = -1 ^ (-1 << $workerIDBits);

	//毫秒內自增位
	private static $sequenceBits = 12;

	//機器ID偏左移12位
	//private static $workerIDShift = self::$sequenceBits;
	private static $workerIDShift = 12;

	//數據中心ID左移17位
	//private $dataCenterIDShift = $sequenceBits + $workerIDBits;

	//時間毫秒左移22位
	//private $timestampLeftShift = $sequenceBits + $workerIDBits + $datacenterIDBits;
	//private $sequenceMask = -1 ^ (-1 << $sequenceBits);

	private static $lastTimestamp = -1;

	private static $sequence = 0;

	public static function id($dataCenterID, $workerID)
	{
		//數據中心ID最大值
		$maxDataCenterID = -1 ^ (-1 << self::$dataCenterIDBits);

		//機器ID最大值
		$maxWorkerID = -1 ^ (-1 << self::$workerIDBits);

		//數據中心ID左移17位
		$dataCenterIDShift = self::$sequenceBits + self::$workerIDBits;

		//時間毫秒左移22位
		$timestampLeftShift = self::$sequenceBits + self::$workerIDBits + self::$dataCenterIDBits;
		$sequenceMask = -1 ^ (-1 << self::$sequenceBits);

		//檢查workerID完整性
		if($workerID > $maxWorkerID || $workerID < 0)
		{
			return 0;
		}

		//檢查數據中心完整性
		if($dataCenterID > $maxDataCenterID || $dataCenterID < 0)
		{
			return 0;
		}

		//echo sprintf("worker starting. timestamp left shift %d, datacenter id bits %d, maxDatacenterID:%d, worker id bits %d, maxWorkerID:%d, sequence bits %d, workerid %d", $timestampLeftShift, self::$dataCenterIDBits, $maxDataCenterID, self::$workerIDBits, $maxWorkerID, self::$sequenceBits, $workerID);

		$timestamp = self::timeGen();

		if($timestamp < self::$lastTimestamp)
		{
			return 0;
		}

		if (self::$lastTimestamp == $timestamp)
		{
			//當前毫秒內,則+1
			self::$sequence = (self::$sequence + 1) & $sequenceMask;
			if(self::$sequence == 0)
			{
				//當前毫秒內計數滿了,則等待下一秒
				$timestamp = self::tilNextMillis(self::$lastTimestamp);
			}
		}
		else
		{
			self::$sequence = 0;
		}

		self::$lastTimestamp = $timestamp;

		$id = (($timestamp - self::$twepoch << $timestampLeftShift)) | ($dataCenterID << $dataCenterIDShift) | ($workerID << self::$workerIDShift) | (self::$sequence);

		return $id;
	}

	public static function timeGen()
	{
		return floor(microtime(true) * 1000);
	}

	public static function tilNextMillis($lastTimestamp)
	{
		$timestamp = self::timeGen();

		while($timestamp <= $lastTimestamp)
		{
			$timestamp = self::timeGen();
		}

		return $timestamp;
	}

	public static function getUUID()
	{
		return strtoupper(sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
	        // 32 bits for "time_low"
	        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),

	        // 16 bits for "time_mid"
	        mt_rand( 0, 0xffff ),

	        // 16 bits for "time_hi_and_version",
	        // four most significant bits holds version number 4
	        mt_rand( 0, 0x0fff ) | 0x4000,

	        // 16 bits, 8 bits for "clk_seq_hi_res",
	        // 8 bits for "clk_seq_low",
	        // two most significant bits holds zero and one for variant DCE1.1
	        mt_rand( 0, 0x3fff ) | 0x8000,

	        // 48 bits for "node"
	        mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
	    ));
	}
}
?>
相關文章
相關標籤/搜索