global_uid 1.4.0 → 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,6 +48,10 @@ module GlobalUid
48
48
  @global_uid_disabled = true
49
49
  end
50
50
 
51
+ def enable_global_uid
52
+ @global_uid_disabled = false
53
+ end
54
+
51
55
  def global_uid_table
52
56
  GlobalUid::Base.id_table_from_name(self.table_name)
53
57
  end
@@ -61,7 +61,7 @@ module GlobalUid
61
61
  GlobalUidTimer = Timeout
62
62
  end
63
63
 
64
- def self.new_connection(name, connection_timeout, offset, increment_by, use_server_variables)
64
+ def self.new_connection(name, connection_timeout, offset, increment_by)
65
65
  raise "No id server '#{name}' configured in database.yml" unless ActiveRecord::Base.configurations.has_key?(name)
66
66
  config = ActiveRecord::Base.configurations[name]
67
67
  c = config.symbolize_keys
@@ -81,14 +81,6 @@ module GlobalUid
81
81
  return nil
82
82
  end
83
83
 
84
- # Please note that this is unreliable -- if you lose your CX to the server
85
- # and auto-reconnect, you will be utterly hosed. Much better to dedicate a server
86
- # or two to the cause, and set their auto_increment_increment globally.
87
- if use_server_variables
88
- con.execute("set @@auto_increment_increment = #{increment_by}")
89
- con.execute("set @@auto_increment_offset = #{offset}")
90
- end
91
-
92
84
  con
93
85
  end
94
86
 
@@ -133,7 +125,7 @@ module GlobalUid
133
125
  if info[:new?] || ( info[:retry_at] && Time.now > info[:retry_at] )
134
126
  info[:new?] = false
135
127
 
136
- connection = new_connection(info[:name], connection_timeout, info[:offset], increment_by, options[:use_server_variables])
128
+ connection = new_connection(info[:name], connection_timeout, info[:offset], increment_by)
137
129
  info[:cx] = connection
138
130
  info[:retry_at] = Time.now + options[:connection_retry] if connection.nil?
139
131
  end
@@ -0,0 +1,29 @@
1
+ # This module is good for testing and development, not so much for production.
2
+ # Please note that this is unreliable -- if you lose your CX to the server
3
+ # and auto-reconnect, you will be utterly hosed. Much better to dedicate a server
4
+ # or two to the cause, and set their auto_increment_increment globally.
5
+ #
6
+ # You can include this module in tests like this:
7
+ # GlobalUid::Base.extend(GlobalUid::ServerVariables)
8
+ #
9
+ module GlobalUid
10
+ module ServerVariables
11
+
12
+ def self.extended(base)
13
+ base.singleton_class.send(:alias_method, :new_connection_without_server_variables, :new_connection)
14
+ base.singleton_class.send(:alias_method, :new_connection, :new_connection_with_server_variables)
15
+ end
16
+
17
+ def new_connection_with_server_variables(name, connection_timeout, offset, increment_by)
18
+ con = new_connection_without_server_variables(name, connection_timeout, offset, increment_by)
19
+
20
+ if con
21
+ con.execute("set @@auto_increment_increment = #{increment_by}")
22
+ con.execute("set @@auto_increment_offset = #{offset}")
23
+ end
24
+
25
+ con
26
+ end
27
+
28
+ end
29
+ end
data/lib/global_uid.rb CHANGED
@@ -3,11 +3,13 @@ require "global_uid/active_record_extension"
3
3
  require "global_uid/migration_extension"
4
4
 
5
5
  module GlobalUid
6
- VERSION = "1.3.1"
6
+ VERSION = "1.4.1"
7
7
 
8
8
  class NoServersAvailableException < Exception ; end
9
9
  class ConnectionTimeoutException < Exception ; end
10
10
  class TimeoutException < Exception ; end
11
+
12
+ autoload :ServerVariables, "global_uid/server_variables"
11
13
  end
12
14
 
13
15
  ActiveRecord::Base.send(:include, GlobalUid::ActiveRecordExtension)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: global_uid
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.0
4
+ version: 1.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-01 00:00:00.000000000 Z
12
+ date: 2014-06-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -139,35 +139,38 @@ dependencies:
139
139
  - - ! '>='
140
140
  - !ruby/object:Gem::Version
141
141
  version: '0'
142
+ - !ruby/object:Gem::Dependency
143
+ name: test-unit
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ type: :development
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
142
158
  description: GUIDs for sharded models
143
159
  email: ben@zendesk.com
144
160
  executables: []
145
161
  extensions: []
146
- extra_rdoc_files:
147
- - README.md
162
+ extra_rdoc_files: []
148
163
  files:
149
- - Appraisals
150
- - Gemfile
151
- - README.md
152
- - Rakefile
153
- - gemfiles/rails2.gemfile
154
- - gemfiles/rails2.gemfile.lock
155
- - gemfiles/rails2mysql2.gemfile.lock
156
- - gemfiles/rails3.gemfile
157
- - gemfiles/rails3.gemfile.lock
158
- - global_uid.gemspec
159
164
  - lib/global_uid.rb
160
165
  - lib/global_uid/active_record_extension.rb
161
166
  - lib/global_uid/base.rb
162
167
  - lib/global_uid/migration_extension.rb
163
- - test/config/database.yml.example
164
- - test/global_uid_test.rb
165
- - test/test_helper.rb
166
- homepage: http://github.com/zendesk/global_uid
167
- licenses: []
168
+ - lib/global_uid/server_variables.rb
169
+ homepage: https://github.com/zendesk/global_uid
170
+ licenses:
171
+ - MIT
168
172
  post_install_message:
