moped 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of moped might be problematic. Click here for more details.

@@ -6,83 +6,262 @@ module Moped
6
6
  class ObjectId
7
7
  include Comparable
8
8
 
9
- class << self
10
- def from_string(string)
11
- raise Errors::InvalidObjectId.new(string) unless legal?(string)
12
- from_data [string].pack("H*")
13
- end
14
-
15
- def from_time(time)
16
- from_data [time.to_i].pack("Nx8")
17
- end
18
-
19
- def legal?(str)
20
- /\A\h{24}\Z/ === str.to_s
21
- end
22
-
23
- def from_data(data)
24
- id = allocate
25
- id.send(:data=, data)
26
- id
27
- end
9
+ # Serialize the object id to its raw bytes.
10
+ #
11
+ # @example Serialize the object id.
12
+ # object_id.__bson_dump__("", "_id")
13
+ #
14
+ # @param [ String ] io The raw bytes to write to.
15
+ # @param [ String ] key The field name.
16
+ #
17
+ # @since 1.0.0
18
+ def __bson_dump__(io, key)
19
+ io << Types::OBJECT_ID
20
+ io << key.to_bson_cstring
21
+ io << data
28
22
  end
29
23
 
24
+ # Check equality on the object.
25
+ #
26
+ # @example Check equality.
27
+ # object === other
28
+ #
29
+ # @param [ Object ] other The object to check against.
30
+ #
31
+ # @return [ true, false ] If the objects are equal.
32
+ #
33
+ # @since 1.0.0
30
34
  def ===(other)
31
35
  return to_str === other.to_str if other.respond_to?(:to_str)
32
36
  super
33
37
  end
34
38
 
39
+ # Check equality on the object.
40
+ #
41
+ # @example Check equality.
42
+ # object == other
43
+ #
44
+ # @param [ Object ] other The object to check against.
45
+ #
46
+ # @return [ true, false ] If the objects are equal.
47
+ #
48
+ # @since 1.0.0
49
+ def ==(other)
50
+ BSON::ObjectId === other && data == other.data
51
+ end
52
+ alias :eql? :==
53
+
54
+ # Compare this object with another object, used in sorting.
55
+ #
56
+ # @example Compare the two objects.
57
+ # object <=> other
58
+ #
59
+ # @param [ Object ] other The object to compare to.
60
+ #
61
+ # @return [ Integer ] The result of the comparison.
62
+ #
63
+ # @since 1.0.0
64
+ def <=>(other)
65
+ data <=> other.data
66
+ end
67
+
68
+ # Get the raw data (bytes) for the object id.
69
+ #
70
+ # @example Get the raw data.
71
+ # object_id.data
72
+ #
73
+ # @return [ String ] The raw bytes.
74
+ #
75
+ # @since 1.0.0
35
76
  def data
36
77
  # If @data is defined, then we know we've been loaded in some
37
78
  # non-standard way, so we attempt to repair the data.
38
79
  repair! @data if defined? @data
39
-
40
80
  @raw_data ||= @@generator.next
41
81
  end
42
82
 
43
- def ==(other)
44
- BSON::ObjectId === other && data == other.data
45
- end
46
- alias eql? ==
47
-
48
- def <=>(other)
49
- data <=> other.data
83
+ # Return the UTC time at which this ObjectId was generated. This may
84
+ # be used instread of a created_at timestamp since this information
85
+ # is always encoded in the object id.
86
+ #
87
+ # @example Get the generation time.
88
+ # object_id.generation_time
89
+ #
90
+ # @return [ Time ] The time the id was generated.
91
+ #
92
+ # @since 1.0.0
93
+ def generation_time
94
+ Time.at(data.unpack("N")[0]).utc
50
95
  end
51
96
 
97
+ # Gets the hash code for the object.
98
+ #
99
+ # @example Get the hash code.
100
+ # object.hash
101
+ #
102
+ # @return [ Fixnum ] The hash code.
103
+ #
104
+ # @since 1.0.0
52
105
  def hash
53
106
  data.hash
54
107
  end
