github.com/benz9527/xboot@v0.0.0-20240504061247-c23f15593274/lib/id/snowflake_id.go (about)

     1  package id
     2  
     3  import (
     4  	"strconv"
     5  	"sync"
     6  	"time"
     7  
     8  	"github.com/benz9527/xboot/lib/infra"
     9  )
    10  
    11  // SnowFlake 64 bits
    12  // 0-00000000_00000000_00000000_00000000_00000000_0-00000_00000-00000000_0000
    13  // 1 bit, as symbol, it always set as 0
    14  // 41 bits, the diff val between current ts and start ts
    15  // The timestamp in high bits will be affected by clock skew (clock rollback).
    16  // 5 bits, as datacenter id
    17  // 5 bits, as machine id
    18  // 12 bits, as internal sequence number, max value is 4096 (2 ^ 12)
    19  
    20  const (
    21  	classicSnowflakeStartEpoch      = int64(946659661000) // 2001-01-01 01:01:01 UTC+8
    22  	classicSnowflakeTsDiffBits      = uint(41)
    23  	classicSnowflakeDIDBits         = uint(5) // DataCenter ID
    24  	classicSnowflakeMIDBits         = uint(5) // Machine ID
    25  	classicSnowflakeSequenceBits    = uint(12)
    26  	classicSnowflakeMIDShiftLeft    = classicSnowflakeSequenceBits
    27  	classicSnowflakeDIDShiftLeft    = classicSnowflakeMIDShiftLeft + classicSnowflakeMIDBits
    28  	classicSnowflakeTsDiffShiftLeft = classicSnowflakeDIDShiftLeft + classicSnowflakeDIDBits // 22 bits
    29  	classicSnowflakeSequenceMax     = int64(-1 ^ (-1 << classicSnowflakeSequenceBits))
    30  	classicSnowflakeMIDMax          = int64(-1 ^ (-1 << classicSnowflakeMIDBits))
    31  	classicSnowflakeDIDMax          = classicSnowflakeMIDMax
    32  	classicSnowflakeTsDiffMax       = int64(-1 ^ (-1 << classicSnowflakeTsDiffBits))
    33  )
    34  
    35  type sfError string
    36  
    37  func (e sfError) Error() string { return string(e) }
    38  
    39  const (
    40  	errSFInvalidDataCenterID = sfError("[snowflake-id] data-center id invalid")
    41  	errSFInvalidMachineID    = sfError("[snowflake-id] machine id invalid")
    42  )
    43  
    44  // The now function is easily to be affected by clock skew. Then
    45  // the global and unique id is unstable.
    46  // Deprecated: Please use the SnowFlakeID(datacenterID, machineID int64, now func() time.Time) (UUIDGen, error)
    47  func StandardSnowFlakeID(dataCenterID, machineID int64, now func() time.Time) (Gen, error) {
    48  	if dataCenterID < 0 || dataCenterID > classicSnowflakeDIDMax {
    49  		return nil, infra.WrapErrorStackWithMessage(errSFInvalidDataCenterID, "dataCenterID: "+strconv.FormatInt(dataCenterID, 10)+
    50  			" (max: "+strconv.FormatInt(classicSnowflakeDIDMax, 10)+")")
    51  	}
    52  
    53  	if machineID < 0 || machineID > classicSnowflakeMIDMax {
    54  		return nil, infra.WrapErrorStackWithMessage(errSFInvalidMachineID, "machineID: "+strconv.FormatInt(machineID, 10)+
    55  			" (max: "+strconv.FormatInt(classicSnowflakeMIDMax, 10)+")")
    56  	}
    57  
    58  	var lock = sync.Mutex{}
    59  	lastTs, sequence := int64(0), int64(0)
    60  	return func() uint64 {
    61  		lock.Lock()
    62  		defer lock.Unlock()
    63  
    64  		now := now().UnixNano() / 1e6
    65  		if now != lastTs {
    66  			sequence = int64(0)
    67  		} else {
    68  			sequence = (sequence + 1) & classicSnowflakeSequenceMax
    69  			if sequence == 0 {
    70  				for now <= lastTs {
    71  					now = time.Now().UnixNano() / 1e6
    72  				}
    73  			}
    74  		}
    75  
    76  		diff := now - classicSnowflakeStartEpoch
    77  		if diff > classicSnowflakeTsDiffMax {
    78  			return 0
    79  		}
    80  		lastTs = now
    81  		id := (diff << classicSnowflakeTsDiffShiftLeft) |
    82  			(dataCenterID << classicSnowflakeDIDShiftLeft) |
    83  			(machineID << classicSnowflakeMIDShiftLeft) |
    84  			sequence
    85  		return uint64(id)
    86  	}, nil
    87  }
    88  
    89  func SnowFlakeID(dataCenterID, machineID int64, now func() time.Time) (UUIDGen, error) {
    90  	if dataCenterID < 0 || dataCenterID > classicSnowflakeDIDMax {
    91  		return nil, infra.WrapErrorStack(errSFInvalidDataCenterID)
    92  	}
    93  
    94  	if machineID < 0 || machineID > classicSnowflakeMIDMax {
    95  		return nil, infra.WrapErrorStack(errSFInvalidMachineID)
    96  	}
    97  
    98  	var lock = sync.Mutex{}
    99  	lastTs, sequence := int64(0), int64(0)
   100  	id := new(uuidDelegator)
   101  	id.number = func() uint64 {
   102  		lock.Lock()
   103  		defer lock.Unlock()
   104  
   105  		now := now().UnixNano() / 1e6
   106  		if now != lastTs {
   107  			sequence = int64(0)
   108  		} else {
   109  			sequence = (sequence + 1) & classicSnowflakeSequenceMax
   110  			if sequence == 0 {
   111  				for now <= lastTs {
   112  					now = time.Now().UnixNano() / 1e6
   113  				}
   114  			}
   115  		}
   116  
   117  		diff := now - classicSnowflakeStartEpoch
   118  		if diff > classicSnowflakeTsDiffMax {
   119  			return 0
   120  		}
   121  		lastTs = now
   122  		id := (diff << classicSnowflakeTsDiffShiftLeft) |
   123  			(dataCenterID << classicSnowflakeDIDShiftLeft) |
   124  			(machineID << classicSnowflakeMIDShiftLeft) |
   125  			sequence
   126  		return uint64(id)
   127  	}
   128  	id.str = func() string {
   129  		return strconv.FormatUint(id.number(), 10)
   130  	}
   131  	return id, nil
   132  }