2008-12-17 16:49:06 +00:00
|
|
|
# --
|
2009-01-06 15:51:01 +00:00
|
|
|
# Copyright (C) 2008-2009 10gen Inc.
|
2008-12-02 01:01:13 +00:00
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify it
|
|
|
|
# under the terms of the GNU Affero General Public License, version 3, as
|
|
|
|
# published by the Free Software Foundation.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
|
|
|
|
# for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2008-12-17 16:49:06 +00:00
|
|
|
# ++
|
2008-12-02 01:01:13 +00:00
|
|
|
|
2008-12-09 17:35:03 +00:00
|
|
|
require 'mutex_m'
|
|
|
|
require 'mongo/util/byte_buffer'
|
2008-12-02 01:01:13 +00:00
|
|
|
|
|
|
|
module XGen
|
|
|
|
module Mongo
|
|
|
|
module Driver
|
|
|
|
|
2008-12-17 16:43:08 +00:00
|
|
|
# Implementation of the Babble OID. Object ids are not required by
|
|
|
|
# Mongo, but they make certain operations more efficient.
|
|
|
|
#
|
|
|
|
# The driver does not automatically assign ids to records that are
|
|
|
|
# inserted. (An upcoming feature will allow you to give an id "factory"
|
|
|
|
# to a database and/or a collection.)
|
2008-12-09 17:35:03 +00:00
|
|
|
#
|
|
|
|
# 12 bytes
|
|
|
|
# ---
|
|
|
|
# 0 time
|
|
|
|
# 1
|
|
|
|
# 2
|
|
|
|
# 3
|
|
|
|
# 4 machine
|
|
|
|
# 5
|
|
|
|
# 6
|
|
|
|
# 7 pid
|
|
|
|
# 8
|
|
|
|
# 9 inc
|
|
|
|
# 10
|
|
|
|
# 11
|
2008-12-02 01:01:13 +00:00
|
|
|
class ObjectID
|
|
|
|
|
2008-12-09 17:35:03 +00:00
|
|
|
MACHINE = ( val = rand(0x1000000); [val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff] )
|
|
|
|
PID = ( val = rand(0x10000); [val & 0xff, (val >> 8) & 0xff]; )
|
2008-12-08 21:41:52 +00:00
|
|
|
|
2009-01-12 15:14:48 +00:00
|
|
|
# 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
|
|
|
|
# position of the two hex characters representing that byte in the
|
|
|
|
# string representation. For example, the 0th BSON byte corresponds to
|
|
|
|
# the (0-based) 7th pair of hex chars in the string.
|
|
|
|
BYTE_ORDER = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8]
|
|
|
|
|
2008-12-09 17:35:03 +00:00
|
|
|
LOCK = Object.new
|
|
|
|
LOCK.extend Mutex_m
|
2008-12-04 13:37:42 +00:00
|
|
|
|
2008-12-09 17:35:03 +00:00
|
|
|
@@index_time = Time.new.to_i
|
|
|
|
@@index = 0
|
2008-12-02 01:01:13 +00:00
|
|
|
|
2009-01-09 18:34:30 +00:00
|
|
|
# Given a string representation of an ObjectID, return a new ObjectID
|
|
|
|
# with that value.
|
|
|
|
def self.from_string(str)
|
|
|
|
data = []
|
2009-01-12 15:14:48 +00:00
|
|
|
BYTE_ORDER.each_with_index { |string_position, data_index|
|
|
|
|
data[data_index] = str[string_position * 2, 2].to_i(16)
|
|
|
|
}
|
|
|
|
self.new(data)
|
2009-01-09 18:34:30 +00:00
|
|
|
end
|
|
|
|
|
2008-12-09 17:35:03 +00:00
|
|
|
# +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)
|
|
|
|
end
|
|
|
|
|
|
|
|
def eql?(other)
|
|
|
|
@data == other.to_a
|
|
|
|
end
|
|
|
|
alias_method :==, :eql?
|
|
|
|
|
|
|
|
def to_a
|
|
|
|
@data.dup
|
2008-12-02 01:01:13 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
2009-01-12 15:14:48 +00:00
|
|
|
str = ' ' * 24
|
|
|
|
BYTE_ORDER.each_with_index { |string_position, data_index|
|
|
|
|
str[string_position * 2, 2] = '%02x' % @data[data_index]
|
|
|
|
}
|
|
|
|
str
|
2008-12-02 01:01:13 +00:00
|
|
|
end
|
2008-12-08 21:41:52 +00:00
|
|
|
|
2008-12-17 16:43:08 +00:00
|
|
|
# (Would normally be private, but isn't so we can test it.)
|
2008-12-09 17:35:03 +00:00
|
|
|
def generate_id(t=nil)
|
|
|
|
t ||= 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.rewind
|
|
|
|
buf.to_a.dup
|
|
|
|
end
|
|
|
|
|
2008-12-17 16:43:08 +00:00
|
|
|
# (Would normally be private, but isn't so we can test it.)
|
2008-12-09 17:35:03 +00:00
|
|
|
def index_for_time(t)
|
|
|
|
LOCK.mu_synchronize {
|
|
|
|
if t != @@index_time
|
|
|
|
@@index = 0
|
|
|
|
@@index_time = t
|
|
|
|
end
|
|
|
|
retval = @@index
|
|
|
|
@@index += 1
|
|
|
|
retval
|
|
|
|
}
|
2008-12-06 21:17:19 +00:00
|
|
|
end
|
2008-12-09 17:35:03 +00:00
|
|
|
|
2008-12-02 01:01:13 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2009-01-06 15:47:29 +00:00
|
|
|
end
|