use correct ObjectID generation - no change to ordering yet though

This commit is contained in:
Mike Dirolf 2009-08-25 10:30:14 -04:00
parent 496af2be9c
commit e05c9fc5da
2 changed files with 35 additions and 56 deletions

View File

@ -15,6 +15,8 @@
# ++
require 'mutex_m'
require 'socket'
require 'digest/md5'
require 'mongo/util/byte_buffer'
module Mongo
@ -41,10 +43,6 @@ module Mongo
# 10
# 11
class ObjectID
MACHINE = ( val = rand(0x1000000); [val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff] )
PID = ( val = rand(0x10000); [val & 0xff, (val >> 8) & 0xff]; )
# The string representation of an OID is different than its internal
# and BSON byte representations. The BYTE_ORDER here maps
# internal/BSON byte position (the index in BYTE_ORDER) to the
@ -56,7 +54,6 @@ module Mongo
LOCK = Object.new
LOCK.extend Mutex_m
@@index_time = Time.new.to_i
@@index = 0
# Given a string representation of an ObjectID, return a new ObjectID
@ -78,9 +75,8 @@ module Mongo
end
# +data+ is an array of bytes. If nil, a new id will be generated.
# The time +t+ is only used for testing; leave it nil.
def initialize(data=nil, t=nil)
@data = data || generate_id(t)
def initialize(data=nil)
@data = data || generate
end
def eql?(other)
@ -100,34 +96,39 @@ module Mongo
str
end
# (Would normally be private, but isn't so we can test it.)
def generate_id(t=nil)
t ||= Time.new.to_i
private
def generate
# 4 bytes current time
time = Time.new.to_i
buf = ByteBuffer.new
buf.put_int(t & 0xffffffff)
buf.put_array(MACHINE)
buf.put_array(PID)
i = index_for_time(t)
buf.put(i & 0xff)
buf.put((i >> 8) & 0xff)
buf.put((i >> 16) & 0xff)
buf.put_int(time & 0xFFFFFFFF)
# 3 bytes machine
machine_hash = Digest::MD5.digest(Socket.gethostname)
buf.put(machine_hash[0])
buf.put(machine_hash[1])
buf.put(machine_hash[2])
# 2 bytes pid
pid = Process.pid % 0xFFFF
buf.put(pid & 0xFF)
buf.put((pid >> 8) & 0xFF)
# 3 bytes inc
inc = get_inc
buf.put(inc & 0xFF)
buf.put((inc >> 8) & 0xFF)
buf.put((inc >> 16) & 0xFF)
buf.rewind
buf.to_a.dup
end
# (Would normally be private, but isn't so we can test it.)
def index_for_time(t)
def get_inc
LOCK.mu_synchronize {
if t != @@index_time
@@index = 0
@@index_time = t
end
retval = @@index
@@index += 1
retval
@@index = (@@index + 1) % 0xFFFFFF
}
end
end
end

View File

@ -7,41 +7,19 @@ class ObjectIDTest < Test::Unit::TestCase
include Mongo
def setup
@t = 42
@o = ObjectID.new(nil, @t)
end
def test_index_for_time
t = 99
assert_equal 0, @o.index_for_time(t)
assert_equal 1, @o.index_for_time(t)
assert_equal 2, @o.index_for_time(t)
t = 100
assert_equal 0, @o.index_for_time(t)
end
def test_time_bytes
a = @o.to_a
assert_equal @t, a[0]
3.times { |i| assert_equal 0, a[i+1] }
t = 43
o = ObjectID.new(nil, t)
a = o.to_a
assert_equal t, a[0]
3.times { |i| assert_equal 0, a[i+1] }
assert_equal 1, o.index_for_time(t) # 0 was used for o
@o = ObjectID.new()
end
def test_different
o2 = ObjectID.new(nil, @t)
assert @o.to_a != o2.to_a
a = ObjectID.new
b = ObjectID.new
assert_not_equal a.to_a, b.to_a
assert_not_equal a, b
end
def test_eql?
o2 = ObjectID.new(@o.to_a)
assert @o.eql?(o2)
assert @o == o2
assert_equal @o, o2
end
def test_to_s