tmm1-em-mysql 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/em-mysql.gemspec +21 -0
- data/lib/em/mysql.rb +55 -29
- data/lib/sequel/async.rb +25 -21
- metadata +4 -3
data/em-mysql.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
spec = Gem::Specification.new do |s|
|
2
|
+
s.name = 'em-mysql'
|
3
|
+
s.version = '0.3.0'
|
4
|
+
s.date = '2009-06-23'
|
5
|
+
s.summary = 'Async MySQL client API for Ruby/EventMachine'
|
6
|
+
s.email = "em-mysql@tmm1.net"
|
7
|
+
s.homepage = "http://github.com/tmm1/em-mysql"
|
8
|
+
s.description = 'Async MySQL client API for Ruby/EventMachine'
|
9
|
+
s.has_rdoc = false
|
10
|
+
s.authors = ["Aman Gupta"]
|
11
|
+
s.add_dependency('eventmachine', '>= 0.12.8')
|
12
|
+
|
13
|
+
# git ls-files
|
14
|
+
s.files = %w[
|
15
|
+
README
|
16
|
+
em-mysql.gemspec
|
17
|
+
lib/em/mysql.rb
|
18
|
+
lib/sequel/async.rb
|
19
|
+
test.rb
|
20
|
+
]
|
21
|
+
end
|
data/lib/em/mysql.rb
CHANGED
@@ -1,27 +1,31 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'eventmachine'
|
3
3
|
require 'mysqlplus'
|
4
|
+
require 'fcntl'
|
5
|
+
|
6
|
+
class Mysql
|
7
|
+
def result
|
8
|
+
@cur_result
|
9
|
+
end
|
10
|
+
end
|
4
11
|
|
5
12
|
class EventedMysql < EM::Connection
|
6
13
|
def initialize mysql, opts
|
7
14
|
@mysql = mysql
|
8
15
|
@fd = mysql.socket
|
9
16
|
@opts = opts
|
10
|
-
@
|
11
|
-
|
17
|
+
@current = nil
|
18
|
+
@@queue ||= []
|
12
19
|
@processing = false
|
13
20
|
@connected = true
|
14
21
|
|
15
22
|
log 'mysql connected'
|
23
|
+
make_socket_blocking
|
24
|
+
EM.add_timer(0){ next_query }
|
16
25
|
end
|
17
26
|
attr_reader :processing, :connected, :opts
|
18
27
|
alias :settings :opts
|
19
28
|
|
20
|
-
def connection_completed
|
21
|
-
@connected = true
|
22
|
-
next_query
|
23
|
-
end
|
24
|
-
|
25
29
|
DisconnectErrors = [
|
26
30
|
'query: not connected',
|
27
31
|
'MySQL server has gone away',
|
@@ -30,11 +34,14 @@ class EventedMysql < EM::Connection
|
|
30
34
|
|
31
35
|
def notify_readable
|
32
36
|
log 'readable'
|
33
|
-
if item = @
|
37
|
+
if item = @current
|
38
|
+
@current = nil
|
34
39
|
start, response, sql, cblk, eblk = item
|
35
40
|
log 'mysql response', Time.now-start, sql
|
36
41
|
arg = case response
|
37
42
|
when :raw
|
43
|
+
result = @mysql.get_result
|
44
|
+
@mysql.instance_variable_set('@cur_result', result)
|
38
45
|
@mysql
|
39
46
|
when :select
|
40
47
|
ret = []
|
@@ -64,8 +71,12 @@ class EventedMysql < EM::Connection
|
|
64
71
|
end
|
65
72
|
rescue Mysql::Error => e
|
66
73
|
log 'mysql error', e.message
|
67
|
-
if
|
68
|
-
|
74
|
+
if e.message =~ /Deadlock/
|
75
|
+
@@queue << [response, sql, cblk, eblk]
|
76
|
+
@processing = false
|
77
|
+
next_query
|
78
|
+
elsif DisconnectErrors.include? e.message
|
79
|
+
@@queue << [response, sql, cblk, eblk]
|
69
80
|
return close
|
70
81
|
elsif cb = (eblk || @opts[:on_error])
|
71
82
|
cb.call(e)
|
@@ -101,6 +112,9 @@ class EventedMysql < EM::Connection
|
|
101
112
|
@signature = EM.attach_fd @mysql.socket, true, false
|
102
113
|
log 'mysql connected'
|
103
114
|
EM.instance_variable_get('@conns')[@signature] = self
|
115
|
+
@connected = true
|
116
|
+
make_socket_blocking
|
117
|
+
next_query
|
104
118
|
end
|
105
119
|
end
|
106
120
|
|
@@ -115,7 +129,7 @@ class EventedMysql < EM::Connection
|
|
115
129
|
# # log 'mysql errno', @mysql.errno
|
116
130
|
# rescue
|
117
131
|
# log 'mysql ping failed'
|
118
|
-
#
|
132
|
+
# @@queue << [response, sql, blk]
|
119
133
|
# return close
|
120
134
|
# end
|
121
135
|
|
@@ -124,13 +138,13 @@ class EventedMysql < EM::Connection
|
|
124
138
|
log 'mysql sending', sql
|
125
139
|
@mysql.send_query(sql)
|
126
140
|
else
|
127
|
-
|
141
|
+
@@queue << [response, sql, cblk, eblk]
|
128
142
|
return
|
129
143
|
end
|
130
144
|
rescue Mysql::Error => e
|
131
145
|
log 'mysql error', e.message
|
132
146
|
if DisconnectErrors.include? e.message
|
133
|
-
|
147
|
+
@@queue << [response, sql, cblk, eblk]
|
134
148
|
return close
|
135
149
|
else
|
136
150
|
raise e
|
@@ -138,7 +152,7 @@ class EventedMysql < EM::Connection
|
|
138
152
|
end
|
139
153
|
|
140
154
|
log 'queuing', response, sql
|
141
|
-
@
|
155
|
+
@current = [Time.now, response, sql, cblk, eblk]
|
142
156
|
end
|
143
157
|
|
144
158
|
def close
|
@@ -148,13 +162,23 @@ class EventedMysql < EM::Connection
|
|
148
162
|
# EM.add_timer(0){ close_connection }
|
149
163
|
# close_connection
|
150
164
|
fd = detach
|
165
|
+
@io.close if @io
|
166
|
+
@io = nil
|
151
167
|
log 'detached fd', fd
|
152
168
|
end
|
153
169
|
|
154
170
|
private
|
155
171
|
|
172
|
+
def make_socket_blocking
|
173
|
+
if defined?(Fcntl::F_GETFL)
|
174
|
+
@io = IO.for_fd(@mysql.socket)
|
175
|
+
m = @io.fcntl(Fcntl::F_GETFL, 0)
|
176
|
+
@io.fcntl(Fcntl::F_SETFL, ~Fcntl::O_NONBLOCK & m)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
156
180
|
def next_query
|
157
|
-
if @connected and !@processing and pending =
|
181
|
+
if @connected and !@processing and pending = @@queue.shift
|
158
182
|
response, sql, cblk, eblk = pending
|
159
183
|
execute(sql, response, cblk, eblk)
|
160
184
|
end
|
@@ -205,9 +229,7 @@ class EventedMysql < EM::Connection
|
|
205
229
|
# XXX multi results require multiple callbacks to parse
|
206
230
|
# Mysql::CLIENT_MULTI_RESULTS +
|
207
231
|
# Mysql::CLIENT_MULTI_STATEMENTS +
|
208
|
-
|
209
|
-
# XXX this should check for opts[:compression]
|
210
|
-
Mysql::CLIENT_COMPRESS
|
232
|
+
(opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
|
211
233
|
)
|
212
234
|
|
213
235
|
# increase timeout so mysql server doesn't disconnect us
|
@@ -227,16 +249,6 @@ class EventedMysql < EM::Connection
|
|
227
249
|
# get results for queries
|
228
250
|
conn.query_with_result = true
|
229
251
|
|
230
|
-
# if encoding = opts[:encoding] || opts[:charset]
|
231
|
-
# conn.options(Mysql::SET_CHARSET_NAME, encoding) rescue nil
|
232
|
-
# conn.query("set names '#{encoding}'")
|
233
|
-
# conn.query("set character_set_connection = '#{encoding}'")
|
234
|
-
# conn.query("set character_set_client = '#{encoding}'")
|
235
|
-
# conn.query("set character_set_database = '#{encoding}'")
|
236
|
-
# conn.query("set character_set_server = '#{encoding}'")
|
237
|
-
# conn.query("set character_set_results = '#{encoding}'")
|
238
|
-
# end
|
239
|
-
|
240
252
|
conn
|
241
253
|
rescue Mysql::Error => e
|
242
254
|
if cb = opts[:on_error]
|
@@ -362,7 +374,7 @@ if __FILE__ == $0 and require 'em/spec'
|
|
362
374
|
should 'have raw mode which yields the mysql object' do
|
363
375
|
@mysql.execute('select 1+2 as num', :raw){ |mysql|
|
364
376
|
mysql.should.is_a? Mysql
|
365
|
-
mysql.
|
377
|
+
mysql.result.all_hashes.should == [{'num' => '3'}]
|
366
378
|
done
|
367
379
|
}
|
368
380
|
end
|
@@ -446,6 +458,20 @@ if __FILE__ == $0 and require 'em/spec'
|
|
446
458
|
}
|
447
459
|
end
|
448
460
|
|
461
|
+
should 'allow access to insert_id in raw mode' do
|
462
|
+
SQL.raw('insert into evented_mysql_test (num) values (20), (21), (22)'){ |mysql|
|
463
|
+
mysql.insert_id.should == 4
|
464
|
+
done
|
465
|
+
}
|
466
|
+
end
|
467
|
+
|
468
|
+
should 'allow access to affected_rows in raw mode' do
|
469
|
+
SQL.raw('update evented_mysql_test set num = num + 10'){ |mysql|
|
470
|
+
mysql.affected_rows.should == 6
|
471
|
+
done
|
472
|
+
}
|
473
|
+
end
|
474
|
+
|
449
475
|
should 'fire error callback with exceptions' do
|
450
476
|
SQL.settings.update :on_error => proc{ |e|
|
451
477
|
e.class.should == Mysql::Error
|
data/lib/sequel/async.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# async sequel extensions, for use with em-mysql
|
2
2
|
#
|
3
3
|
# require 'em/mysql'
|
4
|
-
# DB = Sequel.connect(...)
|
5
|
-
#
|
4
|
+
# DB = Sequel.connect(:adapter => 'mysql', :user => 'root', :database => 'test', ...)
|
5
|
+
# EventedMysql.settings.update(..., :on_error => proc{|e| log 'error', e })
|
6
6
|
#
|
7
7
|
# def log *args
|
8
8
|
# p [Time.now, *args]
|
9
9
|
# end
|
10
10
|
#
|
11
|
-
# DB[:table].where(:id < 100).async_update do |num_updated|
|
11
|
+
# DB[:table].where(:id < 100).async_update(:field => 'new value') do |num_updated|
|
12
12
|
# log "done updating #{num_updated} rows"
|
13
13
|
# end
|
14
14
|
#
|
@@ -48,49 +48,52 @@
|
|
48
48
|
module Sequel
|
49
49
|
class Dataset
|
50
50
|
def async_insert *args, &cb
|
51
|
-
|
51
|
+
EventedMysql.insert insert_sql(*args), &cb
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def async_insert_ignore *args, &cb
|
56
|
+
EventedMysql.insert insert_sql(*args).sub(/insert/i, 'INSERT IGNORE'), &cb
|
52
57
|
nil
|
53
58
|
end
|
54
59
|
|
55
60
|
def async_update *args, &cb
|
56
|
-
|
61
|
+
EventedMysql.update update_sql(*args), &cb
|
57
62
|
nil
|
58
63
|
end
|
59
64
|
|
60
65
|
def async_delete &cb
|
61
|
-
|
66
|
+
EventedMysql.execute delete_sql, &cb
|
62
67
|
nil
|
63
68
|
end
|
64
69
|
|
65
70
|
def async_multi_insert *args, &cb
|
66
|
-
|
71
|
+
EventedMysql.execute multi_insert_sql(*args).first, &cb
|
67
72
|
nil
|
68
73
|
end
|
69
74
|
|
70
75
|
def async_multi_insert_ignore *args, &cb
|
71
|
-
|
76
|
+
EventedMysql.execute multi_insert_sql(*args).first.sub(/insert/i, "INSERT IGNORE"), &cb
|
72
77
|
nil
|
73
78
|
end
|
74
79
|
|
75
|
-
def async_each
|
76
|
-
|
80
|
+
def async_each
|
81
|
+
EventedMysql.select(select_sql) do |rows|
|
77
82
|
rows.each{|r|
|
78
|
-
|
79
|
-
|
80
|
-
|
83
|
+
if row_proc = @row_proc
|
84
|
+
yield row_proc.call(r)
|
85
|
+
else
|
86
|
+
yield r
|
87
|
+
end
|
81
88
|
}
|
82
89
|
end
|
83
90
|
nil
|
84
91
|
end
|
85
92
|
|
86
93
|
def async_all
|
87
|
-
|
88
|
-
if row_proc
|
89
|
-
yield(rows.map{|r|
|
90
|
-
r = transform_load(r) if @transform
|
91
|
-
r = row_proc[r] if row_proc
|
92
|
-
r
|
93
|
-
})
|
94
|
+
EventedMysql.select(sql) do |rows|
|
95
|
+
if row_proc = @row_proc
|
96
|
+
yield(rows.map{|r| row_proc.call(r) })
|
94
97
|
else
|
95
98
|
yield(rows)
|
96
99
|
end
|
@@ -102,7 +105,7 @@ module Sequel
|
|
102
105
|
if options_overlap(COUNT_FROM_SELF_OPTS)
|
103
106
|
from_self.async_count(&cb)
|
104
107
|
else
|
105
|
-
|
108
|
+
clone(STOCK_COUNT_OPTS).async_each{|r|
|
106
109
|
yield r.values.first.to_i
|
107
110
|
}
|
108
111
|
end
|
@@ -124,6 +127,7 @@ module Sequel
|
|
124
127
|
|
125
128
|
class << self
|
126
129
|
[ :async_insert,
|
130
|
+
:async_insert_ignore,
|
127
131
|
:async_multi_insert,
|
128
132
|
:async_multi_insert_ignore,
|
129
133
|
:async_each,
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tmm1-em-mysql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aman Gupta
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-23 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.12.
|
23
|
+
version: 0.12.8
|
24
24
|
version:
|
25
25
|
description: Async MySQL client API for Ruby/EventMachine
|
26
26
|
email: em-mysql@tmm1.net
|
@@ -32,6 +32,7 @@ extra_rdoc_files: []
|
|
32
32
|
|
33
33
|
files:
|
34
34
|
- README
|
35
|
+
- em-mysql.gemspec
|
35
36
|
- lib/em/mysql.rb
|
36
37
|
- lib/sequel/async.rb
|
37
38
|
- test.rb
|