gcosid

package module
v0.0.0-...-ccec772 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 14 Imported by: 4

README

English | 简体中文

gcosid

Segment and snowflake ID generation in Go.

Status: experimental scaffold (v0.0.0-dev).

Scope: CosID feature parity

The target is a complete port of CosID's capabilities, not one chosen strategy. Consumers pick a generator; the library never mixes layouts silently.

CosID capability Status
Segment generator: IdSegment{offset,maxId,sequence,step,fetchTime,ttl} arithmetic (CosID 2.15.1) done
Segment chain (SegmentChainId): safe distance 2, hunger-adaptive prefetch done
Double buffering / chain prefetch with bounded timeout done
SegmentAllocator port + in-memory allocator done
DB segment allocator: cosid(name,last_max_id,last_fetch_time) reserve-then-read (MySQL, Postgres) done
Redis segment allocator: INCRBY cosid:{namespace.name}:adder done
Segment TTL / expiry abandonment, step tuning done (TTL) / planned (step)
Snowflake: layout/epoch/sequence + ms, second and JS-safe variants done
Machine-id distribution: manual id, leased slots — in-memory, JDBC cosid_machine, Redis Lua scripts (verbatim 2.15.1) done
Machine-id guard: periodic lease renewal with failure state (MachineIdGuarder) done
Kubernetes StatefulSet distributor (machine id = pod ordinal) done
Storage adapters: MongoDB, ZooKeeper planned (lowest priority)
Clock-moved-backwards policy: strict error or spin/sleep synchroniser done
String converters: radix 2..62, prefix, suffix, date-prefix, grouped, to-string done
Snowflake-friendly rendering <yyyyMMddHHmmss[SSS]>-<machine>-<sequence> done
Integer / string generator views (IntegerIdGenerator, StringIdGenerator) done
jvm.AtomicLongGenerator, jvm.UuidGenerator done
CosID string family (Radix36/62CosIdGenerator, 44/20/16 layout) done
Generator registry (IdGeneratorProvider) and LazyIdGenerator done
Grouped segments: per-year / month / day counters and <group>-<id> rendering done
Sharding: ModCycle, IntervalTimeline (time windows), CachedSharding done
Diagnostics: Statistical stats for generators and converters done
UncertaintyIdGenerator: random low bits on top of an ordered id done
Struct-tag id injection (@CosId + EnsureId equivalent) done
String views: StringSegmentId, StringSnowflakeId (stat keeps the converter) done
Clock-sync decorators for any generator (ClockSyncSnowflakeId / ClockSyncCosIdGenerator) done
Local machine-state cache file (LocalMachineStateStorage) done
Host address supplier + InstanceId.of(host, port) done
Sharding value converters (StandardLocalDateTimeConvertor, SnowflakeLocalDateTimeConvertor) done
CosID golden compatibility vectors (segment bounds, bit layout, strings) planned

Rule that will not change: uniqueness is only promised inside a configured allocation domain. Gaps, restart waste and clock-regression errors are allowed — "looks continuous" is never a reason to weaken uniqueness.

CosID compatibility contract

The baseline is CosID v2.15.1. This library is consumed by deployments where a Java process and a Go process write the same tables and Redis keys, so the following are contracts, not implementation details. Changing any of them silently breaks mixed deployments — both sides believe they own a machine slot that the other also holds.

Storage

  • Segment counter table cosid(name PK, last_max_id, last_fetch_time); name = {namespace}.{name}. Reserved in one transaction: the UPDATE (last_max_id = last_max_id + ?) and the SELECT must not be split into two autocommitted statements, or two callers can read the same upper bound.
  • Machine slots live in cosid_machine, keyed {namespace}.{8-digit padded machine id} — the padding is part of the primary key.
  • The first machine id is 0: max(machine_id)+1 over an empty table is NULL and CosID reads NULL as 0.
  • revert clears instance_id for unstable instances and keeps it for stable ones; guard treats zero affected rows as a lost lease.

Driver

affected rows means matched rows, not changed rows: MySQL Connector/J sets CLIENT_FOUND_ROWS by default, Go drivers do not. Open the pool with database.OpenMySQL (it also enables parseTime); a plain sql.Open("mysql", dsn) makes a heartbeat look like a lost lease.

Redis

cosid:{namespace.name}:adder for segments and cosid:<namespace>:itc_idx / :adder / :revert for machine slots, with values formatted machineId|lastStamp. The braces are a Redis Cluster hash tag, not decoration; the machine scripts are copied verbatim from cosid-spring-redis.

Ids

COSID_EPOCH = 1577203200000; millisecond layout 41/10/12, second 31/10/22, JavaScript-safe 41/3/9 and 31/3/19; string family 44/20/16 rendered as fixed-width radix fields without an epoch offset; friendly rendering yyyyMMddHHmmss[SSS]-machine-sequence.

Testing

Command Covers Requires
go test ./... pure logic: segment arithmetic, snowflake layout, converters, dialect SQL nothing
go test -tags=integration ./... storage behaviour against real MySQL and Redis Docker, or a provided environment

Rule: anything that depends on a database or another middleware is verified by the integration suite. Unit tests never mock SQL — a mock happily accepts a statement that duplicates ids in reality (that is exactly how a missing transaction boundary slipped through once).

Without Docker, point the tests at a provided environment:

GCOSID_TEST_MYSQL_DSN='test:test@tcp(127.0.0.1:3306)/cosid' \
GCOSID_TEST_REDIS_ADDR=127.0.0.1:6379 \
go test -tags=integration ./...

Images default to mysql:8.4.7 and redis:7 and can be mirrored:

GCOSID_MYSQL_IMAGE=registry.example.com/library/mysql:8.4.7 \
GCOSID_REDIS_IMAGE=registry.example.com/library/redis:7 \
go test -tags=integration ./...

