Documentation
¶
Overview ¶
Package snowflake implements a lock-free Snowflake ID generator alongside encoding and decoding helpers.
Index ¶
- Variables
- func AssertEqual[T any](t testing.TB, got, want T)
- func AssertError(t testing.TB, err error)
- func AssertNoError(t testing.TB, err error)
- type AtomicResolver
- type ClockBackwardError
- type Generator
- type IDConstructor
- type Opt
- type OptEpoch
- type OptNodeBits
- type OptStepBits
- type Options
- type SID
- func ParseBase16(code string) (SID, error)
- func ParseBase16Bytes(buf []byte) (SID, error)
- func ParseBase32(code string) (SID, error)
- func ParseBase32Bytes(buf []byte) (SID, error)
- func ParseBase36(code string) (SID, error)
- func ParseBase36Bytes(buf []byte) (SID, error)
- func ParseBase58(code string) (SID, error)
- func ParseBase58Bytes(buf []byte) (SID, error)
- func ParseBase62(code string) (SID, error)
- func ParseBase62Bytes(buf []byte) (SID, error)
- func ParseBase64(code string) (SID, error)
- func ParseBase64Bytes(buf []byte) (SID, error)
- type SIDConstructor
- type StepResolver
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrNegativeMillisecond = errors.New("millisecond must be >= 0")
ErrNegativeMillisecond is returned if GetNextStep is asked to operate on a negative millisecond offset.
Functions ¶
func AssertEqual ¶
AssertEqual use deep reflect to
Types ¶
type AtomicResolver ¶
type AtomicResolver struct {
// contains filtered or unexported fields
}
AtomicResolver implements StepResolver without locks by packing the current millisecond together with the number of issued sequence values into a single atomic word.
The resolver keeps track of the amount of IDs that have already been emitted in the currently observed millisecond. When the counter reaches the capacity (maxStep + 1), the caller must wait until the clock advances.
func NewAtomicResolver ¶
func NewAtomicResolver(maxStep int64) (*AtomicResolver, error)
NewAtomicResolver builds an AtomicResolver that can serve up to maxStep+1 unique sequence numbers per millisecond.
maxStep must be >= 0. A maxStep of 0 means only a single ID can be emitted within the same millisecond.
func (*AtomicResolver) GetNextStep ¶
func (r *AtomicResolver) GetNextStep(ms int64) (int64, bool, error)
GetNextStep implements StepResolver. Counter start at sequence 0
It returns:
- The sequence number for the requested millisecond.
- A boolean signalling whether the caller should retry in a newer millisecond (true if the capacity has been exhausted or the clock moved backwards).
- An error (non-nil only for invalid input or when the clock regressed).
type ClockBackwardError ¶
type ClockBackwardError struct {
LastMs int64
}
ClockBackwardError is returned when a caller observes a millisecond earlier than the last one the resolver has already seen. The caller should wait until the clock catches up to LastMs (inclusive) before retrying.
func (*ClockBackwardError) Error ¶
func (e *ClockBackwardError) Error() string
Error implements the error interface.
type Generator ¶
type Generator struct {
Constructor SIDConstructor
Resolver StepResolver
Epoch time.Time
}
Generator produces Snowflake IDs with millisecond resolution.
The generator is safe for concurrent use.
Example (ConfigurableEpoch) ¶
package main
import (
"fmt"
"log"
"time"
"github.com/TinyMurky/snowflake"
)
func main() {
epoch := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
gen, err := snowflake.NewGenerator(
snowflake.WithNodeBits(8),
snowflake.WithStepBits(14),
snowflake.WithEpoch(epoch),
)
if err != nil {
log.Fatal(err)
}
id, err := gen.NextID(25)
if err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d (base36: %s)\n", id, id.Base36())
}
func NewGenerator ¶
NewGenerator creates a generator using configurable options. By default it allocates 10 bits for the node identifier, 12 bits for the per-millisecond sequence counter and uses the original Twitter epoch (2010-11-04 UTC).
type IDConstructor ¶
type IDConstructor struct {
// contains filtered or unexported fields
}
IDConstructor construct timestamp, node_id, step_cnt into snowflakeID
func NewDefaultIDConstructor ¶
func NewDefaultIDConstructor() (*IDConstructor, error)
NewDefaultIDConstructor will return a constructor wil format as:
- 41 bits timestamp
- 10 bits node_id
- 12 bits step_cnt
func NewIDConstructor ¶
func NewIDConstructor(nodeBits, stepBits uint8) (*IDConstructor, error)
NewIDConstructor will return a constructor wil format as:
- 41 bits timestamp
- nodeBits of node_id
- stepBits step_cnt
nodeBits and stepBits share 22 bits
func (*IDConstructor) GenID ¶
func (c *IDConstructor) GenID(timestamp, nodeID, stepCnt int64) (SID, error)
GenID construct timestamp, node_id, step_cnt into snowflake ID
func (*IDConstructor) GetMaxStep ¶
func (c *IDConstructor) GetMaxStep() int64
GetMaxStep return the maximum stepCnt allow in a millisecond
type Opt ¶
type Opt interface {
Apply(*Options)
}
Opt is a functional option that mutates Options at construction time.
Typical usage:
NewGenerator(WithNodeBits(10), WithStepBits(12), WithEpoch(t))
type OptEpoch ¶
OptEpoch is the functional option type for configuring the custom epoch.
type OptNodeBits ¶
type OptNodeBits uint8
OptNodeBits is the functional option type for configuring nodeBits.
func WithNodeBits ¶
func WithNodeBits(nodeBits uint8) OptNodeBits
WithNodeBits returns an option that sets the number of bits reserved for the node ID.
nodeBits should be chosen so that nodeBits + stepBits (+ timestamp bits in your layout) fits within your target word size (commonly 63 bits for signed 64-bit integers).
func (OptNodeBits) Apply ¶
func (o OptNodeBits) Apply(opt *Options)
Apply sets the nodeBits on the provided Options.
Example: WithNodeBits(10) allows up to 1024 distinct nodes.
type OptStepBits ¶
type OptStepBits uint8
OptStepBits is the functional option type for configuring stepBits.
func WithStepBits ¶
func WithStepBits(stepBits uint8) OptStepBits
WithStepBits returns an option that sets the number of bits for the per-tick sequence.
Pick a value large enough for your expected peak allocation rate per tick.
func (OptStepBits) Apply ¶
func (o OptStepBits) Apply(opt *Options)
Apply sets the stepBits on the provided Options.
Example: WithStepBits(12) allows up to 4096 IDs per tick (e.g., per millisecond).
type Options ¶
type Options struct {
// contains filtered or unexported fields
}
Options holds internal configuration used when creating a generator.
- nodeBits: number of bits allocated to the node ID. Max nodes = 2^nodeBits.
- stepBits: number of bits allocated to the per-tick sequence counter. Max sequence per tick = 2^stepBits - 1.
- epoch: custom epoch (time origin) used to shrink the timestamp range.
Note: fields are unexported on purpose. Use Opt implementations (With*) to configure these values from outside the package.
type SID ¶
type SID int64
SID represents a Snowflake identifier as a positive 64-bit integer.
Example (Encoding) ¶
package main
import (
"fmt"
"log"
"github.com/TinyMurky/snowflake"
)
func main() {
constructor, err := snowflake.NewIDConstructor(10, 12)
if err != nil {
log.Fatal(err)
}
id, err := constructor.GenID(1_234_567, 42, 7)
if err != nil {
log.Fatal(err)
}
fmt.Println("raw:", int64(id))
fmt.Println("base58:", id.Base58())
fmt.Println("base62:", id.Base62())
fmt.Println("base36:", id.Base36())
fmt.Println("base32:", id.Base32())
fmt.Println("base16:", id.Base16())
fmt.Println("base64:", id.Base64())
}
Output: raw: 5178149478407 base58: 3M2ELaut base62: 1TABHVOJ base36: 1U2T4I4NB base32: 4PPGW5807 base16: 4B5A1C2A007 base64: BLWhwqAH
func ParseBase16 ¶
ParseBase16 will parse the SnowflakeID (string) that has been encoded by Base16 (hexadecimal) back to SID.
func ParseBase16Bytes ¶
ParseBase16Bytes parses a hexadecimal encoded Snowflake ID.
func ParseBase32 ¶
ParseBase32 will parse the SnowflakeID (string) that has been encoded by Base32 back to SID.
func ParseBase32Bytes ¶
ParseBase32Bytes parses a Crockford Base32 encoded Snowflake ID.
func ParseBase36 ¶
ParseBase36 will parse the SnowflakeID (string) that has been encoded by Base36 back to SID.
func ParseBase36Bytes ¶
ParseBase36Bytes parses a Base36 encoded Snowflake ID.
func ParseBase58 ¶
ParseBase58 will parse the SnowflakeID (string) that has been encoded by Base58 back to SID
func ParseBase58Bytes ¶
ParseBase58Bytes will parse the SnowflakeID ([]byte) that has been encoded by Base58 back to SID
func ParseBase62 ¶
ParseBase62 will parse the SnowflakeID (string) that has been encoded by Base62 back to SID
func ParseBase62Bytes ¶
ParseBase62Bytes will parse the SnowflakeID ([]byte) that has been encoded by Base62 back to SID
func ParseBase64 ¶
ParseBase64 will parse the SnowflakeID (string) that has been encoded by Base64 back to SID. Padding characters (`=`) are ignored.
func ParseBase64Bytes ¶
ParseBase64Bytes parses an unpadded Base64 encoded Snowflake ID.
type SIDConstructor ¶
SIDConstructor formats timestamp, node ID and step counter into a Snowflake ID.
type StepResolver ¶
type StepResolver interface {
// GetNextStep returns:
// 1. The sequence/step counter associated with ms.
// 2. Whether the caller should wait for the next millisecond.
// 3. An error (non-nil on invalid input or when the clock regresses).
GetNextStep(ms int64) (int64, bool, error)
}
StepResolver returns the next step counter for a given millisecond.