makara 0.3.9 → 0.3.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +35 -0
  3. data/CHANGELOG.md +23 -1
  4. data/Gemfile +1 -1
  5. data/README.md +9 -2
  6. data/gemfiles/ar-head.gemfile +10 -1
  7. data/gemfiles/ar30.gemfile +7 -3
  8. data/gemfiles/ar31.gemfile +8 -3
  9. data/gemfiles/ar32.gemfile +8 -3
  10. data/gemfiles/ar40.gemfile +10 -3
  11. data/gemfiles/ar41.gemfile +10 -3
  12. data/gemfiles/ar42.gemfile +10 -3
  13. data/gemfiles/ar50.gemfile +10 -1
  14. data/gemfiles/ar51.gemfile +10 -1
  15. data/lib/active_record/connection_adapters/makara_abstract_adapter.rb +3 -3
  16. data/lib/makara/cache/memory_store.rb +4 -1
  17. data/lib/makara/connection_wrapper.rb +2 -2
  18. data/lib/makara/pool.rb +4 -7
  19. data/lib/makara/proxy.rb +0 -1
  20. data/lib/makara/strategies/round_robin.rb +6 -0
  21. data/lib/makara/version.rb +1 -1
  22. data/spec/active_record/connection_adapters/makara_abstract_adapter_spec.rb +10 -1
  23. data/spec/active_record/connection_adapters/makara_mysql2_adapter_spec.rb +16 -1
  24. data/spec/active_record/connection_adapters/makara_postgis_adapter_spec.rb +10 -5
  25. data/spec/active_record/connection_adapters/makara_postgresql_adapter_spec.rb +17 -1
  26. data/spec/cache_spec.rb +22 -0
  27. data/spec/connection_wrapper_spec.rb +5 -2
  28. data/spec/spec_helper.rb +2 -0
  29. data/spec/support/mysql2_database.yml +1 -0
  30. data/spec/support/mysql2_database_with_custom_errors.yml +5 -0
  31. data/spec/support/postgis_database.yml +2 -0
  32. data/spec/support/postgis_schema.rb +6 -3
  33. data/spec/support/postgresql_database.yml +2 -0
  34. data/spec/support/schema.rb +5 -5
  35. data/spec/support/user.rb +5 -0
  36. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2285d0c3c177997ec9e9d8568225f3a1ed1bdf28
4
- data.tar.gz: 953d024813b8bd5bae579665a3988c5770f63d38
3
+ metadata.gz: 4dc4867024ed5527a9b0a499e4daff0c9c4bac5e
4
+ data.tar.gz: 170743d2e7f735b39fbcb477657643918c66cd32
5
5
  SHA512:
6
- metadata.gz: dc7a2f84b22a57f83d1eb3ef4e615975e405f97b150b6b8d6c4e39b4833b4daa28036f7d838cd2062e64c4cc1ca015f519cf0d91c6c3a8f5f25ea85229e4e3e6
7
- data.tar.gz: 528f91cff15ebd34a460d4f79f01679dd457641904df4834ae8179d735a461d23e8dfdae59971bffb019e62aaaabacb8aa36f440bd2165e5ca2835e58a69f8e4
6
+ metadata.gz: 8da212514ba19441a154323990544bb18ce0a3a39ff133f227bab84790e48b747f254b53d9a59c2aa93cfad0f0367fd03a44d3bcbe94a17874e7f2b084bec468
7
+ data.tar.gz: 731c52cd786a65d0a124edf94e1f721b69ec78cee0549d499b2cc35a5ac2210aa7ae87d8b22a3734829271ea538ed6b3cfb197fd1ebc2d4ce0f961d16e86afda
@@ -1,11 +1,15 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  cache: bundler
4
+ dist: precise
4
5
 
5
6
  services:
6
7
  - mysql
7
8
  - postgresql
8
9
 
10
+ before_install:
11
+ - gem install bundler
12
+
9
13
  before_script:
10
14
  - mysql -e 'create database makara_test;'
11
15
  - psql -c 'create database makara_test;' -U postgres
