Module: NoBrainer::Document::PrimaryKey::Generator
- Defined in:
- lib/no_brainer/document/primary_key/generator.rb
Defined Under Namespace
Classes: Retry
Constant Summary collapse
- BASE_TABLE =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".freeze
- TIME_OFFSET =
Time.utc(2014, 01, 01).to_i
- TIMESTAMP_BITS =
30 bits timestamp with 1s resolution -> We overflow in year 2048. Good enough. Math.log(Time.parse(‘2048-01-01’).to_f - TIME_OFFSET)/Math.log(2) = 29.999
30
- SEQUENCE_BITS =
14 bits of sequence number. max 16k values per 1s slices. We want something >10k because we want to be able to do high speed inserts on a single process for future benchmarks.
14
- MACHINE_ID_BITS =
24 bits of machine id 0.1% of chance to have a collision with 183 servers: Math.sqrt(-2*(2**24)*Math.log(0.999)) = 183.2 1% of chance to have a collision with ~580 servers. When using more than 500 machines, it’s therefore a good idea to set the machine_id manually to avoid collisions. XXX This is referenced in nobrainer/config.rb#default_machine_id
24
- PID_BITS =
15 bits for the current pid. We wouldn’t need it if the sequence number was on a piece of shared memory :)
15
- ID_STR_LENGTH =
Total: 83 bits With 14 digits in [A-Za-z0-9], we can represent 83 bits: Math.log(62**14)/Math.log(2) = 83.35
14
- TIMESTAMP_MASK =
(1 << TIMESTAMP_BITS)-1
- SEQUENCE_MASK =
(1 << SEQUENCE_BITS)-1
- MACHINE_ID_MASK =
(1 << MACHINE_ID_BITS)-1
- PID_MASK =
(1 << PID_BITS)-1
- PID_SHIFT =
0
- MACHINE_ID_SHIFT =
PID_SHIFT + PID_BITS
- SEQUENCE_SHIFT =
MACHINE_ID_SHIFT + MACHINE_ID_BITS
- TIMESTAMP_SHIFT =
SEQUENCE_SHIFT + SEQUENCE_BITS
Class Method Summary collapse
Class Method Details
._generate ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/no_brainer/document/primary_key/generator.rb', line 45 def self._generate = (Time.now.to_i - TIME_OFFSET) & TIMESTAMP_MASK unless @last_timestamp == # more noise is better in the ID, but we prefer to avoid # wrapping the sequences so that Model.last on a single # machine returns the latest created document. @first_sequence = sequence = rand(SEQUENCE_MASK/2) @last_timestamp = else sequence = (@sequence + 1) & SEQUENCE_MASK raise Retry if @first_sequence == sequence end @sequence = sequence machine_id = NoBrainer::Config.machine_id & MACHINE_ID_MASK pid = Process.pid & PID_MASK ( << TIMESTAMP_SHIFT) | (sequence << SEQUENCE_SHIFT) | (machine_id << MACHINE_ID_SHIFT) | (pid << PID_SHIFT) rescue Retry sleep 0.1 retry end |
.convert_to_alphanum(id) ⇒ Object
71 72 73 74 75 76 77 78 |
# File 'lib/no_brainer/document/primary_key/generator.rb', line 71 def self.convert_to_alphanum(id) result = [] until id.zero? id, r = id.divmod(BASE_TABLE.size) result << BASE_TABLE[r] end result.reverse.join.rjust(ID_STR_LENGTH, BASE_TABLE[0]) end |
.field_type ⇒ Object
85 86 87 |
# File 'lib/no_brainer/document/primary_key/generator.rb', line 85 def self.field_type String end |
.generate ⇒ Object
81 82 83 |
# File 'lib/no_brainer/document/primary_key/generator.rb', line 81 def self.generate convert_to_alphanum(@lock.synchronize { _generate }) end |