Last active
April 7, 2017 17:33
-
-
Save crhntr/739c01b87665b4273bbb23d47f76f12d to your computer and use it in GitHub Desktop.
minimal bson ObjectID implementation mostly based/copied from implementation in https://labix.org/mgo/bson
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// mostly based on https://labix.org/mgo | |
package id | |
import ( | |
"crypto/md5" | |
"crypto/rand" | |
"encoding/binary" | |
"fmt" | |
"io" | |
"os" | |
"sync/atomic" | |
"time" | |
) | |
type ID string | |
func NewID() ID { | |
var b [12]byte | |
// Timestamp, 4 bytes, big endian | |
binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix())) | |
// Machine, first 3 bytes of md5(hostname) | |
b[4] = machineId[0] | |
b[5] = machineId[1] | |
b[6] = machineId[2] | |
// Pid, 2 bytes, specs don't specify endianness, but we use big endian. | |
pid := os.Getpid() | |
b[7] = byte(pid >> 8) | |
b[8] = byte(pid) | |
// Increment, 3 bytes, big endian | |
i := atomic.AddUint32(&objectIdCounter, 1) | |
b[9] = byte(i >> 16) | |
b[10] = byte(i >> 8) | |
b[11] = byte(i) | |
return ID(b[:]) | |
} | |
// String returns a hex string representation of the id. | |
// Example: 4d88e15b60f486e428412dc9 | |
func (id ID) String() string { | |
return fmt.Sprintf(`%x`, id) | |
} | |
// Valid returns true if id is valid. A valid id must contain exactly 12 bytes. | |
func (id ID) Valid() bool { | |
return len(id) == 12 | |
} | |
// objectIdCounter is atomically incremented when generating a new ObjectId | |
// using NewObjectId() function. It's used as a counter part of an id. | |
var objectIdCounter uint32 = 0 | |
// machineId stores machine id generated once and used in subsequent calls | |
// to NewObjectId function. | |
var machineId = readMachineId() | |
// readMachineId generates machine id and puts it into the machineId global | |
// variable. If this function fails to get the hostname, it will cause | |
// a runtime error. | |
func readMachineId() []byte { | |
var sum [3]byte | |
id := sum[:] | |
hostname, err1 := os.Hostname() | |
if err1 != nil { | |
_, err2 := io.ReadFull(rand.Reader, id) | |
if err2 != nil { | |
panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2)) | |
} | |
return id | |
} | |
hw := md5.New() | |
hw.Write([]byte(hostname)) | |
copy(id, hw.Sum(nil)) | |
return id | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment