mysql2 0.3.7 → 0.3.8
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/.rvmrc +1 -1
- data/.travis.yml +7 -0
- data/CHANGELOG.md +14 -0
- data/README.md +3 -4
- data/ext/mysql2/client.c +32 -29
- data/ext/mysql2/extconf.rb +1 -0
- data/ext/mysql2/result.c +2 -2
- data/ext/mysql2/wait_for_single_fd.h +36 -0
- data/lib/mysql2/client.rb +2 -1
- data/lib/mysql2/version.rb +1 -1
- data/mysql2.gemspec +2 -2
- data/spec/em/em_spec.rb +5 -4
- metadata +31 -19
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +0 -64
- data/lib/active_record/fiber_patches.rb +0 -132
- data/lib/mysql2/em_fiber.rb +0 -31
- data/spec/em/em_fiber_spec.rb +0 -22
data/.rvmrc
CHANGED
@@ -1 +1 @@
|
|
1
|
-
rvm use 1.9.
|
1
|
+
rvm use 1.9.3@mysql2 --create
|
data/.travis.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 0.3.8 (November 9th, 2011)
|
4
|
+
* remove fiber support from mysql2, the code has moved to the
|
5
|
+
em-synchrony gem.
|
6
|
+
* use rb_wait_for_single_fd() if available
|
7
|
+
* fixed a bug with inheriting query options
|
8
|
+
* remove ext/ from the default loadpath
|
9
|
+
* fix build issues on OSX with Xcode 4.2 (gcc-llvm compiler)
|
10
|
+
|
3
11
|
## 0.3.7 (August 16th, 2011)
|
4
12
|
* ensure symbolized column names support encodings in 1.9
|
5
13
|
|
@@ -36,6 +44,12 @@
|
|
36
44
|
* BREAKING CHANGE: the ActiveRecord adapter has been pulled into Rails 3.1 and is no longer part of the gem
|
37
45
|
* added Mysql2::Client.escape (class-level) for raw one-off non-encoding-aware escaping
|
38
46
|
|
47
|
+
## 0.2.14 (November 9th, 2011)
|
48
|
+
* use rb_wait_for_single_fd() if available
|
49
|
+
* fixed a bug with inheriting query options
|
50
|
+
* remove ext/ from the default loadpath
|
51
|
+
* fix build issues on OSX with Xcode 4.2 (gcc-llvm compiler)
|
52
|
+
|
39
53
|
## 0.2.13 (August 16th, 2011)
|
40
54
|
* fix stupid bug around symbol encoding support (thanks coderrr!)
|
41
55
|
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ This one is not.
|
|
6
6
|
|
7
7
|
It also forces the use of UTF-8 [or binary] for the connection [and all strings in 1.9, unless Encoding.default_internal is set then it'll convert from UTF-8 to that encoding] and uses encoding-aware MySQL API calls where it can.
|
8
8
|
|
9
|
-
The API consists of two
|
9
|
+
The API consists of two classes:
|
10
10
|
|
11
11
|
Mysql2::Client - your connection to the database
|
12
12
|
|
@@ -214,7 +214,7 @@ This would be helpful if you wanted to iterate over the results in a streaming m
|
|
214
214
|
|
215
215
|
## ActiveRecord
|
216
216
|
|
217
|
-
To use the ActiveRecord driver (with
|
217
|
+
To use the ActiveRecord driver (with or without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
|
218
218
|
That was easy right? :)
|
219
219
|
|
220
220
|
NOTE: as of 0.3.0, and ActiveRecord 3.1 - the ActiveRecord adapter has been pulled out of this gem and into ActiveRecord itself. If you need to use mysql2 with
|
@@ -222,8 +222,7 @@ Rails versions < 3.1 make sure and specify `gem "mysql2", "~> 0.2.7"` in your Ge
|
|
222
222
|
|
223
223
|
## Asynchronous ActiveRecord
|
224
224
|
|
225
|
-
|
226
|
-
setting the adapter in your database.yml to "em_mysql2". You must be running Ruby 1.9, thin and the rack-fiber_pool middleware for it to work.
|
225
|
+
Please see the [em-synchrony](https://github.com/igrigorik/em-synchrony) project for details about using EventMachine with mysql2 and Rails.
|
227
226
|
|
228
227
|
## Sequel
|
229
228
|
|
data/ext/mysql2/client.c
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
#ifndef _WIN32
|
5
5
|
#include <sys/socket.h>
|
6
6
|
#endif
|
7
|
+
#include "wait_for_single_fd.h"
|
7
8
|
|
8
9
|
VALUE cMysql2Client;
|
9
10
|
extern VALUE mMysql2, cMysql2Error;
|
@@ -45,6 +46,7 @@ struct nogvl_connect_args {
|
|
45
46
|
struct nogvl_send_query_args {
|
46
47
|
MYSQL *mysql;
|
47
48
|
VALUE sql;
|
49
|
+
mysql_client_wrapper *wrapper;
|
48
50
|
};
|
49
51
|
|
50
52
|
/*
|
@@ -145,7 +147,7 @@ static VALUE nogvl_close(void *ptr) {
|
|
145
147
|
#endif
|
146
148
|
|
147
149
|
mysql_close(wrapper->client);
|
148
|
-
|
150
|
+
free(wrapper->client);
|
149
151
|
}
|
150
152
|
|
151
153
|
return Qnil;
|
@@ -156,7 +158,7 @@ static void rb_mysql_client_free(void * ptr) {
|
|
156
158
|
|
157
159
|
nogvl_close(wrapper);
|
158
160
|
|
159
|
-
|
161
|
+
free(ptr);
|
160
162
|
}
|
161
163
|
|
162
164
|
static VALUE allocate(VALUE klass) {
|
@@ -167,7 +169,7 @@ static VALUE allocate(VALUE klass) {
|
|
167
169
|
wrapper->active = 0;
|
168
170
|
wrapper->reconnect_enabled = 0;
|
169
171
|
wrapper->closed = 1;
|
170
|
-
wrapper->client = (MYSQL*)
|
172
|
+
wrapper->client = (MYSQL*)malloc(sizeof(MYSQL));
|
171
173
|
return obj;
|
172
174
|
}
|
173
175
|
|
@@ -179,19 +181,19 @@ static VALUE rb_mysql_client_escape(RB_MYSQL_UNUSED VALUE klass, VALUE str) {
|
|
179
181
|
Check_Type(str, T_STRING);
|
180
182
|
|
181
183
|
oldLen = RSTRING_LEN(str);
|
182
|
-
newStr =
|
184
|
+
newStr = malloc(oldLen*2+1);
|
183
185
|
|
184
186
|
newLen = mysql_escape_string((char *)newStr, StringValuePtr(str), oldLen);
|
185
187
|
if (newLen == oldLen) {
|
186
188
|
// no need to return a new ruby string if nothing changed
|
187
|
-
|
189
|
+
free(newStr);
|
188
190
|
return str;
|
189
191
|
} else {
|
190
192
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
191
193
|
#ifdef HAVE_RUBY_ENCODING_H
|
192
194
|
rb_enc_copy(rb_str, str);
|
193
195
|
#endif
|
194
|
-
|
196
|
+
free(newStr);
|
195
197
|
return rb_str;
|
196
198
|
}
|
197
199
|
}
|
@@ -249,6 +251,17 @@ static VALUE nogvl_send_query(void *ptr) {
|
|
249
251
|
return rv == 0 ? Qtrue : Qfalse;
|
250
252
|
}
|
251
253
|
|
254
|
+
static VALUE do_send_query(void *args) {
|
255
|
+
struct nogvl_send_query_args *query_args = args;
|
256
|
+
mysql_client_wrapper *wrapper = query_args->wrapper;
|
257
|
+
if (rb_thread_blocking_region(nogvl_send_query, args, RUBY_UBF_IO, 0) == Qfalse) {
|
258
|
+
// an error occurred, we're not active anymore
|
259
|
+
MARK_CONN_INACTIVE(self);
|
260
|
+
return rb_raise_mysql2_error(wrapper);
|
261
|
+
}
|
262
|
+
return Qnil;
|
263
|
+
}
|
264
|
+
|
252
265
|
/*
|
253
266
|
* even though we did rb_thread_select before calling this, a large
|
254
267
|
* response can overflow the socket buffers and cause us to eventually
|
@@ -341,9 +354,7 @@ static VALUE do_query(void *args) {
|
|
341
354
|
struct timeval tv;
|
342
355
|
struct timeval* tvp;
|
343
356
|
long int sec;
|
344
|
-
fd_set fdset;
|
345
357
|
int retval;
|
346
|
-
int fd_set_fd;
|
347
358
|
VALUE read_timeout;
|
348
359
|
|
349
360
|
async_args = (struct async_query_args *)args;
|
@@ -364,14 +375,8 @@ static VALUE do_query(void *args) {
|
|
364
375
|
tvp->tv_usec = 0;
|
365
376
|
}
|
366
377
|
|
367
|
-
fd_set_fd = async_args->fd;
|
368
378
|
for(;;) {
|
369
|
-
|
370
|
-
// http://github.com/datamapper/do
|
371
|
-
FD_ZERO(&fdset);
|
372
|
-
FD_SET(fd_set_fd, &fdset);
|
373
|
-
|
374
|
-
retval = rb_thread_select(fd_set_fd + 1, &fdset, NULL, NULL, tvp);
|
379
|
+
retval = rb_wait_for_single_fd(async_args->fd, RB_WAITFD_IN, tvp);
|
375
380
|
|
376
381
|
if (retval == 0) {
|
377
382
|
rb_raise(cMysql2Error, "Timeout waiting for a response from the last query. (waited %d seconds)", FIX2INT(read_timeout));
|
@@ -426,13 +431,6 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
|
426
431
|
REQUIRE_OPEN_DB(wrapper);
|
427
432
|
args.mysql = wrapper->client;
|
428
433
|
|
429
|
-
// see if this connection is still waiting on a result from a previous query
|
430
|
-
if (wrapper->active == 0) {
|
431
|
-
// mark this connection active
|
432
|
-
wrapper->active = 1;
|
433
|
-
} else {
|
434
|
-
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
435
|
-
}
|
436
434
|
|
437
435
|
defaults = rb_iv_get(self, "@query_options");
|
438
436
|
if (rb_scan_args(argc, argv, "11", &args.sql, &opts) == 2) {
|
@@ -453,12 +451,17 @@ static VALUE rb_mysql_client_query(int argc, VALUE * argv, VALUE self) {
|
|
453
451
|
args.sql = rb_str_export_to_enc(args.sql, conn_enc);
|
454
452
|
#endif
|
455
453
|
|
456
|
-
if
|
457
|
-
|
458
|
-
|
459
|
-
|
454
|
+
// see if this connection is still waiting on a result from a previous query
|
455
|
+
if (wrapper->active == 0) {
|
456
|
+
// mark this connection active
|
457
|
+
wrapper->active = 1;
|
458
|
+
} else {
|
459
|
+
rb_raise(cMysql2Error, "This connection is still waiting for a result, try again once you have the result");
|
460
460
|
}
|
461
461
|
|
462
|
+
args.wrapper = wrapper;
|
463
|
+
rb_rescue2(do_send_query, (VALUE)&args, disconnect_and_raise, self, rb_eException, (VALUE)0);
|
464
|
+
|
462
465
|
#ifndef _WIN32
|
463
466
|
if (!async) {
|
464
467
|
async_args.fd = wrapper->client->net.fd;
|
@@ -496,12 +499,12 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
496
499
|
#endif
|
497
500
|
|
498
501
|
oldLen = RSTRING_LEN(str);
|
499
|
-
newStr =
|
502
|
+
newStr = malloc(oldLen*2+1);
|
500
503
|
|
501
504
|
newLen = mysql_real_escape_string(wrapper->client, (char *)newStr, StringValuePtr(str), oldLen);
|
502
505
|
if (newLen == oldLen) {
|
503
506
|
// no need to return a new ruby string if nothing changed
|
504
|
-
|
507
|
+
free(newStr);
|
505
508
|
return str;
|
506
509
|
} else {
|
507
510
|
rb_str = rb_str_new((const char*)newStr, newLen);
|
@@ -511,7 +514,7 @@ static VALUE rb_mysql_client_real_escape(VALUE self, VALUE str) {
|
|
511
514
|
rb_str = rb_str_export_to_enc(rb_str, default_internal_enc);
|
512
515
|
}
|
513
516
|
#endif
|
514
|
-
|
517
|
+
free(newStr);
|
515
518
|
return rb_str;
|
516
519
|
}
|
517
520
|
}
|
data/ext/mysql2/extconf.rb
CHANGED
data/ext/mysql2/result.c
CHANGED
@@ -80,7 +80,7 @@ static void rb_mysql_result_free(void * wrapper) {
|
|
80
80
|
mysql2_result_wrapper * w = wrapper;
|
81
81
|
/* FIXME: this may call flush_use_result, which can hit the socket */
|
82
82
|
rb_mysql_result_free_result(w);
|
83
|
-
|
83
|
+
free(wrapper);
|
84
84
|
}
|
85
85
|
|
86
86
|
/*
|
@@ -139,7 +139,7 @@ static VALUE rb_mysql_result_fetch_field(VALUE self, unsigned int idx, short int
|
|
139
139
|
}
|
140
140
|
|
141
141
|
#ifdef HAVE_RUBY_ENCODING_H
|
142
|
-
|
142
|
+
static VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
|
143
143
|
// if binary flag is set, respect it's wishes
|
144
144
|
if (field.flags & BINARY_FLAG && field.charsetnr == 63) {
|
145
145
|
rb_enc_associate(val, binaryEncoding);
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/*
|
2
|
+
* backwards compatibility for pre-1.9.3 C API
|
3
|
+
*
|
4
|
+
* Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
|
5
|
+
* to minimize select() and malloc() overhead on high-numbered FDs.
|
6
|
+
*/
|
7
|
+
#ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
|
8
|
+
# include <ruby/io.h>
|
9
|
+
#else
|
10
|
+
# define RB_WAITFD_IN 0x001
|
11
|
+
# define RB_WAITFD_PRI 0x002
|
12
|
+
# define RB_WAITFD_OUT 0x004
|
13
|
+
|
14
|
+
static int my_wait_for_single_fd(int fd, int events, struct timeval *tvp)
|
15
|
+
{
|
16
|
+
fd_set fdset;
|
17
|
+
fd_set *rfds = NULL;
|
18
|
+
fd_set *wfds = NULL;
|
19
|
+
fd_set *efds = NULL;
|
20
|
+
|
21
|
+
FD_ZERO(&fdset);
|
22
|
+
FD_SET(fd, &fdset);
|
23
|
+
|
24
|
+
if (events & RB_WAITFD_IN)
|
25
|
+
rfds = &fdset;
|
26
|
+
if (events & RB_WAITFD_OUT)
|
27
|
+
wfds = &fdset;
|
28
|
+
if (events & RB_WAITFD_PRI)
|
29
|
+
efds = &fdset;
|
30
|
+
|
31
|
+
return rb_thread_select(fd + 1, rfds, wfds, efds, tvp);
|
32
|
+
}
|
33
|
+
|
34
|
+
#define rb_wait_for_single_fd(fd,events,tvp) \
|
35
|
+
my_wait_for_single_fd((fd),(events),(tvp))
|
36
|
+
#endif
|
data/lib/mysql2/client.rb
CHANGED
@@ -15,6 +15,7 @@ module Mysql2
|
|
15
15
|
|
16
16
|
def initialize(opts = {})
|
17
17
|
@query_options = @@default_query_options.dup
|
18
|
+
@query_options.merge! opts
|
18
19
|
|
19
20
|
init_connection
|
20
21
|
|
@@ -30,7 +31,7 @@ module Mysql2
|
|
30
31
|
raise Mysql2::Error, "read_timeout must be a positive integer, you passed #{@read_timeout}"
|
31
32
|
end
|
32
33
|
|
33
|
-
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :
|
34
|
+
ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher))
|
34
35
|
|
35
36
|
user = opts[:username]
|
36
37
|
pass = opts[:password]
|
data/lib/mysql2/version.rb
CHANGED
data/mysql2.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.files = `git ls-files`.split("\n")
|
11
11
|
s.homepage = %q{http://github.com/brianmario/mysql2}
|
12
12
|
s.rdoc_options = ["--charset=UTF-8"]
|
13
|
-
s.require_paths = ["lib"
|
13
|
+
s.require_paths = ["lib"]
|
14
14
|
s.rubygems_version = %q{1.4.2}
|
15
15
|
s.summary = %q{A simple, fast Mysql library for Ruby, binding to libmysql}
|
16
16
|
s.test_files = `git ls-files spec examples`.split("\n")
|
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
# tests
|
19
19
|
s.add_development_dependency 'eventmachine'
|
20
20
|
s.add_development_dependency 'rake-compiler', "~> 0.7.7"
|
21
|
+
s.add_development_dependency 'rake', '0.8.7' # NB: 0.8.7 required by rake-compiler 0.7.9
|
21
22
|
s.add_development_dependency 'rspec'
|
22
23
|
# benchmarks
|
23
24
|
s.add_development_dependency 'activerecord'
|
@@ -26,4 +27,3 @@ Gem::Specification.new do |s|
|
|
26
27
|
s.add_development_dependency 'sequel'
|
27
28
|
s.add_development_dependency 'faker'
|
28
29
|
end
|
29
|
-
|
data/spec/em/em_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
3
|
-
|
2
|
+
require 'spec_helper'
|
3
|
+
begin
|
4
|
+
require 'eventmachine'
|
4
5
|
require 'mysql2/em'
|
5
6
|
|
6
7
|
describe Mysql2::EM::Client do
|
@@ -44,6 +45,6 @@ if defined? EventMachine
|
|
44
45
|
results[1].keys.should include("second_query")
|
45
46
|
end
|
46
47
|
end
|
47
|
-
|
48
|
+
rescue LoadError
|
48
49
|
puts "EventMachine not installed, skipping the specs that use it"
|
49
|
-
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mysql2
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 8
|
10
|
+
version: 0.3.8
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Brian Lopez
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-11-09 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -49,21 +49,23 @@ dependencies:
|
|
49
49
|
type: :development
|
50
50
|
version_requirements: *id002
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
|
-
name:
|
52
|
+
name: rake
|
53
53
|
prerelease: false
|
54
54
|
requirement: &id003 !ruby/object:Gem::Requirement
|
55
55
|
none: false
|
56
56
|
requirements:
|
57
|
-
- - "
|
57
|
+
- - "="
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
hash:
|
59
|
+
hash: 49
|
60
60
|
segments:
|
61
61
|
- 0
|
62
|
-
|
62
|
+
- 8
|
63
|
+
- 7
|
64
|
+
version: 0.8.7
|
63
65
|
type: :development
|
64
66
|
version_requirements: *id003
|
65
67
|
- !ruby/object:Gem::Dependency
|
66
|
-
name:
|
68
|
+
name: rspec
|
67
69
|
prerelease: false
|
68
70
|
requirement: &id004 !ruby/object:Gem::Requirement
|
69
71
|
none: false
|
@@ -77,7 +79,7 @@ dependencies:
|
|
77
79
|
type: :development
|
78
80
|
version_requirements: *id004
|
79
81
|
- !ruby/object:Gem::Dependency
|
80
|
-
name:
|
82
|
+
name: activerecord
|
81
83
|
prerelease: false
|
82
84
|
requirement: &id005 !ruby/object:Gem::Requirement
|
83
85
|
none: false
|
@@ -91,7 +93,7 @@ dependencies:
|
|
91
93
|
type: :development
|
92
94
|
version_requirements: *id005
|
93
95
|
- !ruby/object:Gem::Dependency
|
94
|
-
name:
|
96
|
+
name: mysql
|
95
97
|
prerelease: false
|
96
98
|
requirement: &id006 !ruby/object:Gem::Requirement
|
97
99
|
none: false
|
@@ -105,7 +107,7 @@ dependencies:
|
|
105
107
|
type: :development
|
106
108
|
version_requirements: *id006
|
107
109
|
- !ruby/object:Gem::Dependency
|
108
|
-
name:
|
110
|
+
name: do_mysql
|
109
111
|
prerelease: false
|
110
112
|
requirement: &id007 !ruby/object:Gem::Requirement
|
111
113
|
none: false
|
@@ -119,7 +121,7 @@ dependencies:
|
|
119
121
|
type: :development
|
120
122
|
version_requirements: *id007
|
121
123
|
- !ruby/object:Gem::Dependency
|
122
|
-
name:
|
124
|
+
name: sequel
|
123
125
|
prerelease: false
|
124
126
|
requirement: &id008 !ruby/object:Gem::Requirement
|
125
127
|
none: false
|
@@ -132,6 +134,20 @@ dependencies:
|
|
132
134
|
version: "0"
|
133
135
|
type: :development
|
134
136
|
version_requirements: *id008
|
137
|
+
- !ruby/object:Gem::Dependency
|
138
|
+
name: faker
|
139
|
+
prerelease: false
|
140
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
141
|
+
none: false
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
hash: 3
|
146
|
+
segments:
|
147
|
+
- 0
|
148
|
+
version: "0"
|
149
|
+
type: :development
|
150
|
+
version_requirements: *id009
|
135
151
|
description:
|
136
152
|
email: seniorlopez@gmail.com
|
137
153
|
executables: []
|
@@ -144,6 +160,7 @@ files:
|
|
144
160
|
- .gitignore
|
145
161
|
- .rspec
|
146
162
|
- .rvmrc
|
163
|
+
- .travis.yml
|
147
164
|
- CHANGELOG.md
|
148
165
|
- Gemfile
|
149
166
|
- MIT-LICENSE
|
@@ -167,17 +184,14 @@ files:
|
|
167
184
|
- ext/mysql2/mysql2_ext.h
|
168
185
|
- ext/mysql2/result.c
|
169
186
|
- ext/mysql2/result.h
|
170
|
-
-
|
171
|
-
- lib/active_record/fiber_patches.rb
|
187
|
+
- ext/mysql2/wait_for_single_fd.h
|
172
188
|
- lib/mysql2.rb
|
173
189
|
- lib/mysql2/client.rb
|
174
190
|
- lib/mysql2/em.rb
|
175
|
-
- lib/mysql2/em_fiber.rb
|
176
191
|
- lib/mysql2/error.rb
|
177
192
|
- lib/mysql2/result.rb
|
178
193
|
- lib/mysql2/version.rb
|
179
194
|
- mysql2.gemspec
|
180
|
-
- spec/em/em_fiber_spec.rb
|
181
195
|
- spec/em/em_spec.rb
|
182
196
|
- spec/mysql2/client_spec.rb
|
183
197
|
- spec/mysql2/error_spec.rb
|
@@ -197,7 +211,6 @@ rdoc_options:
|
|
197
211
|
- --charset=UTF-8
|
198
212
|
require_paths:
|
199
213
|
- lib
|
200
|
-
- ext
|
201
214
|
required_ruby_version: !ruby/object:Gem::Requirement
|
202
215
|
none: false
|
203
216
|
requirements:
|
@@ -226,7 +239,6 @@ summary: A simple, fast Mysql library for Ruby, binding to libmysql
|
|
226
239
|
test_files:
|
227
240
|
- examples/eventmachine.rb
|
228
241
|
- examples/threaded.rb
|
229
|
-
- spec/em/em_fiber_spec.rb
|
230
242
|
- spec/em/em_spec.rb
|
231
243
|
- spec/mysql2/client_spec.rb
|
232
244
|
- spec/mysql2/error_spec.rb
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
# AR adapter for using a fibered mysql2 connection with EM
|
4
|
-
# This adapter should be used within Thin or Unicorn with the rack-fiber_pool middleware.
|
5
|
-
# Just update your database.yml's adapter to be 'em_mysql2'
|
6
|
-
|
7
|
-
module ActiveRecord
|
8
|
-
class Base
|
9
|
-
def self.em_mysql2_connection(config)
|
10
|
-
client = ::Mysql2::Fibered::Client.new(config.symbolize_keys)
|
11
|
-
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
12
|
-
ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
require 'fiber'
|
18
|
-
require 'eventmachine'
|
19
|
-
require 'mysql2'
|
20
|
-
require 'active_record/connection_adapters/mysql2_adapter'
|
21
|
-
require 'active_record/fiber_patches'
|
22
|
-
|
23
|
-
module Mysql2
|
24
|
-
module Fibered
|
25
|
-
class Client < ::Mysql2::Client
|
26
|
-
module Watcher
|
27
|
-
def initialize(client, deferable)
|
28
|
-
@client = client
|
29
|
-
@deferable = deferable
|
30
|
-
end
|
31
|
-
|
32
|
-
def notify_readable
|
33
|
-
begin
|
34
|
-
detach
|
35
|
-
results = @client.async_result
|
36
|
-
@deferable.succeed(results)
|
37
|
-
rescue Exception => e
|
38
|
-
@deferable.fail(e)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def query(sql, opts={})
|
44
|
-
if ::EM.reactor_running?
|
45
|
-
super(sql, opts.merge(:async => true))
|
46
|
-
deferrable = ::EM::DefaultDeferrable.new
|
47
|
-
::EM.watch(self.socket, Watcher, self, deferrable).notify_readable = true
|
48
|
-
fiber = Fiber.current
|
49
|
-
deferrable.callback do |result|
|
50
|
-
fiber.resume(result)
|
51
|
-
end
|
52
|
-
deferrable.errback do |err|
|
53
|
-
fiber.resume(err)
|
54
|
-
end
|
55
|
-
Fiber.yield.tap do |result|
|
56
|
-
raise result if result.is_a?(Exception)
|
57
|
-
end
|
58
|
-
else
|
59
|
-
super(sql, opts)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
# Necessary monkeypatching to make AR fiber-friendly.
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
module ConnectionAdapters
|
5
|
-
|
6
|
-
def self.fiber_pools
|
7
|
-
@fiber_pools ||= []
|
8
|
-
end
|
9
|
-
def self.register_fiber_pool(fp)
|
10
|
-
fiber_pools << fp
|
11
|
-
end
|
12
|
-
|
13
|
-
class FiberedMonitor
|
14
|
-
class Queue
|
15
|
-
def initialize
|
16
|
-
@queue = []
|
17
|
-
end
|
18
|
-
|
19
|
-
def wait(timeout)
|
20
|
-
t = timeout || 5
|
21
|
-
fiber = Fiber.current
|
22
|
-
x = EM::Timer.new(t) do
|
23
|
-
@queue.delete(fiber)
|
24
|
-
fiber.resume(false)
|
25
|
-
end
|
26
|
-
@queue << fiber
|
27
|
-
Fiber.yield.tap do
|
28
|
-
x.cancel
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def signal
|
33
|
-
fiber = @queue.pop
|
34
|
-
fiber.resume(true) if fiber
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def synchronize
|
39
|
-
yield
|
40
|
-
end
|
41
|
-
|
42
|
-
def new_cond
|
43
|
-
Queue.new
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# ActiveRecord's connection pool is based on threads. Since we are working
|
48
|
-
# with EM and a single thread, multiple fiber design, we need to provide
|
49
|
-
# our own connection pool that keys off of Fiber.current so that different
|
50
|
-
# fibers running in the same thread don't try to use the same connection.
|
51
|
-
class ConnectionPool
|
52
|
-
def initialize(spec)
|
53
|
-
@spec = spec
|
54
|
-
|
55
|
-
# The cache of reserved connections mapped to threads
|
56
|
-
@reserved_connections = {}
|
57
|
-
|
58
|
-
# The mutex used to synchronize pool access
|
59
|
-
@connection_mutex = FiberedMonitor.new
|
60
|
-
@queue = @connection_mutex.new_cond
|
61
|
-
|
62
|
-
# default 5 second timeout unless on ruby 1.9
|
63
|
-
@timeout = spec.config[:wait_timeout] || 5
|
64
|
-
|
65
|
-
# default max pool size to 5
|
66
|
-
@size = (spec.config[:pool] && spec.config[:pool].to_i) || 5
|
67
|
-
|
68
|
-
@connections = []
|
69
|
-
@checked_out = []
|
70
|
-
@automatic_reconnect = true
|
71
|
-
@tables = {}
|
72
|
-
|
73
|
-
@columns = Hash.new do |h, table_name|
|
74
|
-
h[table_name] = with_connection do |conn|
|
75
|
-
|
76
|
-
# Fetch a list of columns
|
77
|
-
conn.columns(table_name, "#{table_name} Columns").tap do |columns|
|
78
|
-
|
79
|
-
# set primary key information
|
80
|
-
columns.each do |column|
|
81
|
-
column.primary = column.name == primary_keys[table_name]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
@columns_hash = Hash.new do |h, table_name|
|
88
|
-
h[table_name] = Hash[columns[table_name].map { |col|
|
89
|
-
[col.name, col]
|
90
|
-
}]
|
91
|
-
end
|
92
|
-
|
93
|
-
@primary_keys = Hash.new do |h, table_name|
|
94
|
-
h[table_name] = with_connection do |conn|
|
95
|
-
table_exists?(table_name) ? conn.primary_key(table_name) : 'id'
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def clear_stale_cached_connections!
|
101
|
-
cache = @reserved_connections
|
102
|
-
keys = Set.new(cache.keys)
|
103
|
-
|
104
|
-
ActiveRecord::ConnectionAdapters.fiber_pools.each do |pool|
|
105
|
-
pool.busy_fibers.each_pair do |object_id, fiber|
|
106
|
-
keys.delete(object_id)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
keys.each do |key|
|
111
|
-
next unless cache.has_key?(key)
|
112
|
-
checkin cache[key]
|
113
|
-
cache.delete(key)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
private
|
118
|
-
|
119
|
-
def current_connection_id #:nodoc:
|
120
|
-
Fiber.current.object_id
|
121
|
-
end
|
122
|
-
|
123
|
-
def checkout_and_verify(c)
|
124
|
-
@checked_out << c
|
125
|
-
c.run_callbacks :checkout
|
126
|
-
c.verify!
|
127
|
-
c
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
data/lib/mysql2/em_fiber.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'mysql2/em'
|
4
|
-
require 'fiber'
|
5
|
-
|
6
|
-
module Mysql2
|
7
|
-
module EM
|
8
|
-
module Fiber
|
9
|
-
class Client < ::Mysql2::EM::Client
|
10
|
-
def query(sql, opts={})
|
11
|
-
if ::EM.reactor_running?
|
12
|
-
deferable = super(sql, opts)
|
13
|
-
|
14
|
-
fiber = ::Fiber.current
|
15
|
-
deferable.callback do |result|
|
16
|
-
fiber.resume(result)
|
17
|
-
end
|
18
|
-
deferable.errback do |err|
|
19
|
-
fiber.resume(err)
|
20
|
-
end
|
21
|
-
::Fiber.yield.tap do |result|
|
22
|
-
raise result if result.is_a?(::Exception)
|
23
|
-
end
|
24
|
-
else
|
25
|
-
super(sql, opts)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/spec/em/em_fiber_spec.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
if defined? EventMachine && defined? Fiber
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'mysql2/em_fiber'
|
5
|
-
|
6
|
-
describe Mysql2::EM::Fiber::Client do
|
7
|
-
it 'should support queries' do
|
8
|
-
results = []
|
9
|
-
EM.run do
|
10
|
-
Fiber.new {
|
11
|
-
client1 = Mysql2::EM::Fiber::Client.new
|
12
|
-
results = client1.query "SELECT sleep(0.1) as first_query"
|
13
|
-
EM.stop_event_loop
|
14
|
-
}.resume
|
15
|
-
end
|
16
|
-
|
17
|
-
results.first.keys.should include("first_query")
|
18
|
-
end
|
19
|
-
end
|
20
|
-
else
|
21
|
-
puts "Either EventMachine or Fibers not available. Skipping tests that use them."
|
22
|
-
end
|