superfeedr-em-mysql 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +40 -0
- data/em-mysql.gemspec +21 -0
- data/lib/em/mysql.rb +306 -0
- data/lib/sequel/async.rb +184 -0
- data/test.rb +59 -0
- metadata +68 -0
data/README
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
Async MySQL driver for Ruby/EventMachine
|
2
|
+
(c) 2008 Aman Gupta (tmm1)
|
3
|
+
|
4
|
+
|
5
|
+
Requires mysqlplus.
|
6
|
+
|
7
|
+
require 'em/mysql'
|
8
|
+
|
9
|
+
# alias SQL for simpler syntax
|
10
|
+
|
11
|
+
SQL = EventedMysql
|
12
|
+
def SQL(query, &blk) SQL.select(query, &blk) end
|
13
|
+
|
14
|
+
|
15
|
+
# setup connection details and allow 4 connections to the server
|
16
|
+
|
17
|
+
SQL.settings.update :host => 'localhost',
|
18
|
+
:port => 3306,
|
19
|
+
:database => 'test',
|
20
|
+
:connections => 4
|
21
|
+
|
22
|
+
|
23
|
+
# use 4 connections to execute queries in parallel
|
24
|
+
|
25
|
+
SQL('select sleep(0.25)'){ p 'done' }
|
26
|
+
SQL('select sleep(0.25)'){ p 'done' }
|
27
|
+
SQL('select sleep(0.25)'){ p 'done' }
|
28
|
+
SQL('select sleep(0.25)'){ p 'done' }
|
29
|
+
|
30
|
+
Also includes a sequel async wrapper
|
31
|
+
|
32
|
+
require 'sequel'
|
33
|
+
require 'sequel/async'
|
34
|
+
|
35
|
+
DB = Sequel.connect(:adapter => 'mysql', :user => 'root', :database => 'test', ...)
|
36
|
+
EventedMysql.settings.update(..., :on_error => proc{|e| log 'error', e })
|
37
|
+
|
38
|
+
DB[:table].where(:field => 'value').async_update(:field => 'new value')
|
39
|
+
|
40
|
+
For more info, see the comments in lib/sequel/async.rb
|
data/em-mysql.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
spec = Gem::Specification.new do |s|
|
2
|
+
s.name = 'superfeedr-em-mysql'
|
3
|
+
s.version = '0.4.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.9')
|
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
ADDED
@@ -0,0 +1,306 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'mysqlplus'
|
4
|
+
require 'fcntl'
|
5
|
+
|
6
|
+
MAX_RETRIES_ON_DEADLOCKS = 10
|
7
|
+
|
8
|
+
class Mysql
|
9
|
+
def result
|
10
|
+
@cur_result
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class EventedMysql < EM::Connection
|
15
|
+
def initialize mysql, opts
|
16
|
+
@mysql = mysql
|
17
|
+
@fd = mysql.socket
|
18
|
+
@opts = opts
|
19
|
+
@current = nil
|
20
|
+
@@queue ||= []
|
21
|
+
@processing = false
|
22
|
+
@connected = true
|
23
|
+
|
24
|
+
log 'mysql connected'
|
25
|
+
|
26
|
+
self.notify_readable = true
|
27
|
+
EM.add_timer(0){ next_query }
|
28
|
+
end
|
29
|
+
attr_reader :processing, :connected, :opts
|
30
|
+
alias :settings :opts
|
31
|
+
|
32
|
+
DisconnectErrors = [
|
33
|
+
'query: not connected',
|
34
|
+
'MySQL server has gone away',
|
35
|
+
'Lost connection to MySQL server during query'
|
36
|
+
] unless defined? DisconnectErrors
|
37
|
+
|
38
|
+
def notify_readable
|
39
|
+
log 'readable'
|
40
|
+
if item = @current
|
41
|
+
@current = nil
|
42
|
+
start, response, sql, cblk, eblk, retries = item
|
43
|
+
log 'mysql response', Time.now-start, sql
|
44
|
+
arg = case response
|
45
|
+
when :raw
|
46
|
+
result = @mysql.get_result
|
47
|
+
@mysql.instance_variable_set('@cur_result', result)
|
48
|
+
@mysql
|
49
|
+
when :select
|
50
|
+
ret = []
|
51
|
+
result = @mysql.get_result
|
52
|
+
result.each_hash{|h| ret << h }
|
53
|
+
log 'mysql result', ret
|
54
|
+
ret
|
55
|
+
when :update
|
56
|
+
result = @mysql.get_result
|
57
|
+
@mysql.affected_rows
|
58
|
+
when :insert
|
59
|
+
result = @mysql.get_result
|
60
|
+
@mysql.insert_id
|
61
|
+
else
|
62
|
+
result = @mysql.get_result
|
63
|
+
log 'got a result??', result if result
|
64
|
+
nil
|
65
|
+
end
|
66
|
+
|
67
|
+
@processing = false
|
68
|
+
# result.free if result.is_a? Mysql::Result
|
69
|
+
next_query
|
70
|
+
cblk.call(arg) if cblk
|
71
|
+
else
|
72
|
+
log 'readable, but nothing queued?! probably an ERROR state'
|
73
|
+
return close
|
74
|
+
end
|
75
|
+
rescue Mysql::Error => e
|
76
|
+
log 'mysql error', e.message
|
77
|
+
if e.message =~ /Deadlock/ and retries < MAX_RETRIES_ON_DEADLOCKS
|
78
|
+
@@queue << [response, sql, cblk, eblk, retries + 1]
|
79
|
+
@processing = false
|
80
|
+
next_query
|
81
|
+
elsif DisconnectErrors.include? e.message
|
82
|
+
@@queue << [response, sql, cblk, eblk, retries + 1]
|
83
|
+
return close
|
84
|
+
elsif cb = (eblk || @opts[:on_error])
|
85
|
+
cb.call(e)
|
86
|
+
@processing = false
|
87
|
+
next_query
|
88
|
+
else
|
89
|
+
raise e
|
90
|
+
end
|
91
|
+
# ensure
|
92
|
+
# res.free if res.is_a? Mysql::Result
|
93
|
+
# @processing = false
|
94
|
+
# next_query
|
95
|
+
end
|
96
|
+
|
97
|
+
def unbind
|
98
|
+
log 'mysql disconnect', $!, *($! ? $!.backtrace[0..5] : [])
|
99
|
+
# cp = EventedMysql.instance_variable_get('@connection_pool') and cp.delete(self)
|
100
|
+
@connected = false
|
101
|
+
|
102
|
+
# XXX wait for the next tick until the current fd is removed completely from the reactor
|
103
|
+
#
|
104
|
+
# XXX in certain cases the new FD# (@mysql.socket) is the same as the old, since FDs are re-used
|
105
|
+
# XXX without next_tick in these cases, unbind will get fired on the newly attached signature as well
|
106
|
+
#
|
107
|
+
# XXX do _NOT_ use EM.next_tick here. if a bunch of sockets disconnect at the same time, we want
|
108
|
+
# XXX reconnects to happen after all the unbinds have been processed
|
109
|
+
EM.add_timer(0) do
|
110
|
+
log 'mysql reconnecting'
|
111
|
+
@processing = false
|
112
|
+
@mysql = EventedMysql._connect @opts
|
113
|
+
@fd = @mysql.socket
|
114
|
+
|
115
|
+
@signature = EM.attach_fd @mysql.socket, true
|
116
|
+
EM.set_notify_readable @signature, true
|
117
|
+
log 'mysql connected'
|
118
|
+
EM.instance_variable_get('@conns')[@signature] = self
|
119
|
+
@connected = true
|
120
|
+
make_socket_blocking
|
121
|
+
next_query
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def execute sql, response = nil, cblk = nil, eblk = nil, retries = 0, &blk
|
126
|
+
cblk ||= blk
|
127
|
+
|
128
|
+
begin
|
129
|
+
unless @processing or !@connected
|
130
|
+
# begin
|
131
|
+
# log 'mysql ping', @mysql.ping
|
132
|
+
# # log 'mysql stat', @mysql.stat
|
133
|
+
# # log 'mysql errno', @mysql.errno
|
134
|
+
# rescue
|
135
|
+
# log 'mysql ping failed'
|
136
|
+
# @@queue << [response, sql, blk]
|
137
|
+
# return close
|
138
|
+
# end
|
139
|
+
|
140
|
+
@processing = true
|
141
|
+
|
142
|
+
log 'mysql sending', sql
|
143
|
+
@mysql.send_query(sql)
|
144
|
+
else
|
145
|
+
@@queue << [response, sql, cblk, eblk, retries]
|
146
|
+
return
|
147
|
+
end
|
148
|
+
rescue Mysql::Error => e
|
149
|
+
log 'mysql error', e.message
|
150
|
+
if DisconnectErrors.include? e.message
|
151
|
+
@@queue << [response, sql, cblk, eblk, retries]
|
152
|
+
return close
|
153
|
+
else
|
154
|
+
raise e
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
log 'queuing', response, sql
|
159
|
+
@current = [Time.now, response, sql, cblk, eblk, retries]
|
160
|
+
end
|
161
|
+
|
162
|
+
def close
|
163
|
+
@connected = false
|
164
|
+
fd = detach
|
165
|
+
log 'detached fd', fd
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
def next_query
|
171
|
+
if @connected and !@processing and pending = @@queue.shift
|
172
|
+
response, sql, cblk, eblk = pending
|
173
|
+
execute(sql, response, cblk, eblk)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def log *args
|
178
|
+
return unless @opts[:logging]
|
179
|
+
p [Time.now, @fd, (@signature[-4..-1] if @signature), *args]
|
180
|
+
end
|
181
|
+
|
182
|
+
public
|
183
|
+
|
184
|
+
def self.connect opts
|
185
|
+
unless EM.respond_to?(:watch) and Mysql.method_defined?(:socket)
|
186
|
+
raise RuntimeError, 'mysqlplus and EM.watch are required for EventedMysql'
|
187
|
+
end
|
188
|
+
|
189
|
+
opts = servers_opts.pop
|
190
|
+
opts[:failover] = servers_opts
|
191
|
+
if conn = _connect(opts)
|
192
|
+
EM.watch conn.socket, self, conn, opts
|
193
|
+
else
|
194
|
+
EM.add_timer(5){ connect opts }
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
self::Mysql = ::Mysql unless defined? self::Mysql
|
199
|
+
|
200
|
+
# stolen from sequel
|
201
|
+
def self._connect opts
|
202
|
+
opts = settings.merge(opts)
|
203
|
+
|
204
|
+
conn = Mysql.init
|
205
|
+
|
206
|
+
# set encoding _before_ connecting
|
207
|
+
if charset = opts[:charset] || opts[:encoding]
|
208
|
+
conn.options(Mysql::SET_CHARSET_NAME, charset)
|
209
|
+
end
|
210
|
+
|
211
|
+
conn.options(Mysql::OPT_LOCAL_INFILE, 'client')
|
212
|
+
|
213
|
+
conn.real_connect(
|
214
|
+
opts[:host] || 'localhost',
|
215
|
+
opts[:user] || 'root',
|
216
|
+
opts[:password],
|
217
|
+
opts[:database],
|
218
|
+
opts[:port],
|
219
|
+
opts[:socket],
|
220
|
+
0 +
|
221
|
+
# XXX multi results require multiple callbacks to parse
|
222
|
+
# Mysql::CLIENT_MULTI_RESULTS +
|
223
|
+
# Mysql::CLIENT_MULTI_STATEMENTS +
|
224
|
+
(opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
|
225
|
+
)
|
226
|
+
|
227
|
+
# increase timeout so mysql server doesn't disconnect us
|
228
|
+
# this is especially bad if we're disconnected while EM.attach is
|
229
|
+
# still in progress, because by the time it gets to EM, the FD is
|
230
|
+
# no longer valid, and it throws a c++ 'bad file descriptor' error
|
231
|
+
# (do not use a timeout of -1 for unlimited, it does not work on mysqld > 5.0.60)
|
232
|
+
conn.query("set @@wait_timeout = #{opts[:timeout] || 2592000}")
|
233
|
+
|
234
|
+
# we handle reconnecting (and reattaching the new fd to EM)
|
235
|
+
conn.reconnect = false
|
236
|
+
|
237
|
+
# By default, MySQL 'where id is null' selects the last inserted id
|
238
|
+
# Turn this off. http://dev.rubyonrails.org/ticket/6778
|
239
|
+
conn.query("set SQL_AUTO_IS_NULL=0")
|
240
|
+
|
241
|
+
# get results for queries
|
242
|
+
conn.query_with_result = true
|
243
|
+
|
244
|
+
conn
|
245
|
+
rescue Mysql::Error => e
|
246
|
+
if cb = opts[:on_error]
|
247
|
+
cb.call(e)
|
248
|
+
nil
|
249
|
+
elsif opts[:failover]
|
250
|
+
connect(opts[:failover])
|
251
|
+
else
|
252
|
+
raise e
|
253
|
+
end
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
class EventedMysql
|
258
|
+
def self.settings
|
259
|
+
@settings ||= { :connections => 4, :logging => false }
|
260
|
+
end
|
261
|
+
|
262
|
+
def self.execute query, type = nil, cblk = nil, eblk = nil, &blk
|
263
|
+
unless nil#connection = connection_pool.find{|c| not c.processing and c.connected }
|
264
|
+
@n ||= 0
|
265
|
+
connection = connection_pool[@n]
|
266
|
+
@n = 0 if (@n+=1) >= connection_pool.size
|
267
|
+
end
|
268
|
+
|
269
|
+
connection.execute(query, type, cblk, eblk, &blk)
|
270
|
+
end
|
271
|
+
|
272
|
+
%w[ select insert update raw ].each do |type| class_eval %[
|
273
|
+
|
274
|
+
def self.#{type} query, cblk = nil, eblk = nil, &blk
|
275
|
+
execute query, :#{type}, cblk, eblk, &blk
|
276
|
+
end
|
277
|
+
|
278
|
+
] end
|
279
|
+
|
280
|
+
def self.all query, type = nil, &blk
|
281
|
+
responses = 0
|
282
|
+
connection_pool.each do |c|
|
283
|
+
c.execute(query, type) do
|
284
|
+
responses += 1
|
285
|
+
blk.call if blk and responses == @connection_pool.size
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.connection_pool
|
291
|
+
@connection_pool ||= (1..settings[:connections]).map{ EventedMysql.connect(settings) }
|
292
|
+
# p ['connpool', settings[:connections], @connection_pool.size]
|
293
|
+
# (1..(settings[:connections]-@connection_pool.size)).each do
|
294
|
+
# @connection_pool << EventedMysql.connect(settings)
|
295
|
+
# end unless settings[:connections] == @connection_pool.size
|
296
|
+
# @connection_pool
|
297
|
+
end
|
298
|
+
|
299
|
+
def self.reset!
|
300
|
+
@connection_pool.each do |c|
|
301
|
+
c.close
|
302
|
+
end
|
303
|
+
@connection_pool = nil
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
data/lib/sequel/async.rb
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
# async sequel extensions, for use with em-mysql
|
2
|
+
#
|
3
|
+
# require 'em/mysql'
|
4
|
+
# DB = Sequel.connect(:adapter => 'mysql', :user => 'root', :database => 'test', ...)
|
5
|
+
# EventedMysql.settings.update(..., :on_error => proc{|e| log 'error', e })
|
6
|
+
#
|
7
|
+
# def log *args
|
8
|
+
# p [Time.now, *args]
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# DB[:table].where(:id < 100).async_update(:field => 'new value') do |num_updated|
|
12
|
+
# log "done updating #{num_updated} rows"
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# DB[:table].async_insert(:field => 'value') do |insert_id|
|
16
|
+
# log "inserted row #{insert_id}"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# DB[:table].async_multi_insert([:field], [ ['one'], ['two'], ['three'] ]) do
|
20
|
+
# log "done inserting 3 rows"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# DB[:table].limit(10).async_each do |row|
|
24
|
+
# log "got a row", row
|
25
|
+
# end; log "this will be printed before the query returns"
|
26
|
+
#
|
27
|
+
# DB[:table].async_all do |rows|
|
28
|
+
# DB[:table].async_multi_insert([:field], rows.map{|r| "new_#{r[:field]}" })
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# DB[:table].async_all do |rows|
|
32
|
+
# num = rows.size
|
33
|
+
#
|
34
|
+
# rows.each{ |r|
|
35
|
+
# DB[:table].where(:id => r[:id]).async_update(:field => rand(10000).to_s) do
|
36
|
+
# num = num-1
|
37
|
+
# if num == 0
|
38
|
+
# log "last update completed"
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
# }
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# DB[:table].async_count do |num_rows|
|
45
|
+
# log "table has #{num_rows} rows"
|
46
|
+
# end
|
47
|
+
|
48
|
+
require 'sequel'
|
49
|
+
raise 'need Sequel >= 3.2.0' unless Sequel::MAJOR == 3 and Sequel::MINOR >= 2
|
50
|
+
|
51
|
+
module Sequel
|
52
|
+
class Dataset
|
53
|
+
def async_insert *args, &cb
|
54
|
+
EventedMysql.insert insert_sql(*args), &cb
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def async_insert_ignore *args, &cb
|
59
|
+
EventedMysql.insert insert_ignore.insert_sql(*args), &cb
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def async_update *args, &cb
|
64
|
+
EventedMysql.update update_sql(*args), &cb
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def async_delete &cb
|
69
|
+
EventedMysql.execute delete_sql, &cb
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def async_multi_insert *args, &cb
|
74
|
+
EventedMysql.execute multi_insert_sql(*args).first, &cb
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def async_multi_insert_ignore *args, &cb
|
79
|
+
EventedMysql.execute insert_ignore.multi_insert_sql(*args).first, &cb
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def async_fetch_rows sql, iter = :each
|
84
|
+
EventedMysql.raw(sql) do |m|
|
85
|
+
r = m.result
|
86
|
+
|
87
|
+
i = -1
|
88
|
+
cols = r.fetch_fields.map{|f| [output_identifier(f.name), Sequel::MySQL::MYSQL_TYPES[f.type], i+=1]}
|
89
|
+
@columns = cols.map{|c| c.first}
|
90
|
+
rows = []
|
91
|
+
while row = r.fetch_row
|
92
|
+
h = {}
|
93
|
+
cols.each{|n, p, i| v = row[i]; h[n] = (v && p) ? p.call(v) : v}
|
94
|
+
if iter == :each
|
95
|
+
yield h
|
96
|
+
else
|
97
|
+
rows << h
|
98
|
+
end
|
99
|
+
end
|
100
|
+
yield rows if iter == :all
|
101
|
+
end
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def async_each
|
106
|
+
async_fetch_rows(select_sql, :each) do |r|
|
107
|
+
if row_proc = @row_proc
|
108
|
+
yield row_proc.call(r)
|
109
|
+
else
|
110
|
+
yield r
|
111
|
+
end
|
112
|
+
end
|
113
|
+
nil
|
114
|
+
end
|
115
|
+
|
116
|
+
def async_all
|
117
|
+
async_fetch_rows(sql, :all) do |rows|
|
118
|
+
if row_proc = @row_proc
|
119
|
+
yield(rows.map{|r| row_proc.call(r) })
|
120
|
+
else
|
121
|
+
yield(rows)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
nil
|
125
|
+
end
|
126
|
+
|
127
|
+
def async_count &cb
|
128
|
+
if options_overlap(COUNT_FROM_SELF_OPTS)
|
129
|
+
from_self.async_count(&cb)
|
130
|
+
else
|
131
|
+
clone(STOCK_COUNT_OPTS).async_each{|r|
|
132
|
+
yield r.is_a?(Hash) ? r.values.first.to_i : r.values.values.first.to_i
|
133
|
+
}
|
134
|
+
end
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Model
|
140
|
+
def async_update *args, &cb
|
141
|
+
this.async_update(*args, &cb)
|
142
|
+
set(*args)
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
def async_delete &cb
|
147
|
+
this.async_delete(&cb)
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
class << self
|
152
|
+
[ :async_insert,
|
153
|
+
:async_insert_ignore,
|
154
|
+
:async_multi_insert,
|
155
|
+
:async_multi_insert_ignore,
|
156
|
+
:async_each,
|
157
|
+
:async_all,
|
158
|
+
:async_update,
|
159
|
+
:async_count ].each do |method|
|
160
|
+
class_eval %[
|
161
|
+
def #{method} *args, &cb
|
162
|
+
dataset.#{method}(*args, &cb)
|
163
|
+
end
|
164
|
+
]
|
165
|
+
end
|
166
|
+
|
167
|
+
# async version of Model#[]
|
168
|
+
def async_lookup args
|
169
|
+
unless Hash === args
|
170
|
+
args = primary_key_hash(args)
|
171
|
+
end
|
172
|
+
|
173
|
+
dataset.where(args).limit(1).async_all{ |rows|
|
174
|
+
if rows.any?
|
175
|
+
yield rows.first
|
176
|
+
else
|
177
|
+
yield nil
|
178
|
+
end
|
179
|
+
}
|
180
|
+
nil
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/test.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'lib/em/mysql'
|
2
|
+
|
3
|
+
# EM.kqueue
|
4
|
+
# EM.epoll
|
5
|
+
EM.run{
|
6
|
+
EM.start_server '127.0.0.1', 12345 do |c|
|
7
|
+
def c.receive_data data
|
8
|
+
p 'sending http response'
|
9
|
+
send_data "hello"
|
10
|
+
close_connection_after_writing
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
SQL = EventedMysql
|
15
|
+
def SQL(query, &blk) SQL.select(query, &blk) end
|
16
|
+
|
17
|
+
if false
|
18
|
+
|
19
|
+
SQL.settings.update :logging => true,
|
20
|
+
:database => 'test',
|
21
|
+
:connections => 1
|
22
|
+
|
23
|
+
SQL.execute('select 1+2')
|
24
|
+
|
25
|
+
EM.add_timer(1){
|
26
|
+
3.times do SQL.select('select sleep(0.5)+1'){|r| p(r) } end
|
27
|
+
}
|
28
|
+
|
29
|
+
elsif false
|
30
|
+
|
31
|
+
SQL.settings.update :logging => true,
|
32
|
+
:database => 'test',
|
33
|
+
:connections => 10
|
34
|
+
|
35
|
+
EM.add_timer(2.5){ SQL.all('use test') }
|
36
|
+
|
37
|
+
else
|
38
|
+
|
39
|
+
SQL.settings.update :logging => true,
|
40
|
+
:database => 'test',
|
41
|
+
:connections => 10,
|
42
|
+
:timeout => 1
|
43
|
+
|
44
|
+
n = 0
|
45
|
+
|
46
|
+
SQL.execute('drop table if exists testingabc'){
|
47
|
+
SQL.execute('create table testingabc (a int, b int, c int)'){
|
48
|
+
EM.add_periodic_timer(0.2) do
|
49
|
+
cur_num = n+=1
|
50
|
+
SQL.execute("insert into testingabc values (1,2,#{cur_num})"){
|
51
|
+
SQL("select * from testingabc where c = #{cur_num} limit 1"){ |res| puts;puts }
|
52
|
+
}
|
53
|
+
end
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
}
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: superfeedr-em-mysql
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aman Gupta
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-06-23 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: eventmachine
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.12.9
|
24
|
+
version:
|
25
|
+
description: Async MySQL client API for Ruby/EventMachine
|
26
|
+
email: em-mysql@tmm1.net
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- README
|
35
|
+
- em-mysql.gemspec
|
36
|
+
- lib/em/mysql.rb
|
37
|
+
- lib/sequel/async.rb
|
38
|
+
- test.rb
|
39
|
+
has_rdoc: true
|
40
|
+
homepage: http://github.com/tmm1/em-mysql
|
41
|
+
licenses: []
|
42
|
+
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: "0"
|
53
|
+
version:
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: "0"
|
59
|
+
version:
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 1.3.5
|
64
|
+
signing_key:
|
65
|
+
specification_version: 3
|
66
|
+
summary: Async MySQL client API for Ruby/EventMachine
|
67
|
+
test_files: []
|
68
|
+
|