@@ -17,6 +21,7 @@ rvm:
17
21
  - 2.2
18
22
  - 2.3
19
23
  - 2.4
24
+ - 2.5.0
20
25
  - ruby-head
21
26
  - jruby
22
27
 
@@ -43,8 +48,34 @@ matrix:
43
48
  rvm: 2.3
44
49
  - gemfile: gemfiles/ar30.gemfile
45
50
  rvm: 2.4
51
+ - gemfile: gemfiles/ar31.gemfile
52
+ rvm: 2.4
53
+ - gemfile: gemfiles/ar32.gemfile
54
+ rvm: 2.4
55
+ - gemfile: gemfiles/ar40.gemfile
56
+ rvm: 2.4
57
+ - gemfile: gemfiles/ar41.gemfile
58
+ rvm: 2.4
59
+ - gemfile: gemfiles/ar30.gemfile
60
+ rvm: 2.5.0
61
+ - gemfile: gemfiles/ar31.gemfile
62
+ rvm: 2.5.0
63
+ - gemfile: gemfiles/ar32.gemfile
64
+ rvm: 2.5.0
65
+ - gemfile: gemfiles/ar40.gemfile
66
+ rvm: 2.5.0
67
+ - gemfile: gemfiles/ar41.gemfile
68
+ rvm: 2.5.0
46
69
  - gemfile: gemfiles/ar30.gemfile
47
70
  rvm: ruby-head
71
+ - gemfile: gemfiles/ar31.gemfile
72
+ rvm: ruby-head
73
+ - gemfile: gemfiles/ar32.gemfile
74
+ rvm: ruby-head
75
+ - gemfile: gemfiles/ar40.gemfile
76
+ rvm: ruby-head
77
+ - gemfile: gemfiles/ar41.gemfile
78
+ rvm: ruby-head
48
79
  - gemfile: gemfiles/ar50.gemfile
49
80
  rvm: 2.0
50
81
  - gemfile: gemfiles/ar50.gemfile
@@ -63,6 +94,10 @@ matrix:
63
94
  rvm: 2.1
64
95
  - gemfile: gemfiles/ar-head.gemfile
65
96
  rvm: 2.2
97
+ - gemfile: gemfiles/ar-head.gemfile
98
+ rvm: 2.3
99
+ - gemfile: gemfiles/ar-head.gemfile
100
+ rvm: 2.4
66
101
  allow_failures:
67
102
  - gemfile: gemfiles/ar-head.gemfile
68
103
  - rvm: ruby-head
