animehunter-mongo 0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/README.rdoc +311 -0
  2. data/Rakefile +62 -0
  3. data/bin/bson_benchmark.rb +59 -0
  4. data/bin/mongo_console +21 -0
  5. data/bin/run_test_script +19 -0
  6. data/bin/standard_benchmark +109 -0
  7. data/examples/admin.rb +41 -0
  8. data/examples/benchmarks.rb +42 -0
  9. data/examples/blog.rb +76 -0
  10. data/examples/capped.rb +23 -0
  11. data/examples/cursor.rb +47 -0
  12. data/examples/gridfs.rb +87 -0
  13. data/examples/index_test.rb +125 -0
  14. data/examples/info.rb +30 -0
  15. data/examples/queries.rb +69 -0
  16. data/examples/simple.rb +23 -0
  17. data/examples/strict.rb +34 -0
  18. data/examples/types.rb +40 -0
  19. data/lib/mongo.rb +19 -0
  20. data/lib/mongo/admin.rb +87 -0
  21. data/lib/mongo/collection.rb +235 -0
  22. data/lib/mongo/cursor.rb +227 -0
  23. data/lib/mongo/db.rb +538 -0
  24. data/lib/mongo/gridfs.rb +16 -0
  25. data/lib/mongo/gridfs/chunk.rb +96 -0
  26. data/lib/mongo/gridfs/grid_store.rb +468 -0
  27. data/lib/mongo/message.rb +20 -0
  28. data/lib/mongo/message/get_more_message.rb +37 -0
  29. data/lib/mongo/message/insert_message.rb +35 -0
  30. data/lib/mongo/message/kill_cursors_message.rb +36 -0
  31. data/lib/mongo/message/message.rb +84 -0
  32. data/lib/mongo/message/message_header.rb +50 -0
  33. data/lib/mongo/message/msg_message.rb +33 -0
  34. data/lib/mongo/message/opcodes.rb +32 -0
  35. data/lib/mongo/message/query_message.rb +77 -0
  36. data/lib/mongo/message/remove_message.rb +36 -0
  37. data/lib/mongo/message/update_message.rb +37 -0
  38. data/lib/mongo/mongo.rb +164 -0
  39. data/lib/mongo/query.rb +119 -0
  40. data/lib/mongo/types/binary.rb +42 -0
  41. data/lib/mongo/types/code.rb +34 -0
  42. data/lib/mongo/types/dbref.rb +37 -0
  43. data/lib/mongo/types/objectid.rb +137 -0
  44. data/lib/mongo/types/regexp_of_holding.rb +44 -0
  45. data/lib/mongo/types/undefined.rb +31 -0
  46. data/lib/mongo/util/bson.rb +534 -0
  47. data/lib/mongo/util/byte_buffer.rb +167 -0
  48. data/lib/mongo/util/ordered_hash.rb +96 -0
  49. data/lib/mongo/util/xml_to_ruby.rb +107 -0
  50. data/mongo-ruby-driver.gemspec +99 -0
  51. data/tests/mongo-qa/_common.rb +8 -0
  52. data/tests/mongo-qa/admin +26 -0
  53. data/tests/mongo-qa/capped +22 -0
  54. data/tests/mongo-qa/count1 +18 -0
  55. data/tests/mongo-qa/dbs +22 -0
  56. data/tests/mongo-qa/find +10 -0
  57. data/tests/mongo-qa/find1 +15 -0
  58. data/tests/mongo-qa/gridfs_in +16 -0
  59. data/tests/mongo-qa/gridfs_out +17 -0
  60. data/tests/mongo-qa/indices +49 -0
  61. data/tests/mongo-qa/remove +25 -0
  62. data/tests/mongo-qa/stress1 +35 -0
  63. data/tests/mongo-qa/test1 +11 -0
  64. data/tests/mongo-qa/update +18 -0
  65. data/tests/test_admin.rb +69 -0
  66. data/tests/test_bson.rb +246 -0
  67. data/tests/test_byte_buffer.rb +69 -0
  68. data/tests/test_chunk.rb +84 -0
  69. data/tests/test_cursor.rb +121 -0
  70. data/tests/test_db.rb +160 -0
  71. data/tests/test_db_api.rb +701 -0
  72. data/tests/test_db_connection.rb +18 -0
  73. data/tests/test_grid_store.rb +284 -0
  74. data/tests/test_message.rb +35 -0
  75. data/tests/test_mongo.rb +78 -0
  76. data/tests/test_objectid.rb +98 -0
  77. data/tests/test_ordered_hash.rb +129 -0
  78. data/tests/test_round_trip.rb +116 -0
  79. metadata +133 -0
@@ -0,0 +1,37 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mongo/message/message'
18
+ require 'mongo/message/opcodes'
19
+
20
+ module XGen
21
+ module Mongo
22
+ module Driver
23
+
24
+ class UpdateMessage < Message
25
+
26
+ def initialize(db_name, collection_name, sel, obj, repsert)
27
+ super(OP_UPDATE)
28
+ write_int(0)
29
+ write_string("#{db_name}.#{collection_name}")
30
+ write_int(repsert ? 1 : 0) # 1 if a repsert operation (upsert)
31
+ write_doc(sel)
32
+ write_doc(obj)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,164 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mongo/db'
18
+
19
+ module XGen
20
+ module Mongo
21
+ module Driver
22
+
23
+ # Represents a Mongo database server.
24
+ class Mongo
25
+
26
+ DEFAULT_PORT = 27017
27
+
28
+ # Create a Mongo database server instance. You specify either one or a
29
+ # pair of servers. If one, you also say if connecting to a slave is
30
+ # OK. In either case, the host default is "localhost" and port default
31
+ # is DEFAULT_PORT.
32
+ #
33
+ # If you specify a pair, pair_or_host is a hash with two keys :left
34
+ # and :right. Each key maps to either
35
+ # * a server name, in which case port is DEFAULT_PORT
36
+ # * a port number, in which case server is "localhost"
37
+ # * an array containing a server name and a port number in that order
38
+ #
39
+ # +options+ are passed on to each DB instance:
40
+ #
41
+ # :slave_ok :: Only used if one host is specified. If false, when
42
+ # connecting to that host/port a DB object will check to
43
+ # see if the server is the master. If it is not, an error
44
+ # is thrown.
45
+ #
46
+ # :auto_reconnect :: If a DB connection gets closed (for example, we
47
+ # have a server pair and saw the "not master"
48
+ # error, which closes the connection), then
49
+ # automatically try to reconnect to the master or
50
+ # to the single server we have been given. Defaults
51
+ # to +false+.
52
+ #
53
+ # Since that's so confusing, here are a few examples:
54
+ #
55
+ # Mongo.new # localhost, DEFAULT_PORT, !slave
56
+ # Mongo.new("localhost") # localhost, DEFAULT_PORT, !slave
57
+ # Mongo.new("localhost", 3000) # localhost, 3000, slave not ok
58
+ # # localhost, 3000, slave ok
59
+ # Mongo.new("localhost", 3000, :slave_ok => true)
60
+ # # localhost, DEFAULT_PORT, auto reconnect
61
+ # Mongo.new(nil, nil, :auto_reconnect => true)
62
+ #
63
+ # # A pair of servers. DB will always talk to the master. On socket
64
+ # # error or "not master" error, we will auto-reconnect to the
65
+ # # current master.
66
+ # Mongo.new({:left => ["db1.example.com", 3000],
67
+ # :right => "db2.example.com"}, # DEFAULT_PORT
68
+ # nil, :auto_reconnect => true)
69
+ #
70
+ # # Here, :right is localhost/DEFAULT_PORT. No auto-reconnect.
71
+ # Mongo.new({:left => ["db1.example.com", 3000]})
72
+ #
73
+ # When a DB object first connects to a pair, it will find the master
74
+ # instance and connect to that one.
75
+ def initialize(pair_or_host=nil, port=nil, options={})
76
+ @pair = case pair_or_host
77
+ when String
78
+ [[pair_or_host, port ? port.to_i : DEFAULT_PORT]]
79
+ when Hash
80
+ connections = []
81
+ connections << pair_val_to_connection(pair_or_host[:left])
82
+ connections << pair_val_to_connection(pair_or_host[:right])
83
+ connections
84
+ when nil
85
+ [['localhost', DEFAULT_PORT]]
86
+ end
87
+ @options = options
88
+ end
89
+
90
+ # Return the XGen::Mongo::Driver::DB named +db_name+. The slave_ok and
91
+ # auto_reconnect options passed in via #new may be overridden here.
92
+ # See DB#new for other options you can pass in.
93
+ def db(db_name, options={})
94
+ XGen::Mongo::Driver::DB.new(db_name, @pair, @options.merge(options))
95
+ end
96
+
97
+ # Returns a hash containing database names as keys and disk space for
98
+ # each as values.
99
+ def database_info
100
+ doc = single_db_command('admin', :listDatabases => 1)
101
+ h = {}
102
+ doc['databases'].each { |db|
103
+ h[db['name']] = db['sizeOnDisk'].to_i
104
+ }
105
+ h
106
+ end
107
+
108
+ # Returns an array of database names.
109
+ def database_names
110
+ database_info.keys
111
+ end
112
+
113
+ # Not implemented.
114
+ def clone_database(from)
115
+ raise "not implemented"
116
+ end
117
+
118
+ # Not implemented.
119
+ def copy_database(from_host, from_db, to_db)
120
+ raise "not implemented"
121
+ end
122
+
123
+ # Drops the database +name+.
124
+ def drop_database(name)
125
+ single_db_command(name, :dropDatabase => 1)
126
+ end
127
+
128
+ protected
129
+
130
+ # Turns an array containing a host name string and a
131
+ # port number integer into a [host, port] pair array.
132
+ def pair_val_to_connection(a)
133
+ case a
134
+ when nil
135
+ ['localhost', DEFAULT_PORT]
136
+ when String
137
+ [a, DEFAULT_PORT]
138
+ when Integer
139
+ ['localhost', a]
140
+ when Array
141
+ a
142
+ end
143
+ end
144
+
145
+ # Send cmd (a hash, possibly ordered) to the admin database and return
146
+ # the answer. Raises an error unless the return is "ok" (DB#ok?
147
+ # returns +true+).
148
+ def single_db_command(db_name, cmd)
149
+ db = nil
150
+ begin
151
+ db = db(db_name)
152
+ doc = db.db_command(cmd)
153
+ raise "error retrieving database info: #{doc.inspect}" unless db.ok?(doc)
154
+ doc
155
+ ensure
156
+ db.close if db
157
+ end
158
+ end
159
+
160
+ end
161
+ end
162
+ end
163
+ end
164
+
@@ -0,0 +1,119 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mongo/collection'
18
+ require 'mongo/message'
19
+ require 'mongo/types/code'
20
+
21
+ module XGen
22
+ module Mongo
23
+ module Driver
24
+
25
+ # A query against a collection. A query's selector is a hash. See the
26
+ # Mongo documentation for query details.
27
+ class Query
28
+
29
+ attr_accessor :number_to_skip, :number_to_return, :order_by
30
+ # If true, $explain will be set in QueryMessage that uses this query.
31
+ attr_accessor :explain
32
+ # Either +nil+ or a hash (preferably an OrderedHash).
33
+ attr_accessor :hint
34
+ attr_reader :selector # writer defined below
35
+
36
+ # sel :: A hash describing the query. See the Mongo docs for details.
37
+ #
38
+ # return_fields :: If not +nil+, a single field name or an array of
39
+ # field names. Only those fields will be returned.
40
+ # (Called :fields in calls to Collection#find.)
41
+ #
42
+ # number_to_skip :: Number of records to skip before returning
43
+ # records. (Called :offset in calls to
44
+ # Collection#find.) Default is 0.
45
+ #
46
+ # number_to_return :: Max number of records to return. (Called :limit
47
+ # in calls to Collection#find.) Default is 0 (all
48
+ # records).
49
+ #
50
+ # order_by :: If not +nil+, specifies record sort order. May be a
51
+ # String, Hash, OrderedHash, or Array. If a string, the
52
+ # results will be ordered by that field in ascending
53
+ # order. If an array, it should be an array of field names
54
+ # which will all be sorted in ascending order. If a hash,
55
+ # it may be either a regular Hash or an OrderedHash. The
56
+ # keys should be field names, and the values should be 1
57
+ # (ascending) or -1 (descending). Note that if it is a
58
+ # regular Hash then sorting by more than one field
59
+ # probably will not be what you intend because key order
60
+ # is not preserved. (order_by is called :sort in calls to
61
+ # Collection#find.)
62
+ #
63
+ # hint :: If not +nil+, specifies query hint fields. Must be either
64
+ # +nil+ or a hash (preferably an OrderedHash). See
65
+ # Collection#hint.
66
+ def initialize(sel={}, return_fields=nil, number_to_skip=0, number_to_return=0, order_by=nil, hint=nil)
67
+ @number_to_skip, @number_to_return, @order_by, @hint =
68
+ number_to_skip, number_to_return, order_by, hint
69
+ @explain = nil
70
+ self.selector = sel
71
+ self.fields = return_fields
72
+ end
73
+
74
+ # Set query selector hash. If sel is Code/string, it will be used as a
75
+ # $where clause. (See Mongo docs for details.)
76
+ def selector=(sel)
77
+ @selector = case sel
78
+ when nil
79
+ {}
80
+ when Code
81
+ {"$where" => sel}
82
+ when String
83
+ {"$where" => Code.new(sel)}
84
+ when Hash
85
+ sel
86
+ end
87
+ end
88
+
89
+ # Set fields to return. If +val+ is +nil+ or empty, all fields will be
90
+ # returned.
91
+ def fields=(val)
92
+ @fields = val
93
+ @fields = nil if @fields && @fields.empty?
94
+ end
95
+
96
+ def fields
97
+ case @fields
98
+ when String
99
+ {@fields => 1}
100
+ when Array
101
+ if @fields.length == 0
102
+ nil
103
+ else
104
+ h = {}
105
+ @fields.each { |field| h[field] = 1 }
106
+ h
107
+ end
108
+ else # nil, anything else
109
+ nil
110
+ end
111
+ end
112
+
113
+ def contains_special_fields
114
+ (@order_by != nil && @order_by.length > 0) || @explain || @hint
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,42 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mongo/util/byte_buffer'
18
+
19
+ module XGen
20
+ module Mongo
21
+ module Driver
22
+
23
+ # An array of binary bytes with a Mongo subtype value.
24
+ class Binary < ByteBuffer
25
+
26
+ SUBTYPE_BYTES = 0x02
27
+ SUBTYPE_UUID = 0x03
28
+ SUBTYPE_MD5 = 0x05
29
+ SUBTYPE_USER_DEFINED = 0x80
30
+
31
+ # One of the SUBTYPE_* constants. Default is SUBTYPE_BYTES.
32
+ attr_accessor :subtype
33
+
34
+ def initialize(initial_data=[], subtype=SUBTYPE_BYTES)
35
+ super(initial_data)
36
+ @subtype = subtype
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,34 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module XGen
18
+ module Mongo
19
+ module Driver
20
+
21
+ # JavaScript code to be evaluated by MongoDB
22
+ class Code < String
23
+ # Hash mapping identifiers to their values
24
+ attr_accessor :scope
25
+
26
+ def initialize(code, scope={})
27
+ super(code)
28
+ @scope = scope
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ module XGen
18
+ module Mongo
19
+ module Driver
20
+
21
+ class DBRef
22
+
23
+ attr_reader :namespace, :object_id
24
+
25
+ def initialize(namespace, object_id)
26
+ @namespace, @object_id =
27
+ namespace, object_id
28
+ end
29
+
30
+ def to_s
31
+ "ns: #{namespace}, id: #{object_id}"
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,137 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ # ++
16
+
17
+ require 'mutex_m'
18
+ require 'mongo/util/byte_buffer'
19
+
20
+ module XGen
21
+ module Mongo
22
+ module Driver
23
+
24
+ # Implementation of the Babble OID. Object ids are not required by
25
+ # Mongo, but they make certain operations more efficient.
26
+ #
27
+ # The driver does not automatically assign ids to records that are
28
+ # inserted. (An upcoming feature will allow you to give an id "factory"
29
+ # to a database and/or a collection.)
30
+ #
31
+ # 12 bytes
32
+ # ---
33
+ # 0 time
34
+ # 1
35
+ # 2
36
+ # 3
37
+ # 4 machine
38
+ # 5
39
+ # 6
40
+ # 7 pid
41
+ # 8
42
+ # 9 inc
43
+ # 10
44
+ # 11
45
+ class ObjectID
46
+
47
+ MACHINE = ( val = rand(0x1000000); [val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff] )
48
+ PID = ( val = rand(0x10000); [val & 0xff, (val >> 8) & 0xff]; )
49
+
50
+ # The string representation of an OID is different than its internal
51
+ # and BSON byte representations. The BYTE_ORDER here maps
52
+ # internal/BSON byte position (the index in BYTE_ORDER) to the
53
+ # position of the two hex characters representing that byte in the
54
+ # string representation. For example, the 0th BSON byte corresponds to
55
+ # the (0-based) 7th pair of hex chars in the string.
56
+ BYTE_ORDER = [7, 6, 5, 4, 3, 2, 1, 0, 11, 10, 9, 8]
57
+
58
+ LOCK = Object.new
59
+ LOCK.extend Mutex_m
60
+
61
+ @@index_time = Time.new.to_i
62
+ @@index = 0
63
+
64
+ # Given a string representation of an ObjectID, return a new ObjectID
65
+ # with that value.
66
+ def self.from_string(str)
67
+ raise "illegal ObjectID format" unless legal?(str)
68
+ data = []
69
+ BYTE_ORDER.each_with_index { |string_position, data_index|
70
+ data[data_index] = str[string_position * 2, 2].to_i(16)
71
+ }
72
+ self.new(data)
73
+ end
74
+
75
+ def self.legal?(str)
76
+ len = BYTE_ORDER.length * 2
77
+ str =~ /([0-9a-f]+)/i
78
+ match = $1
79
+ str && str.length == len && match == str
80
+ end
81
+
82
+ # +data+ is an array of bytes. If nil, a new id will be generated.
83
+ # The time +t+ is only used for testing; leave it nil.
84
+ def initialize(data=nil, t=nil)
85
+ @data = data || generate_id(t)
86
+ end
87
+
88
+ def eql?(other)
89
+ @data == other.instance_variable_get("@data")
90
+ end
91
+ alias_method :==, :eql?
92
+
93
+ def to_a
94
+ @data.dup
95
+ end
96
+
97
+ def to_s
98
+ str = ' ' * 24
99
+ BYTE_ORDER.each_with_index { |string_position, data_index|
100
+ str[string_position * 2, 2] = '%02x' % @data[data_index]
101
+ }
102
+ str
103
+ end
104
+
105
+ # (Would normally be private, but isn't so we can test it.)
106
+ def generate_id(t=nil)
107
+ t ||= Time.new.to_i
108
+ buf = ByteBuffer.new
109
+ buf.put_int(t & 0xffffffff)
110
+ buf.put_array(MACHINE)
111
+ buf.put_array(PID)
112
+ i = index_for_time(t)
113
+ buf.put(i & 0xff)
114
+ buf.put((i >> 8) & 0xff)
115
+ buf.put((i >> 16) & 0xff)
116
+
117
+ buf.rewind
118
+ buf.to_a.dup
119
+ end
120
+
121
+ # (Would normally be private, but isn't so we can test it.)
122
+ def index_for_time(t)
123
+ LOCK.mu_synchronize {
124
+ if t != @@index_time
125
+ @@index = 0
126
+ @@index_time = t
127
+ end
128
+ retval = @@index
129
+ @@index += 1
130
+ retval
131
+ }
132
+ end
133
+
134
+ end
135
+ end
136
+ end
137
+ end