diff --git a/pkg/gid/gid.go b/pkg/gid/gid.go index 471cc8e17..39f06c7aa 100644 --- a/pkg/gid/gid.go +++ b/pkg/gid/gid.go @@ -10,12 +10,11 @@ import ( ) const ( - GIDSize = 32 // 256 bits total + GIDSize = 24 // 192 bits total ) type ( - GID [GIDSize]byte - TenantID [16]byte // 128-bit tenant ID + GID [GIDSize]byte ) var ( @@ -44,25 +43,25 @@ func New(tenantID TenantID, entityType uint16) GID { // NewGID creates a new GID with the specified entity type and tenant ID // Structure: -// - Bytes 0-15: Tenant ID (full 16 bytes) -// - Bytes 16-17: Entity Type (uint16) -// - Bytes 18-25: Timestamp (milliseconds since epoch) -// - Bytes 26-31: Random data for uniqueness +// - Bytes 0-7: Tenant ID (8 bytes) +// - Bytes 8-9: Entity Type (uint16) +// - Bytes 10-17: Timestamp (milliseconds since epoch) +// - Bytes 18-23: Random data for uniqueness func NewGID(tenantID TenantID, entityType uint16) (GID, error) { var id GID - // Write full tenant ID (16 bytes) - copy(id[0:16], tenantID[:]) + // Write full tenant ID (8 bytes) + copy(id[0:8], tenantID[:]) // Write entity type (2 bytes) - binary.BigEndian.PutUint16(id[16:18], entityType) + binary.BigEndian.PutUint16(id[8:10], entityType) // Get current timestamp (milliseconds) and write it (8 bytes) now := time.Now().UnixMilli() - binary.BigEndian.PutUint64(id[18:26], uint64(now)) + binary.BigEndian.PutUint64(id[10:18], uint64(now)) // Fill the rest with random data (6 bytes) - _, err := rand.Read(id[26:32]) + _, err := rand.Read(id[18:24]) if err != nil { return Nil, fmt.Errorf("failed to generate random bytes: %v", err) } @@ -78,18 +77,18 @@ func (gid GID) Value() (driver.Value, error) { // TenantID extracts the tenant ID from the GID func (gid GID) TenantID() TenantID { var tenantID TenantID - copy(tenantID[:], gid[0:16]) + copy(tenantID[:], gid[0:8]) return tenantID } // EntityType extracts the entity type from the GID func (gid GID) EntityType() uint16 { - return binary.BigEndian.Uint16(gid[16:18]) + return binary.BigEndian.Uint16(gid[8:10]) } // Timestamp extracts the timestamp from the GID func (gid GID) Timestamp() time.Time { - millis := binary.BigEndian.Uint64(gid[18:26]) + millis := binary.BigEndian.Uint64(gid[10:18]) return time.UnixMilli(int64(millis)) } diff --git a/pkg/gid/tenant_id.go b/pkg/gid/tenant_id.go index 4fcb50b70..ea7057a9e 100644 --- a/pkg/gid/tenant_id.go +++ b/pkg/gid/tenant_id.go @@ -11,6 +11,9 @@ import ( "time" ) +// TenantID represents a tenant identifier (64 bits/8 bytes total) +type TenantID [8]byte + var ( // NilTenant represents an empty tenant ID NilTenant = TenantID{} @@ -22,8 +25,7 @@ var ( // TenantGenerator handles creation of unique tenant IDs type tenantGenerator struct { // Process-specific values - machineID [6]byte // 48 bits for machine identifier - processID uint16 // 16 bits for process + machineID [3]byte // 24 bits for machine identifier counter uint32 // Counter for the sequence } @@ -63,48 +65,34 @@ func newTenantGenerator() *tenantGenerator { // Pad with timestamp bits if hostname is short if len(hostname) < len(g.machineID) { ts := time.Now().UnixNano() - binary.BigEndian.PutUint32(g.machineID[len(hostname):], uint32(ts)) + binary.BigEndian.PutUint16(g.machineID[len(hostname):], uint16(ts)) } } - // Set process ID from OS PID - g.processID = uint16(os.Getpid() & 0xFFFF) - return g } -// NewTenantID generates a new 128-bit tenant ID with the structure: -// - 48 bits: Machine ID (random, unique per machine) -// - 16 bits: Process ID (unique per process on machine) -// - 48 bits: Timestamp (milliseconds, sequential) +// NewTenantID generates a new 64-bit tenant ID with the structure: +// - 24 bits: Machine ID (random, unique per machine) +// - 24 bits: Timestamp (truncated Unix time in seconds) // - 16 bits: Counter (increments per ID) func (g *tenantGenerator) NewTenantID() TenantID { // Create new ID var id TenantID - // 1. Get timestamp (48 bits = milliseconds since epoch) - now := time.Now().UnixMilli() + // 1. Copy machine ID (first 3 bytes) + copy(id[0:3], g.machineID[:]) - // 2. Increment counter atomically (16 bits used) + // 2. Add timestamp (next 3 bytes) - Unix time in seconds (truncated) + // Using seconds instead of milliseconds gives us until year 2286 + now := uint32(time.Now().Unix()) + id[3] = byte(now >> 16) + id[4] = byte(now >> 8) + id[5] = byte(now) + + // 3. Increment counter atomically (last 2 bytes) count := atomic.AddUint32(&g.counter, 1) & 0xFFFF - - // 3. Assemble the ID - // First 6 bytes: Machine ID - copy(id[0:6], g.machineID[:]) - - // Next 2 bytes: Process ID - binary.BigEndian.PutUint16(id[6:8], g.processID) - - // Next 6 bytes: Timestamp (48 bits) - id[8] = byte(now >> 40) - id[9] = byte(now >> 32) - id[10] = byte(now >> 24) - id[11] = byte(now >> 16) - id[12] = byte(now >> 8) - id[13] = byte(now) - - // Last 2 bytes: Counter - binary.BigEndian.PutUint16(id[14:16], uint16(count)) + binary.BigEndian.PutUint16(id[6:8], uint16(count)) return id } @@ -167,7 +155,6 @@ func (id TenantID) IsValid() bool { // Timestamp extracts the timestamp from the TenantID func (id TenantID) Timestamp() time.Time { - millis := int64(id[8])<<40 | int64(id[9])<<32 | int64(id[10])<<24 | - int64(id[11])<<16 | int64(id[12])<<8 | int64(id[13]) - return time.UnixMilli(millis) + seconds := uint32(id[3])<<16 | uint32(id[4])<<8 | uint32(id[5]) + return time.Unix(int64(seconds), 0) }