169
- rdoc_options:
170
- - --charset=UTF-8
173
+ rdoc_options: []
171
174
  require_paths:
172
175
  - lib
173
176
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -181,13 +184,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
181
184
  requirements:
182
185
  - - ! '>='
183
186
  - !ruby/object:Gem::Version
184
- version: 1.3.6
187
+ version: '0'
185
188
  requirements: []
186
- rubyforge_project: global_uid
187
- rubygems_version: 1.8.24
189
+ rubyforge_project:
190
+ rubygems_version: 1.8.23.2
188
191
  signing_key:
189
- specification_version: 2
192
+ specification_version: 3
190
193
  summary: GUID
191
- test_files:
192
- - test/global_uid_test.rb
193
- - test/test_helper.rb
194
+ test_files: []
data/Appraisals DELETED
@@ -1,12 +0,0 @@
1
- appraise "rails2" do
2
- gem "activerecord", "2.3.14"
3
- end
4
-
5
- appraise "rails2mysql2" do
6
- gem "activerecord", "2.3.14"
7
- gem "mysql2", :git => "git://github.com/osheroff/mysql2.git", :ref => "a1ab7ba"
8
- end
9
-
10
- appraise "rails3" do
11
- gem "activerecord", "3.2.2"
12
- end
data/Gemfile DELETED
@@ -1,6 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec
4
-
5
- gem "ruby-debug", :platform => "mri_18", :group => "test"
6
- gem "debugger", :platform => "mri_19", :require => "ruby-debug", :group => "test"
data/README.md DELETED
@@ -1,130 +0,0 @@
1
- # Global UID Plugin
2
-
3
- ## Summary
4
-
5
- This plugin does a lot of the heavy lifting needed to have an external MySQL based global id generator as described in this article from Flickr
6
-
7
- (http://code.flickr.com/blog/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/)
8
-
9
- There are three parts to it: configuration, migration and object creation
10
-
11
- ### Interactions with other databases
12
-
13
- This plugin shouldn't fail with Databases other than MySQL but neither will it do anything either. There's theoretically nothing that should stop it from being *ported* to other DBs, we just don't need to.
14
-
15
- ## Installation
16
-
17
- Shove this in your Gemfile and smoke it
18
-
19
- gem "global_uid", :git => "git://github.com/zendesk/global_uid.git"
20
-
21
- ### Configuration
22
-
23
- First configure some databases in database.yml in the normal way.
24
-
25
- id_server_1:
26
- adapter: mysql
27
- host: id_server_db1.prod
28
- port: 3306
29
-
30
- id_server_2:
31
- adapter: mysql
32
- host: id_server_db2.prod
33
- port: 3306
34
-
35
- Then setup these servers, and other defaults in your environment.rb:
36
-
37
- GlobalUid.default_options = {
38
- :id_servers => [ 'id_server_1', 'id_server_2' ],
39
- :increment_by => 3
40
- }
41
-
42
- Here's a complete list of the options you can use:
43
-
44
- Name Default
45
- :disabled false
46
- Disable GlobalUid entirely
47
-
48
- :dry_run false
49
- Setting this parameter causes the REPLACE INTO statements to run, but the id picked up will not be used.
50
-
51
- :connection_timeout 3 seconds
52
- Timeout for connecting to a global UID server
53
-
54
- :query_timeout 10 seconds
55
- Timeout for retrieving a global UID from a server before we move on to the next server
56
-
57
- :connection_retry 10.minutes
58
- After failing to connect or query a UID server, how long before we retry
59
-
60
- :use_server_variables false
61
- If set, this gem will call "set @@auto_increment_offset" in order to setup the global uid servers.
62
- good for test/development, not so much for production.
63
- :notifier A proc calling ActiveRecord::Base.logger
64
- This proc is called with two parameters upon UID server failure -- an exception and a message
65
-
66
- :increment_by 5
67
- Chooses the step size for the increment. This will define the maximum number of UID servers you can have.
68
-
69
- ### Testing
70
-
71
- mysqladmin -uroot create global_uid_test
72
- mysqladmin -uroot create global_uid_test_id_server_1
73
- mysqladmin -uroot create global_uid_test_id_server_2
74
-
75
- Copy test/config/database.yml.example to test/config/database.yml and make the modifications you need to point it to 2 local MySQL databases. Then +rake test+
76
-
77
- ### Migration
78
-
79
- Migrations will now add global_uid tables for you by default. They will also change
80
- your primary keys from signature "PRIMARY KEY AUTO_INCREMENT NOT NULL" to "PRIMARY KEY NOT NULL".
81
-
82
- If you'd like to disable this behavior, you can write:
83
-
84
- class CreateFoos < ActiveRecord::Migration
85
- def self.up
86
- create_table :foos, :use_global_uid => false do |t|
87
-
88
-
89
- ## Model-level stuff
90
-
91
- If you want GlobalUIDs created, you don't have to do anything except set up the GlobalUID tables
92
- with your migration. Everything will be taken care you. It's calm, and soothing like aloe.
93
- It's the Rails way.
94
-
95
-
96
- ### Disabling global uid per table
97
-
98
- class Foo < ActiveRecord::Base
99
- disable_global_uid
100
- end
101
-
102
-
103
- ## Taking matters into your own hands:
104
-
105
-
106
- class Foo < ActiveRecord::Base
107
- disable_global_uid
108
-
109
- def before_create
110
- self.id = generate_uid()
111
- # other stuff
112
- ....
113
- end
114
-
115
- end
116
-
117
- If you're using a non standard uid table then pass that in.
118
-
119
- generate_uid(:uid_table => '<name>')
120
-
121
- ## Submitting Bug reports, patches or improvements
122
-
123
- I welcome your feedback, bug reports, patches and improvements. Please e-mail these
124
- to
125
- simon at zendesk.com
126
-
127
-
128
- with [mysqlbigint global uid] in the subject line. I'll get back to you as soon as I can.
129
-
130
- Copyright (c) 2010 Zendesk, released under the MIT license
data/Rakefile DELETED
@@ -1,151 +0,0 @@
1
- require 'rubygems'
2
- require 'rake'
3
- require 'date'
4
- require 'appraisal'
5
-
6
- #############################################################################
7
- #
8
- # Helper functions
9
- #
10
- #############################################################################
11
-
12
- def name
13
- @name ||= Dir['*.gemspec'].first.split('.').first
14
- end
15
-
16
- def version
17
- line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
18
- line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
19
- end
20
-
21
- def date
22
- Date.today.to_s
23
- end
24
-
25
- def rubyforge_project
26
- name
27
- end
28
-
29
- def gemspec_file
30
- "#{name}.gemspec"
31
- end
32
-
33
- def gem_file
34
- "#{name}-#{version}.gem"
35
- end
36
-
37
- def replace_header(head, header_name)
38
- head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
39
- end
40
-
41
- #############################################################################
42
- #
43
- # Standard tasks
44
- #
45
- #############################################################################
46
-
47
- task :default => :test
48
-
49
- require 'rake/testtask'
50
- Rake::TestTask.new(:test) do |test|
51
- test.libs << 'lib' << 'test'
52
- test.pattern = 'test/**/*_test.rb'
53
- test.verbose = true
54
- end
55
-
56
- desc "Generate RCov test coverage and open in your browser"
57
- task :coverage do
58
- require 'rcov'
59
- sh "rm -fr coverage"
60
- sh "rcov test/test_*.rb"
61
- sh "open coverage/index.html"
62
- end
63
-
64
- require 'rake/rdoctask'
65
- Rake::RDocTask.new do |rdoc|
66
- rdoc.rdoc_dir = 'rdoc'
67
- rdoc.title = "#{name} #{version}"
68
- rdoc.rdoc_files.include('README*')
69
- rdoc.rdoc_files.include('lib/**/*.rb')
70
- end
71
-
72
- desc "Open an irb session preloaded with this library"
73
- task :console do
74
- sh "irb -rubygems -r ./lib/#{name}.rb"
75
- end
76
-
77
- #############################################################################
78
- #
79
- # Custom tasks (add your own tasks here)
80
- #
81
- #############################################################################
82
-
83
-
84
-
85
- #############################################################################
86
- #
87
- # Packaging tasks
88
- #
89
- #############################################################################
90
-
91
- desc "Create tag v#{version} and build and push #{gem_file} to Rubygems"
92
- task :release => :build do
93
- unless `git branch` =~ /^\* master$/
94
- puts "You must be on the master branch to release!"
95
- exit!
96
- end
97
- sh "git commit --allow-empty -a -m 'Release #{version}'"
98
- sh "git tag v#{version}"
99
- sh "git push origin master"
100
- sh "git push origin v#{version}"
101
- sh "gem push pkg/#{name}-#{version}.gem"
102
- end
103
-
104
- desc "Build #{gem_file} into the pkg directory"
105
- task :build => :gemspec do
106
- sh "mkdir -p pkg"
107
- sh "gem build #{gemspec_file}"
108
- sh "mv #{gem_file} pkg"
109
- end
110
-
111
- desc "Generate #{gemspec_file}"
112
- task :gemspec => :validate do
113
- # read spec file and split out manifest section
114
- spec = File.read(gemspec_file)
115
- head, manifest, tail = spec.split(" # = MANIFEST =\n")
116
-
117
- # replace name version and date
118
- replace_header(head, :name)
119
- replace_header(head, :version)
120
- replace_header(head, :date)
121
- #comment this out if your rubyforge_project has a different name
122
- replace_header(head, :rubyforge_project)
123
-
124
- # determine file list from git ls-files
125
- files = `git ls-files`.
126
- split("\n").
127
- sort.
128
- reject { |file| file =~ /^\./ }.
129
- reject { |file| file =~ /^(rdoc|pkg)/ }.
130
- map { |file| " #{file}" }.
131
- join("\n")
132
-
133
- # piece file back together and write
134
- manifest = " s.files = %w[\n#{files}\n ]\n"
135
- spec = [head, manifest, tail].join(" # = MANIFEST =\n")
136
- File.open(gemspec_file, 'w') { |io| io.write(spec) }
137
- puts "Updated #{gemspec_file}"
138
- end
139
-
140
- desc "Validate #{gemspec_file}"
141
- task :validate do
142
- libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
143
- unless libfiles.empty?
144
- puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
145
- exit!
146
- end
147
- unless Dir['VERSION*'].empty?
148
- puts "A `VERSION` file at root level violates Gem best practices."
149
- exit!
150
- end
151
- end
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "http://rubygems.org"
4
-
5
- gem "ruby-debug", :platform=>"mri_18", :group=>"test"
6
- gem "debugger", :platform=>"mri_19", :require=>"ruby-debug", :group=>"test"
7
- gem "activerecord", "2.3.14"
8
-
9
- gemspec :path=>"../"
@@ -1,53 +0,0 @@
1
- PATH
2
- remote: /Users/ben/src/global_uid
3
- specs:
4
- global_uid (1.2.6)
5
- activerecord
6
- activesupport
7
-
8
- GEM
9
- remote: http://rubygems.org/
10
- specs:
11
- activerecord (2.3.14)
12
- activesupport (= 2.3.14)
13
- activesupport (2.3.14)
14
- appraisal (0.4.0)
15
- bundler
16
- rake
17
- columnize (0.3.5)
18
- debugger (1.1.1)
19
- columnize (>= 0.3.1)
20
- debugger-linecache (~> 1.1)
21
- debugger-ruby_core_source (~> 1.1)
22
- debugger-linecache (1.1.1)
23
- debugger-ruby_core_source (>= 1.1.1)
24
- debugger-ruby_core_source (1.1.1)
25
- linecache (0.46)
26
- rbx-require-relative (> 0.0.4)
27
- metaclass (0.0.1)
28
- mocha (0.10.0)
29
- metaclass (~> 0.0.1)
30
- mysql (2.8.1)
31
- rake (0.9.2.2)
32
- rbx-require-relative (0.0.5)
33
- ruby-debug (0.10.4)
34
- columnize (>= 0.1)
35
- ruby-debug-base (~> 0.10.4.0)
36
- ruby-debug-base (0.10.4)
37
- linecache (>= 0.3)
38
- shoulda (2.11.3)
39
-
40
- PLATFORMS
41
- ruby
42
-
43
- DEPENDENCIES
44
- activerecord (= 2.3.14)
45
- appraisal
46
- bundler
47
- debugger
48
- global_uid!
49
- mocha
50
- mysql (= 2.8.1)
51
- rake
52
- ruby-debug
53
- shoulda
@@ -1,65 +0,0 @@
1
- GIT
2
- remote: git://github.com/osheroff/mysql2.git
3
- revision: a1ab7bae6252746c68677ad7a0d362e385dcd446
4
- ref: a1ab7ba
5
- specs:
6
- mysql2 (0.2.18)
7
-
8
- PATH
9
- remote: /Users/ben/src/global_uid
10
- specs:
11
- global_uid (1.2.6)
12
- activerecord
13
- activesupport
14
-
15
- GEM
16
- remote: http://rubygems.org/
17
- specs:
18
- activerecord (2.3.14)
19
- activesupport (= 2.3.14)
20
- activesupport (2.3.14)
21
- appraisal (0.4.1)
22
- bundler
23
- rake
24
- columnize (0.3.6)
25
- debugger (1.1.1)
26
- columnize (>= 0.3.1)
27
- debugger-linecache (~> 1.1)
28
- debugger-ruby_core_source (~> 1.1)
29
- debugger-linecache (1.1.1)
30
- debugger-ruby_core_source (>= 1.1.1)
31
- debugger-ruby_core_source (1.1.1)
32
- linecache (0.46)
33
- rbx-require-relative (> 0.0.4)
34
- metaclass (0.0.1)
35
- mocha (0.10.5)
36
- metaclass (~> 0.0.1)
37
- mysql (2.8.1)
38
- rake (0.9.2.2)
39
- rbx-require-relative (0.0.9)
40
- ruby-debug (0.10.4)
41
- columnize (>= 0.1)
42
- ruby-debug-base (~> 0.10.4.0)
43
- ruby-debug-base (0.10.4)
44
- linecache (>= 0.3)
45
- shoulda (3.0.1)
46
- shoulda-context (~> 1.0.0)
47
- shoulda-matchers (~> 1.0.0)
48
- shoulda-context (1.0.0)
49
- shoulda-matchers (1.0.0)
50
-
51
- PLATFORMS
52
- ruby
53
-
54
- DEPENDENCIES
55
- activerecord (= 2.3.14)
56
- appraisal
57
- bundler
58
- debugger
59
- global_uid!
60
- mocha
61
- mysql (= 2.8.1)
62
- mysql2!
63
- rake
64
- ruby-debug
65
- shoulda
@@ -1,9 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "http://rubygems.org"
4
-
5
- gem "ruby-debug", :platform=>"mri_18", :group=>"test"
6
- gem "debugger", :platform=>"mri_19", :require=>"ruby-debug", :group=>"test"
7
- gem "activerecord", "3.2.2"
8
-
9
- gemspec :path=>"../"
@@ -1,66 +0,0 @@
1
- PATH
2
- remote: /Users/ben/src/global_uid
3
- specs:
4
- global_uid (1.2.6)
5
- activerecord
6
- activesupport
7
-
8
- GEM
9
- remote: http://rubygems.org/
10
- specs:
11
- activemodel (3.2.2)
12
- activesupport (= 3.2.2)
13
- builder (~> 3.0.0)
14
- activerecord (3.2.2)
15
- activemodel (= 3.2.2)
16
- activesupport (= 3.2.2)
17
- arel (~> 3.0.2)
18
- tzinfo (~> 0.3.29)
19
- activesupport (3.2.2)
20
- i18n (~> 0.6)
21
- multi_json (~> 1.0)
22
- appraisal (0.4.0)
23
- bundler
24
- rake
25
- arel (3.0.2)
26
- builder (3.0.0)
27
- columnize (0.3.5)
28
- debugger (1.1.1)
29
- columnize (>= 0.3.1)
30
- debugger-linecache (~> 1.1)
31
- debugger-ruby_core_source (~> 1.1)
32
- debugger-linecache (1.1.1)
33
- debugger-ruby_core_source (>= 1.1.1)
34
- debugger-ruby_core_source (1.1.1)
35
- i18n (0.6.0)
36
- linecache (0.46)
37
- rbx-require-relative (> 0.0.4)
38
- metaclass (0.0.1)
39
- mocha (0.10.0)
40
- metaclass (~> 0.0.1)
41
- multi_json (1.1.0)
42
- mysql (2.8.1)
43
- rake (0.9.2.2)
44
- rbx-require-relative (0.0.5)
45
- ruby-debug (0.10.4)
46
- columnize (>= 0.1)
47
- ruby-debug-base (~> 0.10.4.0)
48
- ruby-debug-base (0.10.4)
49
- linecache (>= 0.3)
50
- shoulda (2.11.3)
51
- tzinfo (0.3.32)
52
-
53
- PLATFORMS
54
- ruby
55
-
56
- DEPENDENCIES
57
- activerecord (= 3.2.2)
58
- appraisal
59
- bundler
60
- debugger
61
- global_uid!
62
- mocha
63
- mysql (= 2.8.1)
64
- rake
65
- ruby-debug
66
- shoulda
data/global_uid.gemspec DELETED
@@ -1,90 +0,0 @@
1
- ## This is the rakegem gemspec template. Make sure you read and understand
2
- ## all of the comments. Some sections require modification, and others can
3
- ## be deleted if you don't need them. Once you understand the contents of
4
- ## this file, feel free to delete any comments that begin with two hash marks.
5
- ## You can find comprehensive Gem::Specification documentation, at
6
- ## http://docs.rubygems.org/read/chapter/20
7
- Gem::Specification.new do |s|
8
- s.specification_version = 2 if s.respond_to? :specification_version=
9
- s.required_rubygems_version = Gem::Requirement.new(">= 1.3.6") if s.respond_to? :required_rubygems_version=
10
- s.rubygems_version = '1.3.6'
11
-
12
- ## Leave these as is they will be modified for you by the rake gemspec task.
13
- ## If your rubyforge_project name is different, then edit it and comment out
14
- ## the sub! line in the Rakefile
15
- s.name = 'global_uid'
16
- s.version = '1.4.0'
17
- s.date = '2013-04-01'
18
- s.rubyforge_project = 'global_uid'
19
-
20
- ## Make sure your summary is short. The description may be as long
21
- ## as you like.
22
- s.summary = "GUID"
23
- s.description = "GUIDs for sharded models"
24
-
25
- ## List the primary authors. If there are a bunch of authors, it's probably
26
- ## better to set the email to an email list or something. If you don't have
27
- ## a custom homepage, consider using your GitHub URL or the like.
28
- s.authors = ["Ben Osheroff"]
29
- s.email = 'ben@zendesk.com'
30
- s.homepage = 'http://github.com/zendesk/global_uid'
31
-
32
- ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
33
- ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
34
- s.require_paths = %w[lib]
35
-
36
- ## This sections is only necessary if you have C extensions.
37
- ## s.require_paths << 'ext'
38
- ## s.extensions = %w[ext/extconf.rb]
39
-
40
- ## If your gem includes any executables, list them here.
41
- # s.executables = ["name"]
42
-
43
- ## Specify any RDoc options here. You'll want to add your README and
44
- ## LICENSE files to the extra_rdoc_files list.
45
- s.rdoc_options = ["--charset=UTF-8"]
46
- s.extra_rdoc_files = %w[README.md]
47
-
48
- ## List your runtime dependencies here. Runtime dependencies are those
49
- ## that are needed for an end user to actually USE your code.
50
- s.add_dependency('activerecord')
51
- s.add_dependency('activesupport')
52
-
53
- ## List your development dependencies here. Development dependencies are
54
- ## those that are only needed during development
55
- s.add_development_dependency('mysql', '2.8.1')
56
- s.add_development_dependency("appraisal")
57
- s.add_development_dependency('rake')
58
- s.add_development_dependency('bundler')
59
- s.add_development_dependency('shoulda')
60
- s.add_development_dependency('mocha')
61
-
62
- ## Leave this section as-is. It will be automatically generated from the
63
- ## contents of your Git repository via the gemspec task. DO NOT REMOVE
64
- ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
65
- # = MANIFEST =
66
- s.files = %w[
67
- Appraisals
68
- Gemfile
69
- README.md
70
- Rakefile
71
- gemfiles/rails2.gemfile
72
- gemfiles/rails2.gemfile.lock
73
- gemfiles/rails2mysql2.gemfile.lock
74
- gemfiles/rails3.gemfile
75
- gemfiles/rails3.gemfile.lock
76
- global_uid.gemspec
77
- lib/global_uid.rb
78
- lib/global_uid/active_record_extension.rb
79
- lib/global_uid/base.rb
80
- lib/global_uid/migration_extension.rb
81
- test/config/database.yml.example
82
- test/global_uid_test.rb
83
- test/test_helper.rb
84
- ]
85
- # = MANIFEST =
86
-
87
- ## Test files will be grabbed from the file list. Make sure the path glob
88
- ## matches what you actually use.
89
- s.test_files = s.files.select { |path| path =~ /^test\/(test_.*|.*_test)\.rb/ }
90
- end
@@ -1,20 +0,0 @@
1
- test:
2
- adapter: mysql
3
- encoding: utf8
4
- database: global_uid_test
5
- username: root
6
- password:
7
-
8
- test_id_server_1:
9
- adapter: mysql
10
- encoding: utf8
11
- database: global_uid_test_id_server_1
12
- username: root
13
- password:
14
-
15
- test_id_server_2:
16
- adapter: mysql
17
- encoding: utf8
18
- database: global_uid_test_id_server_2
19
- username: root
20
- password:
@@ -1,475 +0,0 @@
1
- require 'test_helper'
2
-
3
- class CreateWithNoParams < ActiveRecord::Migration
4
- group :change if self.respond_to?(:group)
5
-
6
- def self.up
7
- create_table :with_global_uids do |t|
8
- t.string :description
9
- end
10
- end
11
-
12
- def self.down
13
- drop_table :with_global_uids
14
- end
15
- end
16
-
17
- class CreateWithExplicitUidTrue < ActiveRecord::Migration
18
- group :change if self.respond_to?(:group)
19
-
20
- def self.up
21
- create_table :with_global_uids, :use_global_uid => true do |t|
22
- t.string :description
23
- end
24
- end
25
-
26
- def self.down
27
- drop_table :with_global_uids, :use_global_uid => true
28
- end
29
- end
30
-
31
- class CreateWithNamedID < ActiveRecord::Migration
32
- group :change if self.respond_to?(:group)
33
-
34
- def self.up
35
- create_table :with_global_uids, :id => 'hello' do |t|
36
- t.string :description
37
- end
38
- end
39
-
40
- def self.down
41
- drop_table :with_global_uids
42
- end
43
- end
44
-
45
- class CreateWithoutGlobalUIDs < ActiveRecord::Migration
46
- group :change if self.respond_to?(:group)
47
-
48
- def self.up
49
- create_table :without_global_uids, :use_global_uid => false do |t|
50
- t.string :description
51
- end
52
- end
53
-
54
- def self.down
55
- drop_table :without_global_uids, :use_global_uid => false
56
- end
57
- end
58
-
59
- class WithGlobalUID < ActiveRecord::Base
60
- end
61
-
62
- class WithoutGlobalUID < ActiveRecord::Base
63
- end
64
-
65
- class Parent < ActiveRecord::Base
66
- def self.reset
67
- @global_uid_disabled = nil
68
- end
69
- end
70
-
71
- class ParentSubclass < Parent
72
- end
73
-
74
- class ParentSubclassSubclass < ParentSubclass
75
- end
76
-
77
- class GlobalUIDTest < ActiveSupport::TestCase
78
- ActiveRecord::Migration.verbose = false
79
-
80
- context "#global_uid_disabled" do
81
- setup do
82
- [ Parent, ParentSubclass, ParentSubclassSubclass ].each { |k| k.reset }
83
- end
84
-
85
- should "default to the parent value or false" do
86
- assert !ParentSubclass.global_uid_disabled
87
-
88
- ParentSubclass.disable_global_uid
89
- assert ParentSubclass.global_uid_disabled
90
- assert ParentSubclassSubclass.global_uid_disabled
91
-
92
- ParentSubclass.reset
93
- assert !ParentSubclass.global_uid_disabled
94
- assert ParentSubclassSubclass.global_uid_disabled
95
-
96
- ParentSubclassSubclass.reset
97
- assert !ParentSubclass.global_uid_disabled
98
- assert !ParentSubclassSubclass.global_uid_disabled
99
- end
100
- end
101
-
102
- context "migrations" do
103
- setup do
104
- restore_defaults!
105
- reset_connections!
106
- drop_old_test_tables!
107
- end
108
-
109
- context "without explicit parameters" do
110
- context "with global-uid enabled" do
111
- setup do
112
- GlobalUid::Base.global_uid_options[:disabled] = false
113
- GlobalUid::Base.global_uid_options[:storage_engine] = "InnoDB"
114
- CreateWithNoParams.up
115
- @create_table = show_create_sql(WithGlobalUID, "with_global_uids").split("\n")
116
- end
117
-
118
- should "create the global_uids table" do
119
- GlobalUid::Base.with_connections do |cx|
120
- assert cx.table_exists?('with_global_uids_ids')
121
- end
122
- end
123
-
124
- should "create global_uids tables with matching ids" do
125
- GlobalUid::Base.with_connections do |cx|
126
- foo = cx.select_all("select id from with_global_uids_ids")
127
- assert(foo.first['id'].to_i == 1)
128
- end
129
- end
130
-
131
- should "create tables with the given storage_engine" do
132
- GlobalUid::Base.with_connections do |cx|
133
- foo = cx.select_all("show create table with_global_uids_ids")
134
- assert_match /ENGINE=InnoDB/, foo.first.values.join
135
- end
136
-
137
- end
138
-
139
- should "tear off the auto_increment part of the primary key from the created table" do
140
- id_line = @create_table.grep(/\`id\` int/i).first
141
- assert_no_match /auto_increment/i, id_line
142
- end
143
-
144
- should "create a primary key on id" do
145
- assert @create_table.grep(/primary key/i).size > 0
146
- end
147
-
148
- teardown do
149
- CreateWithNoParams.down
150
- end
151
- end
152
-
153
- context "dropping a table" do
154
- should "not drop the global-uid tables" do
155
- CreateWithNoParams.up
156
- GlobalUid::Base.with_connections do |cx|
157
- assert cx.table_exists?('with_global_uids_ids')
158
- end
159
-
160
- CreateWithNoParams.down
161
- GlobalUid::Base.with_connections do |cx|
162
- assert cx.table_exists?('with_global_uids_ids')
163
- end
164
- end
165
- end
166
-
167
- context "with global-uid disabled, globally" do
168
- setup do
169
- GlobalUid::Base.global_uid_options[:disabled] = true
170
- CreateWithNoParams.up
171
- end
172
-
173
- should "not create the global_uids table" do
174
- GlobalUid::Base.with_connections do |cx|
175
- assert !cx.table_exists?('with_global_uids_ids')
176
- end
177
- end
178
-
179
- teardown do
180
- CreateWithNoParams.down
181
- GlobalUid::Base.global_uid_options[:disabled] = false
182
- end
183
- end
184
-
185
- context "with a named ID key" do
186
- setup do
187
- CreateWithNamedID.up
188
- end
189
-
190
- should "preserve the name of the ID key" do
191
- @create_table = show_create_sql(WithGlobalUID, "with_global_uids").split("\n")
192
- assert(@create_table.grep(/hello.*int/i))
193
- assert(@create_table.grep(/primary key.*hello/i))
194
- end
195
-
196
- teardown do
197
- CreateWithNamedID.down
198
- end
199
- end
200
- end
201
-
202
- context "with :use_global_uid => true" do
203
- context "dropping a table" do
204
- should "drop the global-uid tables" do
205
- CreateWithExplicitUidTrue.up
206
- GlobalUid::Base.with_connections do |cx|
207
- assert cx.table_exists?('with_global_uids_ids')
208
- end
209
-
210
- CreateWithExplicitUidTrue.down
211
- GlobalUid::Base.with_connections do |cx|
212
- assert !cx.table_exists?('with_global_uids_ids')
213
- end
214
- end
215
- end
216
- end
217
-
218
- context "with global-uid disabled in the migration" do
219
- setup do
220
- CreateWithoutGlobalUIDs.up
221
- @create_table = show_create_sql(WithoutGlobalUID, "without_global_uids").split("\n")
222
- end
223
-
224
- should "not create the global_uids table" do
225
- GlobalUid::Base.with_connections do |cx|
226
- assert !cx.table_exists?('without_global_uids_ids')
227
- end
228
- end
229
-
230
- should "create standard auto-increment tables" do
231
- id_line = @create_table.grep(/.id. int/i).first
232
- assert_match /auto_increment/i, id_line
233
- end
234
-
235
- teardown do
236
- CreateWithoutGlobalUIDs.down
237
- end
238
- end
239
- end
240
-
241
- context "With GlobalUID" do
242
- setup do
243
- reset_connections!
244
- drop_old_test_tables!
245
- restore_defaults!
246
- CreateWithNoParams.up
247
- CreateWithoutGlobalUIDs.up
248
- end
249
-
250
- context "normally" do
251
- should "get a unique id" do
252
- test_unique_ids
253
- end
254
-
255
- should "get bulk ids" do
256
- res = GlobalUid::Base.get_many_uids_for_class(WithGlobalUID, 10)
257
- assert res.size == 10
258
- res += GlobalUid::Base.get_many_uids_for_class(WithGlobalUID, 10)
259
- assert res.uniq.size == 20
260
- # starting value of 1 with a step of 5, so we should get 6,11,16...
261
- res.each_with_index do |val, i|
262
- assert_equal val, ((i + 1) * 5) + 1
263
- end
264
- end
265
- end
266
-
267
- context "reserving ids" do
268
- should "get 10 in bulk" do
269
- WithGlobalUID.with_reserved_global_uids(10) do
270
- WithGlobalUID.create!
271
- # now we should be able to run without ever touching the cx again
272
- GlobalUid::Base.get_connections.each.expects(:insert).never
273
- GlobalUid::Base.get_connections.each.expects(:select_value).never
274
- 9.times { WithGlobalUID.create! }
275
- end
276
-
277
- GlobalUid::Base.get_connections.first.expects(:insert).once.returns(50)
278
- WithGlobalUID.create!
279
- end
280
- end
281
-
282
- context "With a timing out server" do
283
- setup do
284
- reset_connections!
285
- @a_decent_cx = GlobalUid::Base.new_connection(GlobalUid::Base.global_uid_servers.first, 50, 1, 5, true)
286
- ActiveRecord::Base.stubs(:mysql_connection).raises(GlobalUid::ConnectionTimeoutException).then.returns(@a_decent_cx)
287
- @connections = GlobalUid::Base.get_connections
288
- end
289
-
290
- should "limp along with one functioning server" do
291
- assert @connections.include?(@a_decent_cx)
292
- assert_equal GlobalUid::Base.global_uid_servers.size - 1, @connections.size, "get_connections size"
293
- end
294
-
295
- should "eventually retry the connection and get it back in place" do
296
- # clear the state machine expectation
297
- ActiveRecord::Base.mysql_connection rescue nil
298
- ActiveRecord::Base.mysql_connection rescue nil
299
-
300
- awhile = Time.now + 10.hours
301
- Time.stubs(:now).returns(awhile)
302
-
303
- assert GlobalUid::Base.get_connections.size == GlobalUid::Base.global_uid_servers.size
304
-
305
- end
306
-
307
- should "get some unique ids" do
308
- test_unique_ids
309
- end
310
- end
311
-
312
- context "With a server timing out on query" do
313
- setup do
314
- reset_connections!
315
- @old_size = GlobalUid::Base.get_connections.size # prime them
316
- GlobalUid::Base.get_connections.first.stubs(:insert).raises(GlobalUid::TimeoutException)
317
- # trigger the failure -- have to do it it a bunch of times, as one call might not hit the server
318
- # Even so there's a 1/(2^32) possibility of this test failing.
319
- 32.times do WithGlobalUID.create! end
320
- end
321
-
322
- should "pull the server out of the pool" do
323
- assert GlobalUid::Base.get_connections.size == @old_size - 1
324
- end
325
-
326
- should "get ids from the remaining server" do
327
- test_unique_ids
328
- end
329
-
330
- should "eventually retry the connection" do
331
- awhile = Time.now + 10.hours
332
- Time.stubs(:now).returns(awhile)
333
-
334
- assert GlobalUid::Base.get_connections.size == GlobalUid::Base.global_uid_servers.size
335
- end
336
- end
337
-
338
- context "With both servers throwing exceptions" do
339
- setup do
340
- # would prefer to do the below, but need Mocha 0.9.10 to do so
341
- # ActiveRecord::ConnectionAdapters::MysqlAdapter.any_instance.stubs(:execute).raises(ActiveRecord::StatementInvalid)
342
- GlobalUid::Base.with_connections do |cx|
343
- cx.stubs(:insert).raises(ActiveRecord::StatementInvalid)
344
- end
345
- end
346
-
347
- should "raise a NoServersAvailableException" do
348
- assert_raises(GlobalUid::NoServersAvailableException) do
349
- WithGlobalUID.create!
350
- end
351
- end
352
-
353
- should "retry the servers immediately after failure" do
354
- assert_raises(GlobalUid::NoServersAvailableException) do
355
- WithGlobalUID.create!
356
- end
357
-
358
- assert WithGlobalUID.create!
359
- end
360
- end
361
-
362
-
363
- context "with per-process_affinity" do
364
- setup do
365
- GlobalUid::Base.global_uid_options[:per_process_affinity] = true
366
- end
367
-
368
- should "increment sequentially" do
369
- last_id = 0
370
- 10.times do
371
- this_id = WithGlobalUID.create!.id
372
- assert this_id > last_id
373
- end
374
- end
375
-
376
- teardown do
377
- GlobalUid::Base.global_uid_options[:per_process_affinity] = false
378
- end
379
- end
380
-
381
- context "with global-uid disabled" do
382
- setup do
383
- WithoutGlobalUID.disable_global_uid
384
- end
385
-
386
- should "never call various unsafe methods" do
387
- GlobalUid::Base.expects(:new_connection).never
388
- GlobalUid::Base.expects(:get_uid_for_class).never
389
- WithoutGlobalUID.expects(:generate_uid).never
390
- WithoutGlobalUID.expects(:ensure_global_uid).never
391
- GlobalUid::Base.expects(:get_uid_for_class).never
392
- end
393
-
394
- teardown do
395
- end
396
- end
397
-
398
- teardown do
399
- mocha_teardown # tear down mocha early to prevent some of this being tied to mocha expectations
400
- reset_connections!
401
- CreateWithNoParams.down
402
- CreateWithoutGlobalUIDs.down
403
- end
404
- end
405
-
406
- context "In dry-run mode" do
407
- setup do
408
- reset_connections!
409
- drop_old_test_tables!
410
- GlobalUid::Base.global_uid_options[:dry_run] = true
411
- CreateWithNoParams.up
412
- end
413
-
414
- should "create a normal looking table" do
415
-
416
- end
417
-
418
- should "increment normally1" do
419
- (1..10).each do |i|
420
- assert_equal i, WithGlobalUID.create!.id
421
- end
422
- end
423
-
424
- should "insert into the UID servers nonetheless" do
425
- GlobalUid::Base.expects(:get_uid_for_class).at_least(10)
426
- 10.times { WithGlobalUID.create! }
427
- end
428
-
429
- should "log the results" do
430
- ActiveRecord::Base.logger.expects(:info).at_least(10)
431
- 10.times { WithGlobalUID.create! }
432
- end
433
-
434
- teardown do
435
- reset_connections!
436
- CreateWithNoParams.down
437
- GlobalUid::Base.global_uid_options[:dry_run] = false
438
- end
439
- end
440
-
441
- private
442
- def test_unique_ids
443
- seen = {}
444
- (0..10).each do
445
- foo = WithGlobalUID.new
446
- foo.save
447
- assert !foo.id.nil?
448
- assert foo.description.nil?
449
- assert !seen.has_key?(foo.id)
450
- seen[foo.id] = 1
451
- end
452
- end
453
-
454
- def drop_old_test_tables!
455
- GlobalUid::Base.with_connections do |cx|
456
- cx.execute("DROP TABLE IF exists with_global_uids_ids")
457
- end
458
- end
459
-
460
- def reset_connections!
461
- GlobalUid::Base.class_eval "@@servers = nil"
462
- end
463
-
464
- def restore_defaults!
465
- GlobalUid::Base.global_uid_options[:disabled] = false
466
- GlobalUid::Base.global_uid_options[:use_server_variables] = true
467
- GlobalUid::Base.global_uid_options[:dry_run] = false
468
- end
469
-
470
- def show_create_sql(klass, table)
471
- klass.connection.select_rows("show create table #{table}")[0][1]
472
- end
473
- end
474
-
475
-
data/test/test_helper.rb DELETED
@@ -1,34 +0,0 @@
1
- require 'rubygems'
2
-
3
- require 'bundler'
4
- Bundler.setup
5
- Bundler.setup(:test)
6
-
7
- require 'ruby-debug'
8
- require "active_record"
9
- require "active_support"
10
- require "active_support/test_case"
11
- require "shoulda"
12
- require "mocha"
13
- require "global_uid"
14
-
15
- GlobalUid::Base.global_uid_options = {
16
- :use_server_variables => true,
17
- :disabled => false,
18
- :id_servers => [
19
- "test_id_server_1",
20
- "test_id_server_2"
21
- ]
22
- }
23
-
24
- yaml = YAML::load(IO.read(File.dirname(__FILE__) + "/config/database.yml"))
25
-
26
- if !Gem::Specification.find_all_by_name("mysql2").empty?
27
- yaml.each do |k, v|
28
- v['adapter'] = 'mysql2'
29
- end
30
- end
31
-
32
- ActiveRecord::Base.configurations = yaml
33
- ActiveRecord::Base.establish_connection("test")
34
- ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/test.log")