~rogpeppe/mgo/thread-safe-newobject

« back to all changes in this revision

Viewing changes to bson/bson.go

  • Committer: Roger Peppe
  • Date: 2013-04-03 09:08:56 UTC
  • Revision ID: roger.peppe@canonical.com-20130403090856-koowpqxzkkxga8s2
bson: make NewObjectId thread safe

Show diffs side-by-side

added added

removed removed

Lines of Context:
176
176
 
177
177
// machineId stores machine id generated once and used in subsequent calls
178
178
// to NewObjectId function.
179
 
var machineId []byte
 
179
var machineId = readMachineId()
180
180
 
181
181
// initMachineId generates machine id and puts it into the machineId global
182
182
// variable. If this function fails to get the hostname, it will cause
183
183
// a runtime error.
184
 
func initMachineId() {
 
184
func readMachineId() []byte {
185
185
        var sum [3]byte
186
 
        machineId = sum[:]
 
186
        id := sum[:]
187
187
        hostname, err1 := os.Hostname()
188
188
        if err1 != nil {
189
 
                _, err2 := io.ReadFull(rand.Reader, machineId)
 
189
                _, err2 := io.ReadFull(rand.Reader, id)
190
190
                if err2 != nil {
191
191
                        panic(fmt.Errorf("cannot get hostname: %v; %v", err1, err2))
192
192
                }
193
 
                return
 
193
                return id
194
194
        }
195
195
        hw := md5.New()
196
196
        hw.Write([]byte(hostname))
197
 
        copy(machineId, hw.Sum(nil))
 
197
        copy(id, hw.Sum(nil))
 
198
        return id
198
199
}
199
200
 
200
201
// NewObjectId returns a new unique ObjectId.
201
202
// This function causes a runtime error if it fails to get the hostname
202
203
// of the current machine.
203
204
func NewObjectId() ObjectId {
204
 
        b := make([]byte, 12)
 
205
        var b [12]byte
205
206
        // Timestamp, 4 bytes, big endian
206
 
        binary.BigEndian.PutUint32(b, uint32(time.Now().Unix()))
 
207
        binary.BigEndian.PutUint32(b[:], uint32(time.Now().Unix()))
207
208
        // Machine, first 3 bytes of md5(hostname)
208
 
        if machineId == nil {
209
 
                initMachineId()
210
 
        }
211
209
        b[4] = machineId[0]
212
210
        b[5] = machineId[1]
213
211
        b[6] = machineId[2]
220
218
        b[9] = byte(i >> 16)
221
219
        b[10] = byte(i >> 8)
222
220
        b[11] = byte(i)
223
 
        return ObjectId(b)
 
221
        return ObjectId(b[:])
224
222
}
225
223
 
226
224
// NewObjectIdWithTime returns a dummy ObjectId with the timestamp part filled
316
314
// why this function exists. Using the time.Now function also works fine
317
315
// otherwise.
318
316
func Now() time.Time {
319
 
        return time.Unix(0, time.Now().UnixNano() / 1e6 * 1e6)
 
317
        return time.Unix(0, time.Now().UnixNano()/1e6*1e6)
320
318
}
321
319
 
322
320
// MongoTimestamp is a special internal type used by MongoDB that for some