Id injection

CosID annotates entity fields with @CosId and lets its Spring/MyBatis/Jackson plugins fill them. Go has neither annotations nor those plugin points, so gcosid uses a struct tag and you call it explicitly:

type Order struct {
    ID     int64  `cosid:"order"`   // generator name
    Amount int64
}
How to wire it
// 1. one generator per entity kind
chain, err := gcosid.NewChainGenerator("order", 100, alloc)
if err != nil {
    return err
}
defer chain.Close(ctx)

// 2. registry: tag name -> generator
injector := gcosid.NewInjector()
injector.Register("order", chain)          // numeric fields
injector.RegisterString("orderNo", orderNo) // string fields

// 3. the repository owns the call site
type OrderRepo struct {
    ids *gcosid.Injector
    db  *sql.DB
}

func (r *OrderRepo) Create(ctx context.Context, order *Order) error {
    if _, err := r.ids.Ensure(ctx, order); err != nil {
        return fmt.Errorf("assign id: %w", err)
    }
    // ... INSERT ...
}

func (r *OrderRepo) CreateBatch(ctx context.Context, orders []*Order) error {
    if _, err := r.ids.EnsureAll(ctx, orders); err != nil {
        return fmt.Errorf("assign ids: %w", err)
    }
    // ... batch INSERT ...
}

A full runnable program is in examples/repository.

There is no automatic fill

Because nothing injects ids behind your back, a write that skips Ensure inserts the zero id. That is the one failure mode to design against:

  • call Ensure in the repository's create path, not in handlers scattered around;
  • Ensure is idempotent — an entity that already has an id is never overwritten, so calling it twice (or in both the service and the repository) is safe;
  • EnsureAll fills a slice in one call and reports how many rows needed an id;
  • a batch insert must call EnsureAll before building the statement, or every row gets id 0 and the primary key collides.
Rules, matching CosIdAccessor
  • the tag value is a generator name; cosid:"-" opts out; cosid:"" means the shared generator (Provider.SetShare);
  • only string and the integer widths can hold ids (String/Long/Integer in CosID); anything else fails at the first Ensure, not at random later;
  • the target must be a non-nil pointer to a struct;
  • embedded structs are searched, so a composite entity can inherit its id;
  • a string field fed by a numeric generator is rendered as decimal (ToStringIdConverter);
  • field plans are cached per reflect.Type, so Ensure does not re-reflect on every call.
Test doubles

NewInjectorFromProvider(provider) reads the registry on every fill, so a test can swap a generator (provider.Set("order", fixed)) without rebuilding the repository.

Layout

The root package is the facade: the constructors (NewSegmentGenerator, NewSnowflake, NewStringCosIDGenerator, ...), the Provider registry and the dependency injection. Two subpackages hold the parts that are shared or independently useful:

Package Holds
core the vocabulary: Generator/NamedGenerator/StringConverter, the segment model and allocator SPI, the radix/prefix/date vocabulary, the snowflake Layout, and the Stat tree
machine machine-id distribution: manual, lease-based and StatefulSet distributors, the guard that renews the lease, and the local state file

Both are re-exported from the root package as aliases, so gcosid.MachineState and machine.MachineState are the same type and existing code keeps working. database/ and redis/ implement the allocator and machine-state SPIs and import machine directly for the interfaces they implement.

Install

go get github.com/maxid/gcosid

License

MIT. See LICENSE.

Documentation

Overview

Package gcosid is part of the gcosid project.

Status: experimental scaffold (v0.0.0-dev). The API is not stable yet.

Index

Constants

View Source
const (
	TTLForever = core.TTLForever

	CosIdEpoch         = core.CosIdEpoch
	CosIdEpochSecond   = core.CosIdEpochSecond
	TotalBit           = core.TotalBit
	JSMaxSafeNumberBit = core.JSMaxSafeNumberBit
	JSMaxSafeNumber    = core.JSMaxSafeNumber

	DefaultHostnameEnv = machine.DefaultHostnameEnv
)
View Source
const (
	CosIDStringTimestampBits = 44
	CosIDStringMachineBits   = 20
	CosIDStringSequenceBits  = 16
)

CosID's string generator family (RadixCosIdGenerator) uses a different layout from the int64 snowflake: 44 timestamp bits + 20 machine bits + 16 sequence bits. The sum exceeds 63 on purpose — the output is a fixed-width string, not a packed int64, and the timestamp is the *raw* epoch millisecond (no epoch offset).

View Source
const DefaultSafeDistance = 2

DefaultSafeDistance is CosID's SegmentChainId.DEFAULT_SAFE_DISTANCE: the chain keeps two segments ready ahead of the cursor.

View Source
const ShareName = "__share__"

ShareName is CosID's IdGeneratorProvider.SHARE: the generator used when a caller does not name one. `@CosId` without a value resolves to it, and every registry operation treats it like any other name.

View Source
const TagKey = "cosid"

TagKey marks a struct field as an id field — the Go equivalent of CosID's `@CosId` annotation:

type Order struct {
    ID   int64  `cosid:"order"`
    Name string
}

The tag value is the generator name in the Injector's registry. `cosid:"-"` opts a field out, and an empty value (`cosid:""`) means the shared generator, which is what CosID's `@CosId` without a value does. String fields accept a StringGenerator; numeric fields accept a Generator.

View Source
const Version = "0.0.0-dev"

Version is the semantic version of this library.

Variables

View Source
var (
	MillisecondLayout       = core.MillisecondLayout
	SecondLayout            = core.SecondLayout
	SafeJSMillisecondLayout = core.SafeJSMillisecondLayout
	SafeJSSecondLayout      = core.SafeJSSecondLayout

	ErrClosed               = core.ErrClosed
	ErrAllocatorUnavailable = core.ErrAllocatorUnavailable
	ErrInvalidConfig        = core.ErrInvalidConfig
	ErrExhausted            = core.ErrExhausted
	ErrClockMovedBackwards  = core.ErrClockMovedBackwards
	ErrInvalidMachineID     = core.ErrInvalidMachineID
	ErrNamespaceConflict    = core.ErrNamespaceConflict
)
View Source
var (
	NewStat  = core.NewStat
	NewRadix = core.NewRadix

	NewInstanceID             = machine.NewInstanceID
	WithGuardTiming           = machine.WithGuardTiming
	WithGuardClock            = machine.WithGuardClock
	NewGuarder                = machine.NewGuarder
	InstanceIDFrom            = machine.InstanceIDFrom
	DefaultStatePath          = machine.DefaultStatePath
	NewLocalStateStorage      = machine.NewLocalStateStorage
	NewMemoryMachineStorage   = machine.NewMemoryMachineStorage
	WithLeaseStable           = machine.WithLeaseStable
	WithLeaseSafeGuard        = machine.WithLeaseSafeGuard
	NewLeaseDistributor       = machine.NewLeaseDistributor
	NewStatefulSetDistributor = machine.NewStatefulSetDistributor
)

Constructors and options keep their names by forwarding to the package that owns them.

View Source
var NeverGrouped = GroupedKey{Key: "", TTLAt: TTLForever}

NeverGrouped is GroupedKey.NEVER: an ungrouped allocation.

Functions

func JoinNodes

func JoinNodes(nodes []string) string

JoinNodes renders a node list for logs and diagnostics.

Types

type AtomicGenerator

type AtomicGenerator struct {
	// contains filtered or unexported fields
}

AtomicGenerator is CosID's jvm.AtomicLongGenerator: a per-process counter. It is only unique inside one process, so it is for caches and tests, never for a persisted primary key.

func NewAtomicGenerator

func NewAtomicGenerator() *AtomicGenerator

NewAtomicGenerator creates a counter starting at zero.

func (*AtomicGenerator) Next

Next implements Generator.

type CachedSharding

type CachedSharding[T any] struct {
	Actual Sharding[T]
	// contains filtered or unexported fields
}

CachedSharding memoises range lookups — CosID's CachedSharding. Precise lookups are cheap enough to pass through.

func NewCachedSharding

func NewCachedSharding[T any](actual Sharding[T]) *CachedSharding[T]

NewCachedSharding wraps a sharding with a range cache.

func (*CachedSharding[T]) EffectiveNodes

func (c *CachedSharding[T]) EffectiveNodes() []string

EffectiveNodes implements Sharding.

func (*CachedSharding[T]) Sharding

func (c *CachedSharding[T]) Sharding(value T) (string, error)

Sharding implements Sharding.

func (*CachedSharding[T]) ShardingRange

func (c *CachedSharding[T]) ShardingRange(lower, upper T, hasLower, hasUpper bool) []string

ShardingRange implements Sharding with memoisation. The key renders the range bounds as strings, which is stable because bounds are compared, never mutated.

type ChainGenerator

type ChainGenerator struct {
	// contains filtered or unexported fields
}

ChainGenerator is CosID's SegmentChainId: a chain of reserved ranges, walked forward as they expire or overflow, with a background prefetcher that keeps `safeDistance` ranges ready.

func NewChainGenerator

func NewChainGenerator(namespace string, step int64, alloc SegmentAllocator, opts ...ChainOption) (*ChainGenerator, error)

NewChainGenerator creates a chain generator and starts the prefetcher.

func (*ChainGenerator) Close

func (g *ChainGenerator) Close(ctx context.Context) error

Close stops the prefetcher. Buffered ranges are dropped: a closed generator never hands out another id.

func (*ChainGenerator) Namespace

func (g *ChainGenerator) Namespace() string

Namespace implements NamedGenerator.

func (*ChainGenerator) Next

func (g *ChainGenerator) Next(ctx context.Context) (int64, error)

Next implements Generator, mirroring SegmentChainId.generate: walk the chain for an available range, and extend it when nothing is left.

func (*ChainGenerator) Stat

func (g *ChainGenerator) Stat() Stat

Stat implements Statistical for a chain generator.

type ChainOption

type ChainOption func(*ChainGenerator)

ChainOption configures a ChainGenerator.

func WithChainClock

func WithChainClock(now func() int64) ChainOption

WithChainClock overrides the clock (tests).

func WithChainTTL

func WithChainTTL(ttl time.Duration) ChainOption

WithChainTTL gives every reserved range a lifetime. Durations shorter than a second round up: a zero TTL would expire each range the moment it is created.

func WithSafeDistance

func WithSafeDistance(n int) ChainOption

WithSafeDistance keeps `n` ranges ready ahead of the cursor.

type ClockSync

type ClockSync interface {
	// Synchronize waits until the clock catches up with lastTimestamp.
	Synchronize(lastTimestamp int64) error
}

CosID 2.15.1 constants (the CosId class, SnowflakeId implementations).

type ClockSyncGenerator

type ClockSyncGenerator struct {
	Actual Generator
	Sync   ClockSync
}

ClockSyncGenerator wraps any generator with a clock-backwards handler — CosID's ClockSyncSnowflakeId / ClockSyncCosIdGenerator. The wrapped generator still owns the layout; this decorator only intervenes when the clock moved backwards.

SnowflakeGenerator already accepts WithClockSync directly, but the string family and user-supplied generators do not, which is what this decorator is for.

func NewClockSyncGenerator

func NewClockSyncGenerator(actual Generator, sync ClockSync) (*ClockSyncGenerator, error)

NewClockSyncGenerator wraps a generator. A nil sync means CosID's default thresholds.

func (*ClockSyncGenerator) Next

func (g *ClockSyncGenerator) Next(ctx context.Context) (int64, error)