@@ -1,7 +1,29 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## v0.3.8 - 2016-07-11
4
+ ## v0.3.9 - 2013-03-20
5
+ [Full Changelog](https://github.com/taskrabbit/makara/compare/v0.3.9...v0.3.10)
6
+
7
+ Fixed
8
+ - Send nextval queries to master and show queries to replicas for Postgres [#173](https://github.com/taskrabbit/makara/pull/173) Andrew Kane
9
+ - Fixes can't add a new key into hash during iteration error [#174](https://github.com/taskrabbit/makara/pull/174) Andrew Kane
10
+ - Fix: an application freezes when a slave is down [#180](https://github.com/taskrabbit/makara/pull/180) Alexey P
11
+ - Allow SELECTs that use common table expressions to go to replicas [#184](https://github.com/taskrabbit/makara/pull/184) Andrew Kane
12
+ - Send advisory lock requests to the master [#198](https://github.com/taskrabbit/makara/pull/198) George Claghorn
13
+ - Postgres exists query [#199](https://github.com/taskrabbit/makara/pull/199) Brian Leonard
14
+
15
+ Documentation and Test
16
+ - Clarify README's "What goes where" [#187](https://github.com/taskrabbit/makara/pull/187) Jan Sandbrink
17
+ - Fix loading fixtures in Rails 5.2 [#192](https://github.com/taskrabbit/makara/pull/192) George Claghorn
18
+ - Travis Upgrade [#199](https://github.com/taskrabbit/makara/pull/199) Brian Leonard
19
+
20
+ ## v0.3.9 - 2017-08-14
21
+ [Full Changelog](https://github.com/taskrabbit/makara/compare/v0.3.8...v0.3.9)
22
+
23
+ Changed
24
+ - Add postgis support [#118](https://github.com/taskrabbit/makara/pull/118) Kevin Bacha
25
+
26
+ ## v0.3.8 - 2017-07-11
5
27
 
6
28
  [Full Changelog](https://github.com/taskrabbit/makara/compare/v0.3.7...v0.3.8)
7
29
 
data/Gemfile CHANGED
@@ -11,7 +11,7 @@ gem 'ruby-debug', :platform => :jruby
11
11
  gem 'rack', '1.6.0'
12
12
 
13
13
  gem 'mysql2', :platform => :ruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-postgis-adapter', :platform => :ruby
16
16
  gem 'rgeo', :platform => :ruby
17
17
 
data/README.md CHANGED
@@ -120,7 +120,13 @@ By creating a makara database adapter which simply acts as a proxy we avoid any
120
120
 
121
121
  ### What goes where?
122
122
 
123
- Any `SELECT` statements will execute against your slave(s), anything else will go to master. The only edge case is `SET` operations which are sent to all connections. Execution of specific methods such as `connect!`, `disconnect!`, and `clear_cache!` are invoked on all underlying connections.
123
+ In general: Any `SELECT` statements will execute against your slave(s), anything else will go to master.
124
+
125
+ There are some edge cases:
126
+ * `SET` operations will be sent to all connections
127
+ * Execution of specific methods such as `connect!`, `disconnect!`, and `clear_cache!` are invoked on all underlying connections
128
+ * Calls inside a transaction will always be sent to the master (otherwise changes from within the transaction could not be read back on most transaction isolation levels)
129
+ * Locking reads (e.g. `SELECT ... FOR UPDATE`) will always be sent to the master
124
130
 
125
131
  ### Errors / blacklisting
126
132
 
@@ -165,7 +171,8 @@ The makara subconfig sets up the proxy with a few of its own options, then provi
165
171
  * disable_blacklist - do not blacklist node at any error, useful in case of one master
166
172
  * sticky - if a node should be stuck to once it's used during a specific context
167
173
  * master_ttl - how long the master context is persisted. generally, this needs to be longer than any replication lag
168
- * master_strategy - use a different strategy for picking the "current" node: `failover` will try to keep the same one until it is blacklisted. The default is `round_robin` which will cycle through available ones.
174
+ * master_strategy - use a different strategy for picking the "current" master node: `failover` will try to keep the same one until it is blacklisted. The default is `round_robin` which will cycle through available ones.
175
+ * slave_strategy - use a different strategy for picking the "current" slave node: `failover` will try to keep the same one until it is blacklisted. The default is `round_robin` which will cycle through available ones.
169
176
  * connection_error_matchers - array of custom error matchers you want to be handled gracefully by Makara (as in, errors matching these regexes will result in blacklisting the connection as opposed to raising directly).
170
177
 
171
178
  Connection definitions contain any extra node-specific configurations. If the node should behave as a master you must provide `role: master`. Any previous configurations can be overridden within a specific node's config. Nodes can also contain weights if you'd like to balance usage based on hardware specifications. Optionally, you can provide a name attribute which will be used in sql logging.
@@ -11,5 +11,14 @@ gem 'rack'
11
11
  gem 'timecop'
12
12
  gem 'mysql2', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
16
+
17
+
18
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
+
20
+ # 2.1 +
21
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
22
+ gem 'activerecord-postgis-adapter', :platform => :ruby
23
+ gem 'rgeo', :platform => :ruby
24
+ end
@@ -12,8 +12,6 @@ gem 'i18n', '~> 0.5.0'
12
12
  gem 'mysql2', '0.2.11', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
14
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
15
- gem 'activerecord-postgis-adapter', :platform => :ruby
16
- gem 'rgeo', :platform => :ruby
17
15
 
18
16
 
19
17
  rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
@@ -28,5 +26,11 @@ end
28
26
  if rmajor == 1 && (rminor == 8 || (rminor == 9 && rpatch < 3))
29
27
  gem 'pg', '0.17.1', :platform => :ruby
30
28
  else
31
- gem 'pg', :platform => :ruby
29
+ gem 'pg', '0.21.0', :platform => :ruby
30
+ end
31
+
32
+ # 2.1 +
33
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
34
+ gem 'activerecord-postgis-adapter', :platform => :ruby
35
+ gem 'rgeo', :platform => :ruby
32
36
  end
@@ -12,8 +12,7 @@ gem 'i18n', '~> 0.6.0'
12
12
  gem 'mysql2', '~> 0.3.10', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
14
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
15
- gem 'activerecord-postgis-adapter', :platform => :ruby
16
- gem 'rgeo', :platform => :ruby
15
+
17
16
 
18
17
  rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
18
 
@@ -27,5 +26,11 @@ end
27
26
  if rmajor == 1 && (rminor == 8 || (rminor == 9 && rpatch < 3))
28
27
  gem 'pg', '0.17.1', :platform => :ruby
29
28
  else
30
- gem 'pg', :platform => :ruby
29
+ gem 'pg', '0.21.0', :platform => :ruby
30
+ end
31
+
32
+ # 2.1 +
33
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
34
+ gem 'activerecord-postgis-adapter', :platform => :ruby
35
+ gem 'rgeo', :platform => :ruby
31
36
  end
@@ -12,8 +12,7 @@ gem 'i18n', '~> 0.6.0'
12
12
  gem 'mysql2', '~> 0.3.10', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
14
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
15
- gem 'activerecord-postgis-adapter', :platform => :ruby
16
- gem 'rgeo', :platform => :ruby
15
+
17
16
 
18
17
  rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
18
 
@@ -27,5 +26,11 @@ end
27
26
  if rmajor == 1 && (rminor == 8 || (rminor == 9 && rpatch < 3))
28
27
  gem 'pg', '0.17.1', :platform => :ruby
29
28
  else
30
- gem 'pg', :platform => :ruby
29
+ gem 'pg', '0.21.0', :platform => :ruby
30
+ end
31
+
32
+ # 2.1 +
33
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
34
+ gem 'activerecord-postgis-adapter', :platform => :ruby
35
+ gem 'rgeo', :platform => :ruby
31
36
  end
@@ -11,7 +11,14 @@ gem 'rack', '1.6.0'
11
11
  gem 'timecop'
12
12
  gem 'mysql2', '~> 0.3.10', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
16
- gem 'activerecord-postgis-adapter', :platform => :ruby
17
- gem 'rgeo', :platform => :ruby
16
+
17
+
18
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
+
20
+ # 2.1 +
21
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
22
+ gem 'activerecord-postgis-adapter', :platform => :ruby
23
+ gem 'rgeo', :platform => :ruby
24
+ end
@@ -11,7 +11,14 @@ gem 'rack', '1.6.0'
11
11
  gem 'timecop'
12
12
  gem 'mysql2', '~> 0.3.10', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
16
- gem 'activerecord-postgis-adapter', :platform => :ruby
17
- gem 'rgeo', :platform => :ruby
16
+
17
+
18
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
+
20
+ # 2.1 +
21
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
22
+ gem 'activerecord-postgis-adapter', :platform => :ruby
23
+ gem 'rgeo', :platform => :ruby
24
+ end
@@ -11,7 +11,14 @@ gem 'rack', '1.6.0'
11
11
  gem 'timecop'
12
12
  gem 'mysql2', '~> 0.3.10', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
16
- gem 'activerecord-postgis-adapter', :platform => :ruby
17
- gem 'rgeo', :platform => :ruby
16
+
17
+
18
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
+
20
+ # 2.1 +
21
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
22
+ gem 'activerecord-postgis-adapter', :platform => :ruby
23
+ gem 'rgeo', :platform => :ruby
24
+ end
@@ -11,5 +11,14 @@ gem 'rack'
11
11
  gem 'timecop'
12
12
  gem 'mysql2', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
16
+
17
+
18
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
+
20
+ # 2.1 +
21
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
22
+ gem 'activerecord-postgis-adapter', :platform => :ruby
23
+ gem 'rgeo', :platform => :ruby
24
+ end
@@ -11,5 +11,14 @@ gem 'rack'
11
11
  gem 'timecop'
12
12
  gem 'mysql2', :platform => :ruby
13
13
  gem 'activerecord-jdbcmysql-adapter', :platform => :jruby
14
- gem 'pg', :platform => :ruby
14
+ gem 'pg', '0.21.0', :platform => :ruby
15
15
  gem 'activerecord-jdbcpostgresql-adapter', :platform => :jruby
16
+
17
+
18
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
19
+
20
+ # 2.1 +
21
+ if rmajor > 2 || (rmajor == 2 && rminor >= 1)
22
+ gem 'activerecord-postgis-adapter', :platform => :ruby
23
+ gem 'rgeo', :platform => :ruby
24
+ end
@@ -105,11 +105,11 @@ module ActiveRecord
105
105
  end
106
106
 
107
107
 
108
- hijack_method :execute, :select_rows, :exec_query, :transaction
108
+ hijack_method :execute, :exec_query, :exec_no_cache, :exec_cache, :transaction
109
109
  send_to_all :connect, :reconnect!, :verify!, :clear_cache!, :reset!
110
110
 
111
- SQL_MASTER_MATCHERS = [/\A\s*select.+for update\Z/i, /select.+lock in share mode\Z/i].map(&:freeze).freeze
112
- SQL_SLAVE_MATCHERS = [/\A\s*select\s/i].map(&:freeze).freeze
111
+ SQL_MASTER_MATCHERS = [/\A\s*select.+for update\Z/i, /select.+lock in share mode\Z/i, /\A\s*select.+(nextval|currval|lastval|get_lock|release_lock|pg_advisory_lock|pg_advisory_unlock)\(/i].map(&:freeze).freeze
112
+ SQL_SLAVE_MATCHERS = [/\A\s*(select|with.+\)\s*select)\s/i].map(&:freeze).freeze
113
113
  SQL_ALL_MATCHERS = [/\A\s*set\s/i].map(&:freeze).freeze
114
114
  SQL_SKIP_STICKINESS_MATCHERS = [/\A\s*show\s([\w]+\s)?(field|table|database|schema|view|index)(es|s)?/i, /\A\s*(set|describe|explain|pragma)\s/i].map(&:freeze).freeze
115
115
 
@@ -4,6 +4,7 @@ module Makara
4
4
 
5
5
  def initialize
6
6
  @data = {}
7
+ @mutex = Mutex.new
7
8
  end
8
9
 
9
10
  def read(key)
@@ -20,7 +21,9 @@ module Makara
20
21
  protected
21
22
 
22
23
  def clean
23
- @data.delete_if{|k,v| v[1] <= Time.now.to_i }
24
+ @mutex.synchronize do
25
+ @data.delete_if{|k,v| v[1] <= Time.now.to_i }
26
+ end
24
27
  end
25
28
 
26
29
  end
@@ -146,10 +146,10 @@ module Makara
146
146
  # The new definition should allow for the proxy to intercept the invocation if required.
147
147
  @proxy.class.hijack_methods.each do |meth|
148
148
  extension << %Q{
149
- def #{meth}(*args)
149
+ def #{meth}(*args, &block)
150
150
  _makara_hijack do |proxy|
151
151
  if proxy
152
- proxy.#{meth}(*args)
152
+ proxy.#{meth}(*args, &block)
153
153
  else
154
154
  super
155
155
  end
@@ -64,17 +64,14 @@ module Makara
64
64
  @connections.each do |con|
65
65
  next if con._makara_blacklisted?
66
66
  begin
67
- if block
68
- value = @proxy.error_handler.handle(con) do
67
+ ret = @proxy.error_handler.handle(con) do
68
+ if block
69
69
  yield con
70
+ else
71
+ con.send(method, *args)
70
72
  end
71
73
  end
72
74
 
73
- if method
74
- ret = con.send(method, *args)
75
- else
76
- ret = value
77
- end
78
75
  one_worked = true
79
76
  rescue Makara::Errors::BlacklistConnection => e
80
77
  errors.insert(0, e)
@@ -182,7 +182,6 @@ module Makara
182
182
 
183
183
  # for testing purposes
184
184
  pool = _appropriate_pool(method_name, args)
185
-
186
185
  yield pool
187
186
 
188
187
  rescue ::Makara::Errors::AllConnectionsBlacklisted, ::Makara::Errors::NoConnectionsAvailable => e
@@ -23,6 +23,8 @@ module Makara
23
23
  end
24
24
 
25
25
  def next
26
+ return safe_value(0, true) if single_one?
27
+
26
28
  idx = @current_idx
27
29
  begin
28
30
 
@@ -67,6 +69,10 @@ module Makara
67
69
  def should_shuffle?
68
70
  true
69
71
  end
72
+
73
+ def single_one?
74
+ false
75
+ end
70
76
  end
71
77
  end
72
78
  end
@@ -3,7 +3,7 @@ module Makara
3
3
 
4
4
  MAJOR = 0
5
5
  MINOR = 3
6
- PATCH = 9
6
+ PATCH = 10
7
7
  PRE = nil
8
8
 
9
9
  def self.to_s
@@ -27,7 +27,16 @@ describe ActiveRecord::ConnectionAdapters::MakaraAbstractAdapter do
27
27
  ' select * from users for update' => true,
28
28
  'select * from users lock in share mode' => true,
29
29
  'select * from users where name = "for update"' => false,
30
- 'select * from users where name = "lock in share mode"' => false
30
+ 'select * from users where name = "lock in share mode"' => false,
31
+ 'select nextval(\'users_id_seq\')' => true,
32
+ 'select currval(\'users_id_seq\')' => true,
33
+ 'select lastval()' => true,
34
+ 'with fence as (select * from users) select * from fence' => false,
35
+ 'with fence as (select * from felines) insert to cats' => true,
36
+ 'select get_lock(\'foo\', 0)' => true,
37
+ 'select release_lock(\'foo\')' => true,
38
+ 'select pg_advisory_lock(12345)' => true,
39
+ 'select pg_advisory_unlock(12345)' => true
31
40
  }.each do |sql, should_go_to_master|
32
41
 
33
42
  it "determines that \"#{sql}\" #{should_go_to_master ? 'requires' : 'does not require'} master" do
@@ -150,7 +150,7 @@ describe 'MakaraMysql2Adapter' do
150
150
 
151
151
  it 'should send reads to the slave' do
152
152
  # ensure the next connection will be the first one
153
- connection.slave_pool.strategy.instance_variable_set('@current_idx', connection.slave_pool.connections.length)
153
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
154
154
 
155
155
  con = connection.slave_pool.connections.first
156
156
  expect(con).to receive(:execute).with('SELECT * FROM users').once
@@ -158,6 +158,21 @@ describe 'MakaraMysql2Adapter' do
158
158
  connection.execute('SELECT * FROM users')
159
159
  end
160
160
 
161
+ it 'should send exists? to slave' do
162
+ next if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0 # query doesn't work?
163
+
164
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
165
+ Test::User.exists? # flush other (schema) things that need to happen
166
+
167
+ con = connection.slave_pool.connections.first
168
+ if (ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR <= 0)
169
+ expect(con).to receive(:execute).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
170
+ else
171
+ expect(con).to receive(:exec_query).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
172
+ end
173
+ Test::User.exists?
174
+ end
175
+
161
176
  it 'should send writes to master' do
162
177
  con = connection.master_pool.connections.first
163
178
  expect(con).to receive(:execute).with('UPDATE users SET name = "bob" WHERE id = 1')
@@ -1,8 +1,16 @@
1
1
  # RGeo doesn't play well with JRuby and to avoid complicated test setup
2
2
  # we're only testing ActiveRecord version ~> 4.2
3
+ # also rgeo only works on 2.1+
4
+
5
+ rmajor, rminor, rpatch = RUBY_VERSION.split(/[^\d]/)[0..2].map(&:to_i)
6
+ require 'active_record'
7
+
8
+ # TODO: test this in AR 5+ ?
9
+
3
10
  if RUBY_ENGINE == 'ruby' &&
4
11
  ActiveRecord::VERSION::MAJOR == 4 &&
5
- ActiveRecord::VERSION::MINOR >= 2
12
+ ActiveRecord::VERSION::MINOR >= 2 &&
13
+ (rmajor > 2 || (rmajor == 2 && rminor >= 1))
6
14
 
7
15
  require 'spec_helper'
8
16
  require 'rgeo'
@@ -83,10 +91,7 @@ if RUBY_ENGINE == 'ruby' &&
83
91
 
84
92
  it 'should send reads to the slave' do
85
93
  # ensure the next connection will be the first one
86
- connection.slave_pool
87
- .strategy
88
- .instance_variable_set('@current_idx',
89
- connection.slave_pool.connections.length)
94
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
90
95
 
91
96
  con = connection.slave_pool.connections.first
92
97
  expect(con).to receive(:execute).with('SELECT * FROM users').once
@@ -64,7 +64,7 @@ describe 'MakaraPostgreSQLAdapter' do
64
64
 
65
65
  it 'should send reads to the slave' do
66
66
  # ensure the next connection will be the first one
67
- connection.slave_pool.strategy.instance_variable_set('@current_idx', connection.slave_pool.connections.length)
67
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
68
68
 
69
69
  con = connection.slave_pool.connections.first
70
70
  expect(con).to receive(:execute).with('SELECT * FROM users').once
@@ -72,6 +72,22 @@ describe 'MakaraPostgreSQLAdapter' do
72
72
  connection.execute('SELECT * FROM users')
73
73
  end
74
74
 
75
+ it 'should send exists? to slave' do
76
+ next if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0 # query doesn't work?
77
+
78
+ allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:single_one?){ true }
79
+ Test::User.exists? # flush other (schema) things that need to happen
80
+
81
+ con = connection.slave_pool.connections.first
82
+ if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 2) ||
83
+ (ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR <= 0)
84
+ expect(con).to receive(:exec_no_cache).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
85
+ else
86
+ expect(con).to receive(:exec_query).with(/SELECT\s+1\s*(AS one)?\s+FROM .?users.?\s+LIMIT\s+.?1/, any_args).once.and_call_original
87
+ end
88
+ Test::User.exists?
89
+ end
90
+
75
91
  it 'should send writes to master' do
76
92
  con = connection.master_pool.connections.first
77
93
  expect(con).to receive(:execute).with('UPDATE users SET name = "bob" WHERE id = 1')
@@ -52,6 +52,28 @@ describe Makara::Cache do
52
52
  expect(data).not_to have_key('test')
53
53
  end
54
54
 
55
+ it 'has thread-safety' do
56
+ store = Makara::Cache::MemoryStore.new
57
+ previous_value = Thread.abort_on_exception
58
+
59
+ begin
60
+ Thread.abort_on_exception = true
61
+
62
+ workers = 2.times.map do
63
+ Thread.new do
64
+ 100.times do |n|
65
+ store.write(n, 'value', expires_in: 0.5)
66
+ sleep(0.01)
67
+ end
68
+ end
69
+ end
70
+
71
+ expect { workers.map(&:join) }.to_not raise_error
72
+ ensure
73
+ Thread.abort_on_exception = previous_value
74
+ end
75
+ end
76
+
55
77
  end
56
78
 
57
79
 
@@ -14,8 +14,11 @@ describe Makara::ConnectionWrapper do
14
14
  end
15
15
 
16
16
  it 'should invoke hijacked methods on the proxy when invoked directly' do
17
- expect(proxy).to receive(:execute).with('test').once
18
- connection.execute("test")
17
+ expect(proxy).to receive(:execute).with('test').once do |&block|
18
+ expect(block.call).to eq('Hello')
19
+ end
20
+
21
+ connection.execute('test') { 'Hello' }
19
22
  end
20
23
 
21
24
  it 'should have a default weight of 1' do
@@ -24,6 +24,7 @@ RSpec.configure do |config|
24
24
  require "#{File.dirname(__FILE__)}/support/pool_extensions"
25
25
  require "#{File.dirname(__FILE__)}/support/mock_objects"
26
26
  require "#{File.dirname(__FILE__)}/support/deep_dup"
27
+ require "#{File.dirname(__FILE__)}/support/user"
27
28
 
28
29
  config.include SpecHelpers
29
30
 
@@ -31,6 +32,7 @@ RSpec.configure do |config|
31
32
  Makara::Cache.store = :memory
32
33
  change_context
33
34
  allow_any_instance_of(Makara::Strategies::RoundRobin).to receive(:should_shuffle?){ false }
35
+ RSpec::Mocks.space.proxy_for(ActiveRecord::Base).reset # make sure not stubbed in some way
34
36
  end
35
37
 
36
38
  def change_context
@@ -4,6 +4,7 @@ test:
4
4
  username: 'root'
5
5
  password: ''
6
6
 
7
+ timeout: 5000
7
8
  connect_timeout: 1
8
9
  read_timeout: 1
9
10
  write_timeout: 2
@@ -4,6 +4,11 @@ test:
4
4
  username: 'root'
5
5
  password: ''
6
6
 
7
+ timeout: 5000
8
+ connect_timeout: 1
9
+ read_timeout: 1
10
+ write_timeout: 2
11
+
7
12
  makara:
8
13
  blacklist_duration: 2
9
14
  master_ttl: 5
@@ -4,6 +4,8 @@ test:
4
4
  username: 'root'
5
5
  password: ''
6
6
 
7
+ timeout: 5000
8
+
7
9
  makara:
8
10
  blacklist_duration: 2
9
11
  master_ttl: 5
@@ -1,8 +1,11 @@
1
+ conn = ActiveRecord::Base.connection
1
2
 
2
- ActiveRecord::Schema.define(:version => 20160518161227) do
3
- execute "create extension if not exists postgis"
3
+ conn.execute "create extension if not exists postgis"
4
4
 
5
- create_table "towns", :force => true do |t|
5
+ if conn.table_exists? "towns"
6
+ conn.execute("TRUNCATE TABLE towns")
7
+ else
8
+ conn.create_table "towns", :force => true do |t|
6
9
  t.st_point "location"
7
10
  end
8
11
  end
@@ -4,6 +4,8 @@ test:
4
4
  username: 'root'
5
5
  password: ''
6
6
 
7
+ timeout: 5000
8
+
7
9
  makara:
8
10
  blacklist_duration: 2
9
11
  master_ttl: 5
@@ -1,9 +1,9 @@
1
- ActiveRecord::Schema.define(:version => 20130628161227) do
1
+ conn = ActiveRecord::Base.connection
2
2
 
3
- drop_table "users" if table_exists? "users"
4
-
5
- create_table "users" do |t|
3
+ if conn.table_exists? "users"
4
+ conn.execute("TRUNCATE TABLE users")
5
+ else
6
+ conn.create_table "users" do |t|
6
7
  t.string "name"
7
8
  end
8
-
9
9
  end
@@ -0,0 +1,5 @@
1
+ module Test
2
+ class User < ::ActiveRecord::Base
3
+
4
+ end
5
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: makara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
4
+ version: 0.3.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-14 00:00:00.000000000 Z
11
+ date: 2018-03-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -108,6 +108,7 @@ files:
108
108
  - spec/support/postgresql_database.yml
109
109
  - spec/support/proxy_extensions.rb
110
110
  - spec/support/schema.rb
111
+ - spec/support/user.rb
111
112
  homepage: ''
112
113
  licenses: []
113
114
  metadata: {}
@@ -158,3 +159,4 @@ test_files:
158
159
  - spec/support/postgresql_database.yml
159
160
  - spec/support/proxy_extensions.rb
160
161
  - spec/support/schema.rb
162
+ - spec/support/user.rb