From 20ab5dc6a45e1c57b60936ea1d26f9c72d22ade9 Mon Sep 17 00:00:00 2001 From: Bruce Marriner Date: Wed, 10 Apr 2019 01:33:37 +0000 Subject: [PATCH] Deprecate several global variables This allows better data race protection and makes it more possible to have multi nodes running on the same program with different options. A temp global mutex was added to protect data races caused by NewNode until the deprecated variables are removed. fixed #15 --- snowflake.go | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/snowflake.go b/snowflake.go index 0462cd7..a5952a9 100644 --- a/snowflake.go +++ b/snowflake.go @@ -24,6 +24,8 @@ var ( // Remember, you have a total 22 bits to share between Node/Step StepBits uint8 = 12 + // DEPRECATED: the below four variables will be removed in a future release. + mu sync.Mutex nodeMax int64 = -1 ^ (-1 << NodeBits) nodeMask = nodeMax << StepBits stepMask int64 = -1 ^ (-1 << StepBits) @@ -79,6 +81,12 @@ type Node struct { time int64 node int64 step int64 + + nodeMax int64 + nodeMask int64 + stepMask int64 + timeShift uint8 + nodeShift uint8 } // An ID is a custom type used for a snowflake ID. This is used so we can @@ -90,21 +98,28 @@ type ID int64 func NewNode(node int64) (*Node, error) { // re-calc in case custom NodeBits or StepBits were set + // DEPRECATED: the below block will be removed in a future release. + mu.Lock() nodeMax = -1 ^ (-1 << NodeBits) nodeMask = nodeMax << StepBits stepMask = -1 ^ (-1 << StepBits) timeShift = NodeBits + StepBits nodeShift = StepBits + mu.Unlock() - if node < 0 || node > nodeMax { - return nil, errors.New("Node number must be between 0 and " + strconv.FormatInt(nodeMax, 10)) + n := Node{} + n.node = node + n.nodeMax = -1 ^ (-1 << NodeBits) + n.nodeMask = n.nodeMax << StepBits + n.stepMask = -1 ^ (-1 << StepBits) + n.timeShift = NodeBits + StepBits + n.nodeShift = StepBits + + if n.node < 0 || n.node > n.nodeMax { + return nil, errors.New("Node number must be between 0 and " + strconv.FormatInt(n.nodeMax, 10)) } - return &Node{ - time: 0, - node: node, - step: 0, - }, nil + return &n, nil } // Generate creates and returns a unique snowflake ID @@ -115,7 +130,7 @@ func (n *Node) Generate() ID { now := time.Now().UnixNano() / 1000000 if n.time == now { - n.step = (n.step + 1) & stepMask + n.step = (n.step + 1) & n.stepMask if n.step == 0 { for now <= n.time { @@ -128,8 +143,8 @@ func (n *Node) Generate() ID { n.time = now - r := ID((now-Epoch)<> timeShift) + Epoch } // Node returns an int64 of the snowflake ID node number +// DEPRECATED: the below function will be removed in a future release. func (f ID) Node() int64 { return int64(f) & nodeMask >> nodeShift } // Step returns an int64 of the snowflake step (or sequence) number +// DEPRECATED: the below function will be removed in a future release. func (f ID) Step() int64 { return int64(f) & stepMask }