tmm1-em-mysql 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|