Next implements Generator.

func (*ClockSyncGenerator) Stat

func (g *ClockSyncGenerator) Stat() Stat

Stat implements Statistical.

type CosIDState

type CosIDState struct {
	Timestamp int64
	MachineID int32
	Sequence  int32
}

CosIDState is one generated value split into its three parts (CosID's CosIdState).

func (CosIDState) Compare

func (s CosIDState) Compare(other CosIDState) int

Compare orders states by timestamp, then machine, then sequence.

type DateGroup

type DateGroup struct {
	Period   Period
	Layout   string // Go layout; defaults follow the period
	Location *time.Location
}

DateGroup groups allocations by calendar period, like CosID's AbstractDateGroupBySupplier: the key is the formatted period and the TTL ends with it, so the next period starts a fresh counter.

func NewDateGroup

func NewDateGroup(period Period) (*DateGroup, error)

NewDateGroup builds a date-based grouping.

func (*DateGroup) Group

func (g *DateGroup) Group(now time.Time) GroupedKey

Group implements GroupBy, filling the key and setting TTLAt to the last second of the period (CosID uses LocalTime.MAX, i.e. the period's very end).

type DatePrefix

type DatePrefix = core.DatePrefix

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type DefaultClockSync

type DefaultClockSync struct {
	SpinThreshold   int64 // milliseconds
	BrokenThreshold int64 // milliseconds
	Now             func() int64
	Sleep           func(time.Duration)
}

DefaultClockSync mirrors DefaultClockBackwardsSynchronizer.

func NewDefaultClockSync

func NewDefaultClockSync() *DefaultClockSync

NewDefaultClockSync returns CosID's default thresholds (1ms / 500ms).

func (*DefaultClockSync) Synchronize

func (d *DefaultClockSync) Synchronize(lastTimestamp int64) error

Synchronize implements ClockSync.

type Generator

type Generator = core.Generator

core vocabulary

type GroupBy

type GroupBy interface {
	Group(now time.Time) GroupedKey
}

GroupBy resolves the group of a moment in time — CosID's GroupBySupplier.

type GroupedAllocator

type GroupedAllocator struct {
	Source SegmentAllocator
	By     GroupBy
	Now    func() time.Time
}

GroupedAllocator turns a SegmentAllocator into per-period counters: each period gets its own storage key `name@<group>`, so ids restart when the period rolls over — CosID's DefaultGroupedIdSegmentDistributor.

func (*GroupedAllocator) Key

func (g *GroupedAllocator) Key() GroupedKey

Key returns the current group.

func (*GroupedAllocator) NameFor

func (g *GroupedAllocator) NameFor(name string) string

NameFor renders the storage key of the current period.

func (*GroupedAllocator) NextMaxId

func (g *GroupedAllocator) NextMaxId(ctx context.Context, name string, step int64) (int64, error)

NextMaxId implements SegmentAllocator.

type GroupedGenerator

type GroupedGenerator struct {
	Allocator *GroupedAllocator
	Generator *ChainGenerator
}

GroupedGenerator pairs a generator with its group key, which is what a GroupedPrefix converter needs to render `<group>-<id>`. CosID carries the key in a ThreadLocal; passing it explicitly keeps this library free of ambient state.

func NewGroupedGenerator

func NewGroupedGenerator(allocator *GroupedAllocator, step int64, opts ...ChainOption) (*GroupedGenerator, error)

NewGroupedGenerator builds a chain generator backed by per-period counters.

func (*GroupedGenerator) Close

func (g *GroupedGenerator) Close(ctx context.Context) error

Close releases the underlying generator.

func (*GroupedGenerator) Namespace

func (g *GroupedGenerator) Namespace() string

Namespace implements NamedGenerator.

func (*GroupedGenerator) Next

Next returns one id together with the group it belongs to.

func (*GroupedGenerator) NextString

func (g *GroupedGenerator) NextString(ctx context.Context, delimiter string, actual StringConverter) (string, error)

NextString renders the id with a grouped prefix, e.g. `2026-000042`.

type GroupedKey

type GroupedKey struct {
	Key   string
	TTLAt int64
}

GroupedKey labels an allocation period — CosID's GroupedKey. TTLAt is the unix second at which the group ends, so a caller can tell when a counter restarts.

func (GroupedKey) TTL

func (k GroupedKey) TTL(now time.Time) int64

TTL returns how many seconds the group has left.

type GroupedPrefix

type GroupedPrefix = core.GroupedPrefix

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type Guarder

type Guarder = machine.Guarder

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type GuarderOption

type GuarderOption = machine.GuarderOption

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type GuardianState

type GuardianState = machine.GuardianState

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type HostAddressSupplier

type HostAddressSupplier = machine.HostAddressSupplier

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type Injector

type Injector struct {
	// contains filtered or unexported fields
}

Injector fills id fields of structs from registered generators. CosID reaches the fields through reflection on annotated classes; Go does the same through struct tags, so an entity does not have to know about the generator at all.

func NewInjector

func NewInjector() *Injector

NewInjector creates an empty injector.

func NewInjectorFromProvider

func NewInjectorFromProvider(provider *Provider) *Injector

NewInjectorFromProvider creates an injector backed by a Provider's named generators. The registry is read on every fill, so generators may be replaced at runtime.

func (*Injector) Ensure

func (i *Injector) Ensure(ctx context.Context, entity any) (bool, error)

Ensure fills every empty id field of the entity. It reports whether anything was filled, mirroring CosID's EnsureId: an entity that already carries an id is left untouched.

func (*Injector) EnsureAll

func (i *Injector) EnsureAll(ctx context.Context, entities any) (int, error)

EnsureAll fills every entity of a slice or array.

func (*Injector) Register

func (i *Injector) Register(name string, gen Generator)

Register binds a generator name to an int64 id field.

func (*Injector) RegisterString

func (i *Injector) RegisterString(name string, gen StringGenerator)

RegisterString binds a generator name to a string id field.

type InstanceID

type InstanceID = machine.InstanceID

machine-id distribution

type IntegerGenerator

type IntegerGenerator struct {
	Actual Generator
}

IntegerGenerator exposes a Generator as a 32-bit id source, refusing values that do not fit — CosID's IntegerIdGenerator.

func (IntegerGenerator) GenerateAsString

func (g IntegerGenerator) GenerateAsString(ctx context.Context) (string, error)

GenerateAsString implements StringGenerator: the decimal rendering of the id.

func (IntegerGenerator) NextAsInt

func (g IntegerGenerator) NextAsInt(ctx context.Context) (int32, error)

NextAsInt implements the integer view with an overflow check.

type IntervalNode

type IntervalNode struct {
	Lower time.Time
	Node  string
}

IntervalNode is one node of a timeline with the instant it starts at.

type IntervalStep

type IntervalStep struct {
	// Kind is the calendar unit; months and years are not fixed durations, so
	// arithmetic goes through the calendar rather than a time.Duration.
	Kind   StepUnit
	Amount int
}

IntervalStep is one step of an interval timeline: `Amount` units of `Unit`, floored to the unit — CosID's IntervalStep.

func NewIntervalStep

func NewIntervalStep(unit StepUnit, amount int) (IntervalStep, error)

NewIntervalStep validates a step.

func (IntervalStep) FloorUnit

func (s IntervalStep) FloorUnit(t time.Time) time.Time

FloorUnit truncates to the start of the unit, like IntervalStep.floorUnit.

func (IntervalStep) Next

func (s IntervalStep) Next(t time.Time) time.Time

Next advances one step.

func (IntervalStep) Offset

func (s IntervalStep) Offset(start, t time.Time) int

Offset counts whole steps between start and t (IntervalStep.offsetUnit).

type IntervalTimeline

type IntervalTimeline struct {
	Prefix   string
	Layout   string
	Step     IntervalStep
	Lower    time.Time
	Upper    time.Time
	Location *time.Location
	// contains filtered or unexported fields
}

IntervalTimeline shards by time window: node names are `prefix + formatted window start`, so each window can live in its own storage — CosID's IntervalTimeline.

func NewIntervalTimeline

func NewIntervalTimeline(prefix, layout string, step IntervalStep, lower, upper time.Time) (*IntervalTimeline, error)

NewIntervalTimeline builds a timeline covering [lower, upper] in steps.

func (*IntervalTimeline) EffectiveNodes

func (tl *IntervalTimeline) EffectiveNodes() []string

EffectiveNodes implements Sharding.

func (*IntervalTimeline) Sharding

func (tl *IntervalTimeline) Sharding(value time.Time) (string, error)

Sharding implements Sharding for instants. Values outside the timeline are an error rather than silently landing on the first or last node.

func (*IntervalTimeline) ShardingRange

func (tl *IntervalTimeline) ShardingRange(lower, upper time.Time, hasLower, hasUpper bool) []string

ShardingRange implements Sharding.

type Layout

type Layout = core.Layout

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type LazyGenerator

type LazyGenerator struct {
	// contains filtered or unexported fields
}

LazyGenerator defers construction until the first Next call — CosID's LazyIdGenerator. It lets a distribution wire a generator whose backing store (or machine id) is only available after start-up.

func NewLazyGenerator

func NewLazyGenerator(init func(context.Context) (Generator, error)) *LazyGenerator

NewLazyGenerator creates a generator that builds itself on first use.

func (*LazyGenerator) Next

func (g *LazyGenerator) Next(ctx context.Context) (int64, error)

Next implements Generator.

type LeaseDistributor

type LeaseDistributor = machine.LeaseDistributor

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type LeaseOption

type LeaseOption = machine.LeaseOption

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type LocalDateTimeConverter

type LocalDateTimeConverter interface {
	ToTime(value any) (time.Time, error)
}

LocalDateTimeConverter turns a sharding value of any supported shape into an instant — CosID's LocalDateTimeConvertor. Sharding then works uniformly for timestamps, formatted strings and snowflake ids.

type LocalHostAddress

type LocalHostAddress = machine.LocalHostAddress

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type LocalStateStorage

type LocalStateStorage = machine.LocalStateStorage

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type MachineIdDistributor

type MachineIdDistributor = machine.MachineIdDistributor

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type MachineState

type MachineState = machine.MachineState

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type MachineStateStorage

type MachineStateStorage = machine.MachineStateStorage

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type ManualDistributor

type ManualDistributor = machine.ManualDistributor

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type MemoryAllocator

type MemoryAllocator struct {
	// contains filtered or unexported fields
}

MemoryAllocator is an in-process allocator for tests and single-process deployments without a database.

func NewMemoryAllocator

func NewMemoryAllocator(step int64) *MemoryAllocator

NewMemoryAllocator creates an allocator using `step` when the caller does not request one.

func (*MemoryAllocator) NextMaxId

func (m *MemoryAllocator) NextMaxId(_ context.Context, namespace string, step int64) (int64, error)

NextMaxId implements SegmentAllocator.

type MemoryMachineStorage

type MemoryMachineStorage = machine.MemoryMachineStorage

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type ModCycle

type ModCycle struct {
	Divisor int
	Prefix  string
	// contains filtered or unexported fields
}

ModCycle spreads values over `divisor` nodes by modulo — CosID's ModCycle. The node name is `prefix + (value mod divisor)`.

func NewModCycle

func NewModCycle(divisor int, prefix string) (*ModCycle, error)

NewModCycle creates a modulo cycle sharding.

func (*ModCycle) EffectiveNodes

func (m *ModCycle) EffectiveNodes() []string

EffectiveNodes implements Sharding.

func (*ModCycle) Sharding

func (m *ModCycle) Sharding(value int64) (string, error)

Sharding implements Sharding for int64 values.

func (*ModCycle) ShardingRange

func (m *ModCycle) ShardingRange(lower, upper int64, hasLower, hasUpper bool) []string

ShardingRange implements Sharding. A full (unbounded) range covers every node.

type NamedGenerator

type NamedGenerator = core.NamedGenerator

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type NamespacedInstanceID

type NamespacedInstanceID = machine.NamespacedInstanceID

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type NoopGuarder

type NoopGuarder = machine.NoopGuarder

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type Period

type Period string

Period is the granularity of a date-based group.

const (
	PeriodYear      Period = "year"
	PeriodYearMonth Period = "year-month"
	PeriodYearDay   Period = "year-month-day"
)

Supported periods, matching CosID's Year / YearMonth / YearMonthDay suppliers.

type Prefix

type Prefix = core.Prefix

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type Provider

type Provider struct {
	// contains filtered or unexported fields
}

Provider is CosID's IdGeneratorProvider: a registry of named generators.

func NewProvider

func NewProvider() *Provider

NewProvider creates an empty registry.

func (*Provider) All

func (p *Provider) All() []Generator

All returns every registered generator, including the shared one.

func (*Provider) Clear

func (p *Provider) Clear()

Clear drops every generator, including the shared one.

func (*Provider) Get

func (p *Provider) Get(name string) (Generator, bool)

Get returns a named generator.

func (*Provider) Names

func (p *Provider) Names() []string

Names lists the registered generator names in a stable order.

func (*Provider) Remove

func (p *Provider) Remove(name string) Generator

Remove drops a generator and returns it.

func (*Provider) RemoveShare

func (p *Provider) RemoveShare() Generator

RemoveShare clears the shared generator and returns it.

func (*Provider) Required

func (p *Provider) Required(name string) (Generator, error)

Required returns a named generator or an error naming it, mirroring IdGeneratorProvider.getRequired.

func (*Provider) Set

func (p *Provider) Set(name string, gen Generator)

Set registers a generator. The share name routes to SetShare so the two views never disagree.

func (*Provider) SetShare

func (p *Provider) SetShare(gen Generator)

SetShare installs the shared generator. As in CosID, the shared generator is also reachable by name, so Get(ShareName) works.

func (*Provider) Share

func (p *Provider) Share() Generator

Share returns the shared generator, or nil.

func (*Provider) ShareRequired

func (p *Provider) ShareRequired() (Generator, error)

ShareRequired returns the shared generator or an error naming it. It is what an unnamed id field resolves to.

type Radix

type Radix = core.Radix

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type RadixStateParser

type RadixStateParser struct {
	Base      int
	Timestamp *Radix
	Machine   *Radix
	Sequence  *Radix
}

RadixStateParser renders a state as fixed-width padded radix fields — CosID's RadixCosIdStateParser. Each field is padded to the digit count its bit width needs, so the total length is constant.

func NewRadixStateParser

func NewRadixStateParser(base, timestampBits, machineBits, sequenceBits int) (*RadixStateParser, error)

NewRadixStateParser builds a parser for the given bits and radix.

func (RadixStateParser) Format

func (p RadixStateParser) Format(state CosIDState) string

Format implements the string rendering.

func (RadixStateParser) Parse

func (p RadixStateParser) Parse(id string) (CosIDState, error)

Parse is the inverse of Format.

type Segment

type Segment = core.Segment

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type SegmentAllocator

type SegmentAllocator = core.SegmentAllocator

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type SegmentGenerator

type SegmentGenerator struct {
	// contains filtered or unexported fields
}

SegmentGenerator issues the values of ranges reserved from a SegmentAllocator. It keeps one range in reserve so a refill does not stall every caller.

Concurrency: Next is safe for concurrent use. The synchronous refill path holds the generator lock across the allocator call; that path is rare because the fetcher keeps a range ready.

func NewSegmentGenerator

func NewSegmentGenerator(namespace string, step int64, alloc SegmentAllocator, opts ...SegmentOption) (*SegmentGenerator, error)

NewSegmentGenerator creates a generator for one namespace. Ranges are prefetched once half of the current one is consumed.

func (*SegmentGenerator) Close

func (g *SegmentGenerator) Close(ctx context.Context) error

Close stops prefetching and waits for the in-flight reservation to finish. Ranges already buffered are dropped: a closed generator never hands out another id.

func (*SegmentGenerator) Namespace

func (g *SegmentGenerator) Namespace() string

Namespace implements NamedGenerator.

func (*SegmentGenerator) Next

func (g *SegmentGenerator) Next(ctx context.Context) (int64, error)

Next implements Generator. The first id of a reserved range (offset+1) is handed out first, exactly like CosID's DefaultIdSegment.

func (*SegmentGenerator) Stat

func (g *SegmentGenerator) Stat() Stat

Stat implements Statistical for a segment generator: the same fields CosID's SegmentIdStat exposes, so an operator sees how much of the range is left.

type SegmentOption

type SegmentOption func(*SegmentGenerator)

SegmentOption configures a SegmentGenerator.

func WithPrefetchRatio

func WithPrefetchRatio(ratio float64) SegmentOption

WithPrefetchRatio sets the fraction of a range that must remain for a prefetch to start. 0 disables prefetching.

func WithSegmentClock

func WithSegmentClock(now func() int64) SegmentOption

WithSegmentClock overrides the clock used for TTL checks (tests).

func WithSegmentTTL

func WithSegmentTTL(ttl time.Duration) SegmentOption

WithSegmentTTL gives reserved ranges a lifetime. An expired range is abandoned and a new one is reserved, matching CosID's IdSegment.isExpired. Durations shorter than a second round up, so a range never starts expired.

type Sharding

type Sharding[T any] interface {
	// Sharding returns the node for a single value.
	Sharding(value T) (string, error)
	// ShardingRange returns the nodes a range touches, deduplicated.
	ShardingRange(lower, upper T, hasLower, hasUpper bool) []string
	// EffectiveNodes lists every node the sharding can produce.
	EffectiveNodes() []string
}

Sharding maps a value (or a value range) to logical node names — CosID's sharding package. It is how a deployment spreads snowflake ids of different time windows over different storage shards.

type SnowflakeConverter

type SnowflakeConverter struct {
	Layout Layout
	// Radix parses string values; nil means decimal.
	Radix *Radix
}

SnowflakeConverter goes the other way: from an id (or its rendered string) to the instant it was generated — CosID's SnowflakeLocalDateTimeConvertor. That is what lets a sharding question start from an id instead of a timestamp.

func (SnowflakeConverter) ToTime

func (c SnowflakeConverter) ToTime(value any) (time.Time, error)

ToTime implements LocalDateTimeConverter.

type SnowflakeFriendly

type SnowflakeFriendly = core.SnowflakeFriendly

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type SnowflakeGenerator

type SnowflakeGenerator struct {
	// contains filtered or unexported fields
}

SnowflakeGenerator implements Generator on a fixed layout.

func NewSnowflake

func NewSnowflake(layout Layout, machineID int64, opts ...SnowflakeOption) (*SnowflakeGenerator, error)

NewSnowflake creates a generator for one machine id.

func (*SnowflakeGenerator) Layout

func (g *SnowflakeGenerator) Layout() Layout

Layout returns the configured layout.

func (*SnowflakeGenerator) Next

Next implements Generator, following AbstractSnowflakeId.generate.

func (*SnowflakeGenerator) Stat

func (g *SnowflakeGenerator) Stat() Stat

Stat implements Statistical for a snowflake generator.

type SnowflakeOption

type SnowflakeOption func(*SnowflakeGenerator)

SnowflakeOption configures a SnowflakeGenerator.

func WithClockSync

func WithClockSync(sync ClockSync) SnowflakeOption

WithClockSync installs a clock-backwards handler. Without one the generator fails on any backwards movement.

func WithSequenceResetThreshold

func WithSequenceResetThreshold(threshold int64) SnowflakeOption

WithSequenceResetThreshold overrides CosID's default (half the sequence space), which evens out id distribution across shards.

func WithSnowflakeClock

func WithSnowflakeClock(now func() int64) SnowflakeOption

WithSnowflakeClock overrides the time source (tests). It must return the same unit as the layout: milliseconds for millisecond layouts, seconds for second layouts.

type StandardConverter

type StandardConverter struct {
	// SecondEpoch treats numeric values as seconds instead of milliseconds.
	SecondEpoch bool
	Location    *time.Location
	// Layout parses string values; RFC3339 when empty.
	Layout string
}

StandardConverter accepts time.Time, epoch millis or seconds, and RFC3339 strings — CosID's StandardLocalDateTimeConvertor.

func (StandardConverter) ToTime

func (c StandardConverter) ToTime(value any) (time.Time, error)

ToTime implements LocalDateTimeConverter.

type Stat

type Stat = core.Stat

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type State

type State = core.State

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type StatefulSetDistributor

type StatefulSetDistributor = machine.StatefulSetDistributor

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type Statistical

type Statistical = core.Statistical

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type StepUnit

type StepUnit string

StepUnit is the calendar unit of an interval step.

const (
	StepYear   StepUnit = "year"
	StepMonth  StepUnit = "month"
	StepDay    StepUnit = "day"
	StepHour   StepUnit = "hour"
	StepMinute StepUnit = "minute"
)

Supported step units.

type StringClockSyncGenerator

type StringClockSyncGenerator struct {
	Actual StringGenerator
	Sync   ClockSync
}

StringClockSyncGenerator is ClockSyncGenerator for string generators.

func NewStringClockSyncGenerator

func NewStringClockSyncGenerator(actual StringGenerator, sync ClockSync) (*StringClockSyncGenerator, error)

NewStringClockSyncGenerator wraps a string generator.

func (*StringClockSyncGenerator) GenerateAsString

func (g *StringClockSyncGenerator) GenerateAsString(ctx context.Context) (string, error)

GenerateAsString implements StringGenerator.

type StringConverter

type StringConverter = core.StringConverter

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type StringCosIDGenerator

type StringCosIDGenerator struct {
	// contains filtered or unexported fields
}

StringCosIDGenerator is CosID's Radix36/Radix62 generator: a string id made of timestamp, machine and sequence, rendered in a radix.

func NewStringCosIDGenerator

func NewStringCosIDGenerator(base int, machineID int32, opts ...StringCosIDOption) (*StringCosIDGenerator, error)

NewStringCosIDGenerator creates a base36 or base62 string generator.

func (*StringCosIDGenerator) GenerateAsString

func (g *StringCosIDGenerator) GenerateAsString(ctx context.Context) (string, error)

GenerateAsString implements StringGenerator.

func (*StringCosIDGenerator) Next

Next is not supported: this generator produces strings, not int64 ids.

func (*StringCosIDGenerator) NextState

func (g *StringCosIDGenerator) NextState() (CosIDState, error)

NextState implements CosID's RadixCosIdGenerator.generateAsState: the same sequence reset / overflow handling as the snowflake, but without an epoch offset and without bit packing.

func (*StringCosIDGenerator) Parser

Parser exposes the state parser (useful for tests and tooling).

func (*StringCosIDGenerator) Stat

func (g *StringCosIDGenerator) Stat() Stat

Stat implements Statistical for the CosID string family.

func (*StringCosIDGenerator) StateOfString

func (g *StringCosIDGenerator) StateOfString(id string) (CosIDState, error)

StateOfString parses an id produced by a generator with the same layout.

type StringCosIDOption

type StringCosIDOption func(*StringCosIDGenerator)

StringCosIDOption configures a StringCosIDGenerator.

func WithStringCosIDClock

func WithStringCosIDClock(now func() int64) StringCosIDOption

WithStringCosIDClock overrides the millisecond clock (tests).

func WithStringCosIDLayout

func WithStringCosIDLayout(timestampBits, machineBits, sequenceBits int) StringCosIDOption

WithStringCosIDLayout overrides the bit layout (defaults 44/20/16).

type StringGenerator

type StringGenerator interface {
	GenerateAsString(ctx context.Context) (string, error)
}

StringGenerator renders ids as strings. Some generators (UUID, CosID's base36/base62 family) only make sense as strings, so they implement this instead of Generator.

func StringOf

func StringOf(gen Generator, conv StringConverter) StringGenerator

StringOf adapts a Generator to StringGenerator using a converter — the Go equivalent of CosID's StringIdGenerator decorators (Radix36/62, friendly).

type StringSegmentID

type StringSegmentID struct {
	Actual    *SegmentGenerator
	Converter StringConverter
}

StringSegmentID is a segment generator rendered as a string — CosID's StringSegmentId. The numeric generator stays the source of truth; the wrapper only changes the surface, and it exposes the current segment and the stat of both halves.

func NewStringSegmentID

func NewStringSegmentID(actual *SegmentGenerator, converter StringConverter) (*StringSegmentID, error)

NewStringSegmentID wraps a segment generator with a converter.

func (*StringSegmentID) Current

func (s *StringSegmentID) Current() Segment

Current exposes the segment in use, like SegmentId.current().

func (*StringSegmentID) GenerateAsString

func (s *StringSegmentID) GenerateAsString(ctx context.Context) (string, error)

GenerateAsString implements StringGenerator.

func (*StringSegmentID) Next

func (s *StringSegmentID) Next(ctx context.Context) (int64, error)

Next keeps the numeric view available.

func (*StringSegmentID) Stat

func (s *StringSegmentID) Stat() Stat

Stat implements Statistical, keeping the converter visible in the tree.

type StringSnowflakeID

type StringSnowflakeID struct {
	Actual    *SnowflakeGenerator
	Converter StringConverter
}

StringSnowflakeID is a snowflake generator rendered as a string — CosID's StringSnowflakeId.

func NewStringSnowflakeID

func NewStringSnowflakeID(actual *SnowflakeGenerator, converter StringConverter) (*StringSnowflakeID, error)

NewStringSnowflakeID wraps a snowflake generator with a converter.

func (*StringSnowflakeID) GenerateAsString

func (s *StringSnowflakeID) GenerateAsString(ctx context.Context) (string, error)

GenerateAsString implements StringGenerator.

func (*StringSnowflakeID) Layout

func (s *StringSnowflakeID) Layout() Layout

Layout exposes the wrapped layout, like SnowflakeId.getEpoch()/getTimestampBit().

func (*StringSnowflakeID) Next

func (s *StringSnowflakeID) Next(ctx context.Context) (int64, error)

Next keeps the numeric view available.

func (*StringSnowflakeID) Stat

func (s *StringSnowflakeID) Stat() Stat

Stat implements Statistical.

type Suffix

type Suffix = core.Suffix

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type ToString

type ToString = core.ToString

The vocabulary every generator, converter and allocator shares lives in ./core: the generator contracts, the segment model, the radix/prefix vocabulary, the snowflake layout and the Stat tree. Every name below is an alias, so a consumer keeps importing gcosid and still gets the core type — one definition, two import paths.

type UUIDGenerator

type UUIDGenerator struct{}

UUIDGenerator is CosID's jvm.UuidGenerator: random UUIDv4 as a string.

func (UUIDGenerator) GenerateAsString

func (UUIDGenerator) GenerateAsString(context.Context) (string, error)

GenerateAsString implements StringGenerator.

func (UUIDGenerator) Next

Next refuses to produce a long id, exactly like CosID: a UUID does not fit in an int64 and pretending otherwise silently loses half of it.

type UncertaintyGenerator

type UncertaintyGenerator struct {
	Actual          Generator
	UncertaintyBits int
	// contains filtered or unexported fields
}

UncertaintyGenerator appends random low bits to every id — CosID's UncertaintyIdGenerator. The ordering is preserved at the granularity of the original id, while the trailing digits no longer expose the sequence, which keeps ids from advertising how many were issued or which one comes next.

func NewUncertaintyGenerator

func NewUncertaintyGenerator(actual Generator, bits int) (*UncertaintyGenerator, error)

NewUncertaintyGenerator wraps a generator, reserving `bits` low bits for randomness. `bits` must leave room for the original id inside 63 bits.

func (*UncertaintyGenerator) Bound

func (g *UncertaintyGenerator) Bound() int64

Bound is the exclusive upper bound of the random suffix.

func (*UncertaintyGenerator) Next

Next implements Generator.

func (*UncertaintyGenerator) OriginalMaxID

func (g *UncertaintyGenerator) OriginalMaxID() int64

OriginalMaxID is the largest id the wrapped generator may produce.

func (*UncertaintyGenerator) Stat

func (g *UncertaintyGenerator) Stat() Stat

Stat implements Statistical.

Directories

Path Synopsis
Package database implements gcosid's segment allocator on top of database/sql.
Package database implements gcosid's segment allocator on top of database/sql.
examples
inject command
Command inject shows how gcosid fills entity ids.
Command inject shows how gcosid fills entity ids.
repository command
Command repository shows where id injection belongs in a real service.
Command repository shows where id injection belongs in a real service.
Package redis implements CosID's Redis storage protocol.
Package redis implements CosID's Redis storage protocol.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL