mongo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ %w(get_more_message insert_message kill_cursors_message message_header
2
+ msg_message query_message remove_message update_message).each { |f|
3
+ require "mongo/message/#{f}"
4
+ }
@@ -0,0 +1,21 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class GetMoreMessage < Message
9
+
10
+ def initialize(db_name, collection_name, cursor)
11
+ super(OP_GET_MORE)
12
+ write_int(0)
13
+ write_string("#{db_name}.#{collection_name}")
14
+ write_int(0) # num to return; leave it up to the db for now
15
+ write_long(cursor)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,19 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class InsertMessage < Message
9
+
10
+ def initialize(db_name, collection_name, *objs)
11
+ super(OP_INSERT)
12
+ write_int(0)
13
+ write_string("#{db_name}.#{collection_name}")
14
+ objs.each { |o| write_doc(o) }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class KillCursorsMessage < Message
9
+
10
+ def initialize(*cursors)
11
+ super(OP_KILL_CURSORS)
12
+ write_int(0)
13
+ write_int(cursors.length)
14
+ cursors.each { |c| write_long c }
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,68 @@
1
+ require 'mongo/util/bson'
2
+ require 'mongo/util/byte_buffer'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class Message
9
+
10
+ HEADER_SIZE = 16 # size, id, response_to, opcode
11
+
12
+ @@class_req_id = 0
13
+
14
+ attr_reader :buf # for testing
15
+
16
+ def initialize(op)
17
+ @op = op
18
+ @message_length = HEADER_SIZE
19
+ @data_length = 0
20
+ @request_id = (@@class_req_id += 1)
21
+ @response_id = 0
22
+ @buf = ByteBuffer.new
23
+
24
+ @buf.put_int(16) # holder for length
25
+ @buf.put_int(@request_id)
26
+ @buf.put_int(0) # response_to
27
+ @buf.put_int(op)
28
+ end
29
+
30
+ def write_int(i)
31
+ @buf.put_int(i)
32
+ update_message_length
33
+ end
34
+
35
+ def write_long(i)
36
+ @buf.put_long(i)
37
+ update_message_length
38
+ end
39
+
40
+ def write_string(s)
41
+ BSON.serialize_cstr(@buf, s)
42
+ update_message_length
43
+ end
44
+
45
+ def write_doc(hash)
46
+ @buf.put_array(BSON.new.serialize(hash).to_a)
47
+ update_message_length
48
+ end
49
+
50
+ def to_a
51
+ @buf.to_a
52
+ end
53
+
54
+ def dump
55
+ @buf.dump
56
+ end
57
+
58
+ # Do not call. Private, but kept public for testing.
59
+ def update_message_length
60
+ pos = @buf.position
61
+ @buf.put_int(@buf.size, 0)
62
+ @buf.position = pos
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,34 @@
1
+ require 'mongo/util/byte_buffer'
2
+
3
+ module XGen
4
+ module Mongo
5
+ module Driver
6
+
7
+ class MessageHeader
8
+
9
+ HEADER_SIZE = 16
10
+
11
+ def initialize()
12
+ @buf = ByteBuffer.new
13
+ end
14
+
15
+ def read_header(socket)
16
+ @buf.rewind
17
+ @buf.put_array(socket.recv(HEADER_SIZE).unpack("C*"))
18
+ raise "Short read for DB response header: expected #{HEADER_SIZE} bytes, saw #{@buf.size}" unless @buf.size == HEADER_SIZE
19
+ @buf.rewind
20
+ @size = @buf.get_int
21
+ @request_id = @buf.get_int
22
+ @response_to = @buf.get_int
23
+ @op = @buf.get_int
24
+ self
25
+ end
26
+
27
+ def dump
28
+ @buf.dump
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+
@@ -0,0 +1,17 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class MsgMessage < Message
9
+
10
+ def initialize(msg)
11
+ super(OP_MSG)
12
+ write_string(msg)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module XGen
2
+ module Mongo
3
+ module Driver
4
+ OP_REPLY = 1 # reply. responseTo is set.
5
+ OP_MSG = 1000 # generic msg command followed by a string
6
+ OP_UPDATE = 2001 # update object
7
+ OP_INSERT = 2002
8
+ # GET_BY_OID = 2003
9
+ OP_QUERY = 2004
10
+ OP_GET_MORE = 2005
11
+ OP_DELETE = 2006
12
+ OP_KILL_CURSORS = 2007
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,45 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+ require 'mongo/util/ordered_hash'
4
+
5
+ module XGen
6
+ module Mongo
7
+ module Driver
8
+
9
+ class QueryMessage < Message
10
+
11
+ def initialize(db_name, collection_name, query)
12
+ super(OP_QUERY)
13
+ write_int(0)
14
+ write_string("#{db_name}.#{collection_name}")
15
+ write_int(query.number_to_skip)
16
+ write_int(query.number_to_return)
17
+ sel = query.selector
18
+ if query.order_by && query.order_by.length > 0
19
+ sel = OrderedHash.new
20
+ sel['query'] = query.selector
21
+ sel['orderby'] = case query.order_by
22
+ when String
23
+ {query.order_by => 1}
24
+ when Array
25
+ h = OrderedHash.new
26
+ query.order_by.each { |ob| h[ob] = 1 }
27
+ h
28
+ when Hash # Should be an ordered hash, but this message doesn't care
29
+ query.order_by
30
+ else
31
+ raise "illegal order_by: is a #{query.order_by.class.name}, must be String, Array, Hash, or OrderedHash"
32
+ end
33
+
34
+ end
35
+ write_doc(sel)
36
+ write_doc(query.fields) if query.fields
37
+ end
38
+
39
+ def first_key(key)
40
+ @first_key = key
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,20 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class RemoveMessage < Message
9
+
10
+ def initialize(db_name, collection_name, sel)
11
+ super(OP_DELETE)
12
+ write_int(0)
13
+ write_string("#{db_name}.#{collection_name}")
14
+ write_int(0) # flags?
15
+ write_doc(sel)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ require 'mongo/message/message'
2
+ require 'mongo/message/opcodes'
3
+
4
+ module XGen
5
+ module Mongo
6
+ module Driver
7
+
8
+ class UpdateMessage < Message
9
+
10
+ def initialize(db_name, collection_name, sel, obj, repsert)
11
+ super(OP_UPDATE)
12
+ write_int(0)
13
+ write_string("#{db_name}.#{collection_name}")
14
+ write_int(repsert ? 1 : 0) # 1 if a repsert operation (upsert)
15
+ write_doc(sel)
16
+ write_doc(obj)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify it
5
+ # under the terms of the GNU Affero General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful, but WITHOUT
9
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
11
+ # for more details.
12
+ #
13
+ # You should have received a copy of the GNU Affero General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
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
+ # Host default is 'localhost', port default is DEFAULT_PORT.
29
+ def initialize(host='localhost', port=DEFAULT_PORT)
30
+ @host, @port = host, port
31
+ end
32
+
33
+ # Return the XGen::Mongo::Driver::DB named +db_name+.
34
+ def db(db_name)
35
+ XGen::Mongo::Driver::DB.new(db_name, @host, @port)
36
+ end
37
+
38
+ # Not implemented.
39
+ def clone_database(from)
40
+ raise "not implemented"
41
+ end
42
+
43
+ # Not implemented.
44
+ def copy_database(from_host, from_db, to_db)
45
+ raise "not implemented"
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+ end
52
+
@@ -0,0 +1,107 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify it
5
+ # under the terms of the GNU Affero General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful, but WITHOUT
9
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
11
+ # for more details.
12
+ #
13
+ # You should have received a copy of the GNU Affero General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
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
+ LOCK = Object.new
51
+ LOCK.extend Mutex_m
52
+
53
+ @@index_time = Time.new.to_i
54
+ @@index = 0
55
+
56
+ # +data+ is an array of bytes. If nil, a new id will be generated.
57
+ # The time +t+ is only used for testing; leave it nil.
58
+ def initialize(data=nil, t=nil)
59
+ @data = data || generate_id(t)
60
+ end
61
+
62
+ def eql?(other)
63
+ @data == other.to_a
64
+ end
65
+ alias_method :==, :eql?
66
+
67
+ def to_a
68
+ @data.dup
69
+ end
70
+
71
+ def to_s
72
+ @data.collect { |b| '%02x' % b }.join
73
+ end
74
+
75
+ # (Would normally be private, but isn't so we can test it.)
76
+ def generate_id(t=nil)
77
+ t ||= Time.new.to_i
78
+ buf = ByteBuffer.new
79
+ buf.put_int(t & 0xffffffff)
80
+ buf.put_array(MACHINE)
81
+ buf.put_array(PID)
82
+ i = index_for_time(t)
83
+ buf.put(i & 0xff)
84
+ buf.put((i >> 8) & 0xff)
85
+ buf.put((i >> 16) & 0xff)
86
+
87
+ buf.rewind
88
+ buf.to_a.dup
89
+ end
90
+
91
+ # (Would normally be private, but isn't so we can test it.)
92
+ def index_for_time(t)
93
+ LOCK.mu_synchronize {
94
+ if t != @@index_time
95
+ @@index = 0
96
+ @@index_time = t
97
+ end
98
+ retval = @@index
99
+ @@index += 1
100
+ retval
101
+ }
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+ end