55
108
 
56
- def to_s
57
- data.unpack("H*")[0]
58
- end
59
- alias :to_str :to_s
60
-
109
+ # Gets the string inspection for the object.
110
+ #
111
+ # @example Get the string inspection.
112
+ # object.inspect
113
+ #
114
+ # @return [ String ] The inspection.
115
+ #
116
+ # @since 1.0.0
61
117
  def inspect
62
118
  to_s.inspect
63
119
  end
64
120
 
121
+ # Dump the object for use in a marshal dump.
122
+ #
123
+ # @example Dump the object.
124
+ # object.marshal_dump
125
+ #
126
+ # @return [ String ] The dumped object.
127
+ #
128
+ # @since 1.0.0
129
+ def marshal_dump
130
+ data
131
+ end
132
+
133
+ # Load the object from the marshal dump.
134
+ #
135
+ # @example Load the object.
136
+ # object.marshal_load("")
137
+ #
138
+ # @param [ String ] data The raw data.
139
+ #
140
+ # @since 1.0.0
141
+ def marshal_load(data)
142
+ self.data = data
143
+ end
144
+
145
+ # Convert the object to a JSON string.
146
+ #
147
+ # @example Convert to a JSON string.
148
+ # obejct.to_json
149
+ #
150
+ # @return [ String ] The object as JSON.
151
+ #
152
+ # @since 1.0.0
65
153
  def to_json(*args)
66
154
  "{\"$oid\": \"#{to_s}\"}"
67
155
  end
68
156
 
69
- # Return the UTC time at which this ObjectId was generated. This may
70
- # be used instread of a created_at timestamp since this information
71
- # is always encoded in the object id.
72
- def generation_time
73
- Time.at(data.unpack("N")[0]).utc
157
+ # Get the string representation of the object.
158
+ #
159
+ # @example Get the string representation.
160
+ # object.to_s
161
+ #
162
+ # @return [ String ] The string representation.
163
+ #
164
+ # @since 1.0.0
165
+ def to_s
166
+ data.unpack("H*")[0].force_encoding(UTF8_ENCODING)
167
+ end
168
+ alias :to_str :to_s
169
+
170
+ private
171
+
172
+ # Private interface for setting the internal data for an object id.
173
+ def data=(data)
174
+ @raw_data = data
175
+ end
176
+
177
+ # Attempts to repair ObjectId data marshalled in previous formats.
178
+ #
179
+ # The first check covers an ObjectId generated by the mongo-ruby-driver.
180
+ #
181
+ # The second check covers an ObjectId generated by moped before a custom
182
+ # marshal strategy was added.
183
+ def repair!(data)
184
+ if data.is_a?(Array) && data.size == 12
185
+ self.data = data.pack("C*")
186
+ elsif data.is_a?(String) && data.size == 12
187
+ self.data = data
188
+ else
189
+ raise TypeError, "Could not convert #{data.inspect} into an ObjectId"
190
+ end
74
191
  end
75
192
 
76
193
  class << self
194
+
77
195
  def __bson_load__(io)
78
196
  from_data(io.read(12))
79
197
  end
80
- end
81
198
 
82
- def __bson_dump__(io, key)
83
- io << Types::OBJECT_ID
84
- io << key.to_bson_cstring
85
- io << data
199
+ # Create a new object id from a string.
200
+ #
201
+ # @example Create an object id from the string.
202
+ # Moped::BSON::ObjectId.from_string(id)
203
+ #
204
+ # @param [ String ] string The string to create from.
205
+ #
206
+ # @return [ ObjectId ] The new object id.
207
+ #
208
+ # @since 1.0.0
209
+ def from_string(string)
210
+ raise Errors::InvalidObjectId.new(string) unless legal?(string)
211
+ from_data [string].pack("H*")
212
+ end
213
+
214
+ # Create a new object id from a time.
215
+ #
216
+ # @example Create an object id from a time.
217
+ # Moped::BSON::ObjectId.from_id(time)
218
+ #
219
+ # @example Create an object id from a time, ensuring uniqueness.
220
+ # Moped::BSON::ObjectId.from_id(time, unique: true)
221
+ #
222
+ # @param [ Time ] time The time to generate from.
223
+ # @param [ Hash ] options The options.
224
+ #
225
+ # @option options [ true, false ] :unique Whether the id should be
226
+ # unique.
227
+ #
228
+ # @return [ ObjectId ] The new object id.
229
+ #
230
+ # @since 1.0.0
231
+ def from_time(time, options = nil)
232
+ unique = (options || {})[:unique]
233
+ from_data(unique ? @@generator.next(time.to_i) : [ time.to_i ].pack("Nx8"))
234
+ end
235
+
236
+ # Determine if the string is a legal object id.
237
+ #
238
+ # @example Is the string a legal object id?
239
+ # Moped::BSON::ObjectId.legal?(string)
240
+ #
241
+ # @param [ String ] The string to test.
242
+ #
243
+ # @return [ true, false ] If the string is legal.
244
+ #
245
+ # @since 1.0.0
246
+ def legal?(string)
247
+ /\A\h{24}\Z/ === string.to_s
248
+ end
249
+
250
+ # Create a new object id from some raw data.
251
+ #
252
+ # @example Create an object id from raw data.
253
+ # Moped::BSON::ObjectId.from_data(data)
254
+ #
255
+ # @param [ String ] data The raw bytes.
256
+ #
257
+ # @return [ ObjectId ] The new object id.
258
+ #
259
+ # @since 1.0.0
260
+ def from_data(data)
261
+ id = allocate
262
+ id.send(:data=, data)
263
+ id
264
+ end
86
265
  end
87
266
 
88
267
  # @api private
@@ -98,7 +277,7 @@ module Moped
98
277
 
99
278
  # Return object id data based on the current time, incrementing the
100
279
  # object id counter.
101
- def next
280
+ def next(time = nil)
102
281
  @mutex.lock
103
282
  begin
104
283
  counter = @counter = (@counter + 1) % 0xFFFFFF
@@ -106,7 +285,7 @@ module Moped
106
285
  @mutex.unlock rescue nil
107
286
  end
108
287
 
109
- generate(Time.new.to_i, counter)
288
+ generate(time || Time.new.to_i, counter)
110
289
  end
111
290
 
112
291
  # Generate object id data for a given time using the provided +counter+.
@@ -117,39 +296,6 @@ module Moped
117
296
  end
118
297
 
119
298
  @@generator = Generator.new
120
-
121
- # @private
122
- def marshal_dump
123
- data
124
- end
125
-
126
- # @private
127
- def marshal_load(data)
128
- self.data = data
129
- end
130
-
131
- private
132
-
133
- # Attempts to repair ObjectId data marshalled in previous formats.
134
- #
135
- # The first check covers an ObjectId generated by the mongo-ruby-driver.
136
- #
137
- # The second check covers an ObjectId generated by moped before a custom
138
- # marshal strategy was added.
139
- def repair!(data)
140
- if data.is_a?(Array) && data.size == 12
141
- self.data = data.pack("C*")
142
- elsif data.is_a?(String) && data.size == 12
143
- self.data = data
144
- else
145
- raise TypeError, "Could not convert #{data.inspect} into an ObjectId"
146
- end
147
- end
148
-
149
- # Private interface for setting the internal data for an object id.
150
- def data=(data)
151
- @raw_data = data
152
- end
153
299
  end
154
300
  end
155
301
  end
@@ -1,15 +1,38 @@
1
1
  module Moped
2
2
  module BSON
3
+
4
+ # A time representation in BSON.
3
5
  class Timestamp < Struct.new(:seconds, :increment)
6
+
7
+ # Serialize the time to the stream.
8
+ #
9
+ # @example Serialize the time.
10
+ # time.__bson_dump__("", "created_at")
11
+ #
12
+ # @param [ String ] io The raw bytes.
13
+ # @param [ String ] key The field name.
14
+ #
15
+ # @since 1.0.0
16
+ def __bson_dump__(io, key)
17
+ io << [17, key, increment, seconds].pack('cZ*l2')
18
+ end
19
+
4
20
  class << self
