mysql2 0.3.7 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use 1.9.2@mysql2 --create
1
+ rvm use 1.9.3@mysql2 --create
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 1.8.7
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - ree
6
+ before_script:
7
+ - "mysql -e 'create database test;' >/dev/null"
@@ -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 clases:
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 our without rails), all you should need to do is have this gem installed and set the adapter in your database.yml to "mysql2".
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
- You can also use Mysql2 with asynchronous Rails (first introduced at http://www.mikeperham.com/2010/04/03/introducing-phat-an-asynchronous-rails-app/) by
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
 
@@ -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
- xfree(wrapper->client);
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
- xfree(ptr);
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*)xmalloc(sizeof(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 = xmalloc(oldLen*2+1);
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
- xfree(newStr);
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
- xfree(newStr);
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
- // the below code is largely from do_mysql
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 (rb_thread_blocking_region(nogvl_send_query, &args, RUBY_UBF_IO, 0) == Qfalse) {
457
- // an error occurred, we're not active anymore
458
- MARK_CONN_INACTIVE(self);
459
- return rb_raise_mysql2_error(wrapper);
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 = xmalloc(oldLen*2+1);
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
- xfree(newStr);
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
- xfree(newStr);
517
+ free(newStr);
515
518
  return rb_str;
516
519
  }
517
520
  }
@@ -7,6 +7,7 @@ end
7
7
 
8
8
  # 1.9-only
9
9
  have_func('rb_thread_blocking_region')
10
+ have_func('rb_wait_for_single_fd')
10
11
 
11
12
  # borrowed from mysqlplus
12
13
  # http://github.com/oldmoe/mysqlplus/blob/master/ext/extconf.rb
@@ -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
- xfree(wrapper);
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
- inline VALUE mysql2_set_field_string_encoding(VALUE val, MYSQL_FIELD field, rb_encoding *default_internal_enc, rb_encoding *conn_enc) {
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
@@ -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, :sslciper))
34
+ ssl_set(*opts.values_at(:sslkey, :sslcert, :sslca, :sslcapath, :sslcipher))
34
35
 
35
36
  user = opts[:username]
36
37
  pass = opts[:password]
@@ -1,3 +1,3 @@
1
1
  module Mysql2
2
- VERSION = "0.3.7"
2
+ VERSION = "0.3.8"
3
3
  end
@@ -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", "ext"]
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
-
@@ -1,6 +1,7 @@
1
1
  # encoding: UTF-8
2
- if defined? EventMachine
3
- require 'spec_helper'
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
- else
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: 29
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
- - 7
10
- version: 0.3.7
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-08-17 00:00:00 -07:00
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: rspec
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: 3
59
+ hash: 49
60
60
  segments:
61
61
  - 0
62
- version: "0"
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: activerecord
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: mysql
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: do_mysql
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: sequel
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: faker
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
- - lib/active_record/connection_adapters/em_mysql2_adapter.rb
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
@@ -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
@@ -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