mongoid如何生成BSON ObjectId

时间:2013-07-09 10:38:24

标签: ruby-on-rails mongodb ruby-on-rails-3.2 mongoid

这是参考这个答案:https://stackoverflow.com/a/5694803/762747

所以BSON对象ID包括:

[epoch以来的4个字节,3个字节的机器散列,2个字节的进程ID,3个字节的计数器]

mongoid / moped(http://mongoid.org/)使用什么逻辑来生成3字节计数器 - 它们是递增还是生成随机数?

如果有效,我们几乎可以肯定mongoid生成的BSON ObjectId是唯一的(并且避免参考答案中的第2点)吗?

1 个答案:

答案 0 :(得分:2)

我们几乎可以肯定ObjectId将是唯一的。 :)

当不使用原生扩展(现在明显包含在mongoid / moped使用的bson gem中)时,it's使用计数器。

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时,it也在使用计数器:

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(Global Interpreter Lock)并使用上面的C代码实现,C代码在递增计数器rb_bson_object_id_counter时也是安全的,因为是对此代码的调用的外部锁定。