Module: CouchbaseId::Generator
- Defined in:
- lib/couchbase-id/generator.rb
Overview
- NOTE
-
incr, decr, append, prepend == atomic
Class Method Summary collapse
Instance Method Summary collapse
-
#generate_id ⇒ Object
instance method.
Class Method Details
.included(base) ⇒ Object
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/couchbase-id/generator.rb', line 80 def self.included(base) class << base attr_accessor :__overflow__ attr_accessor :__class_id_generator__ end base.class_eval do # # Best case we have 18446744073709551615 * 18446744073709551615 model entries for each database cluster # and we can always change the cluster id if this limit is reached # define_model_callbacks :save, :create before_save :generate_id before_create :generate_id def self.default_class_id_generator(overflow, count) id = Radix.convert(overflow, B10, B64) + Radix.convert(count, B10, B64) "#{self.design_document}_#{CLUSTER_ID}-#{id}" end # # Override the default hashing function # def self.set_class_id_generator(callback = nil, &block) callback ||= block self.__class_id_generator__ = callback end # # Configure class level variables base.__overflow__ = nil base.__class_id_generator__ = method(:default_class_id_generator) end end |
Instance Method Details
#generate_id ⇒ Object
instance method
36 37 38 39 40 41 42 43 44 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 70 71 72 73 74 75 76 77 78 |
# File 'lib/couchbase-id/generator.rb', line 36 def generate_id if self.id.nil? # # Generate the id (incrementing values as required) # overflow = self.class.__overflow__ ||= self.class.bucket.get("#{self.class.design_document}:#{CLUSTER_ID}:overflow", :quiet => true) # Don't error if not there count = self.class.bucket.incr("#{self.class.design_document}:#{CLUSTER_ID}:count", :create => true) # This models current id count if count == 0 || overflow.nil? overflow ||= 0 overflow += 1 # We shouldn't need to worry about concurrency here due to the size of count # Would require ~18446744073709551615 concurrent writes self.class.bucket.set("#{self.class.design_document}:#{CLUSTER_ID}:overflow", overflow) self.class.__overflow__ = overflow end self.id = self.class.__class_id_generator__.call(overflow, count) # # So an existing id would only be present if: # => something crashed before incrementing the overflow # => this is another request was occurring before the overflow is incremented # # Basically only the overflow should be able to cause issues, we'll increment the count just to be sure # One would hope this code only ever runs under high load during an overflow event # while self.class.bucket.get(self.id, :quiet => true).present? # Set in-case we are here due to a crash (concurrency is not an issue) # Note we are not incrementing the @__overflow__ variable self.class.bucket.set("#{self.class.design_document}:#{CLUSTER_ID}:overflow", overflow + 1) count = self.class.bucket.incr("#{self.class.design_document}:#{CLUSTER_ID}:count") # Increment just in case (attempt to avoid infinite loops) # Reset the overflow if self.class.__overflow__ == overflow self.class.__overflow__ = nil end # Generate the new id self.id = self.class.__class_id_generator__.call(overflow + 1, count) end end end |