21
+
22
+ # Deserialize the timestamp to an object.
23
+ #
24
+ # @example Deserialize the time.
25
+ # Moped::BSON::Timestamp.__bson_load__(string)
26
+ #
27
+ # @param [ String ] io The raw bytes.
28
+ #
29
+ # @return [ Timestamp ] The time.
30
+ #
31
+ # @since 1.0.0
5
32
  def __bson_load__(io)
6
33
  new(*io.read(8).unpack('l2').reverse)
7
34
  end
8
35
  end
9
-
10
- def __bson_dump__(io, key)
11
- io << [17, key, increment, seconds].pack('cZ*l2')
12
- end
13
36
  end
14
37
  end
15
38
  end
@@ -1,20 +1,21 @@
1
1
  module Moped
2
2
  module BSON
3
3
 
4
- # @private
4
+ # Various BSON type behaviour.
5
5
  module Types
6
+
6
7
  class CodeWithScope
8
+
7
9
  def self.__bson_load__(io)
8
10
  io.read 4 # swallow the length
9
-
10
11
  code = io.read(*io.read(4).unpack(INT32_PACK)).from_utf8_binary.chop!
11
12
  scope = BSON::Document.deserialize(io)
12
-
13
- Code.new code, scope
13
+ Code.new(code, scope)
14
14
  end
15
15
  end
16
16
 
17
17
  class Integer64
18
+
18
19
  def self.__bson_load__(io)
19
20
  io.read(8).unpack(INT64_PACK)[0]
20
21
  end
@@ -61,7 +62,6 @@ module Moped
61
62
  MIN_KEY = 255.chr.freeze
62
63
 
63
64
  TRUE = 1.chr.freeze
64
-
65
65
  end
66
66
  end
67
67
  end
data/lib/moped/cluster.rb CHANGED
@@ -100,6 +100,7 @@ module Moped
100
100
  def initialize(hosts, options)
101
101
  @seeds = hosts
102
102
  @nodes = hosts.map { |host| Node.new(host, options) }
103
+ @peers = []
103
104
 
104
105
  @options = {
105
106
  down_interval: 30,
@@ -135,7 +136,9 @@ module Moped
135
136
 
136
137
  # Now return all the nodes that are available and participating in the
137
138
  # replica set.
138
- available.reject { |node| node.down? || (!opts[:include_arbiters] && node.arbiter?) }
139
+ available.reject do |node|
140
+ node.down? || !member?(node) || (!opts[:include_arbiters] && node.arbiter?)
141
+ end
139
142
  end
140
143
 
141
144
  # Refreshes information for each of the nodes provided. The node list
@@ -170,10 +173,11 @@ module Moped
170
173
  # This node is good, so add it to the list of nodes to return.
171
174
  refreshed_nodes << node unless refreshed_nodes.include?(node)
172
175
 
173
- # Now refresh any newly discovered peer nodes.
174
- (node.peers - @nodes).each(&refresh_node) if node.peers
176
+ # Now refresh any newly discovered peer nodes - this will also
177
+ # remove nodes that are not included in the peer list.
178
+ refresh_peers(node, &refresh_node)
175
179
  rescue Errors::ConnectionFailure
176
- # We couldn't connect to the node, so don't do anything with it.
180
+ # We couldn't connect to the node.
177
181
  end
178
182
  end
179
183
  end
@@ -273,5 +277,18 @@ module Moped
273
277
  def initialize_copy(_)
274
278
  @nodes = @nodes.map(&:dup)
275
279
  end
280
+
281
+ def member?(node)
282
+ @peers.empty? || @peers.include?(node)
283
+ end
284
+
285
+ def refresh_peers(node, &block)
286
+ peers = node.peers
287
+ return if peers.empty?
288
+ peers.each do |node|
289
+ block.call(node) unless @nodes.include?(node)
290
+ @peers.push(node) unless peers.include?(node)
291
+ end
292
+ end
276
293
  end
277
294
  end