我们几乎可以肯定 ObjectId 将是唯一的。:)
当不使用本机扩展(现在bson
显然包含在 mongoid/moped 使用的 gem 中)时,它使用了一个计数器。
def next(time = nil)
@mutex.lock
begin
count = @counter = (@counter + 1) % 0xFFFFFF
ensure
@mutex.unlock rescue nil
end
generate(time || ::Time.new.to_i, count)
end
正如你在Generator
课堂上看到的那样,它使用了一个计数器。
当使用本机 C 代码生成 ObjectId 时,它也使用了一个计数器:
static VALUE rb_object_id_generator_next(int argc, VALUE* time, VALUE self)
{
char bytes[12];
unsigned long t;
unsigned short pid = htons(getpid());
if (argc == 0 || (argc == 1 && *time == Qnil)) {
t = rb_current_time_milliseconds();
}
else {
t = htonl(NUM2UINT(rb_funcall(*time, rb_intern("to_i"), 0)));
}
memcpy(&bytes, &t, 4);
memcpy(&bytes[4], rb_bson_machine_id, 3);
memcpy(&bytes[7], &pid, 2);
memcpy(&bytes[9], (unsigned char*) &rb_bson_object_id_counter, 3);
rb_bson_object_id_counter++;
return rb_str_new(bytes, 12);
}
附录(感谢@ChrisHeald的提示)
假设正在使用的 Ruby 实现使用 GIL(全局解释器锁)并使用上面的 C 代码实现,C 代码在递增计数器时也是安全的rb_bson_object_id_counter
,因为在调用此代码时会有一个外部锁.