sequel-schema-sharding 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +0 -3
- data/README.md +15 -1
- data/lib/sequel/plugins/dataset_shard_id.rb +21 -0
- data/lib/sequel/schema-sharding/connection_manager.rb +2 -5
- data/lib/sequel/schema-sharding/extensions/postgres/dataset.rb +16 -0
- data/lib/sequel/schema-sharding/extensions/sequel_ext.rb +12 -8
- data/lib/sequel/schema-sharding/finder.rb +4 -3
- data/lib/sequel/schema-sharding/model.rb +10 -0
- data/lib/sequel/schema-sharding/version.rb +1 -1
- data/lib/sequel/tasks/test.rake +9 -0
- data/sequel-schema-sharding.gemspec +1 -1
- data/spec/schema-sharding/finder_spec.rb +1 -0
- data/spec/schema-sharding/model_spec.rb +21 -4
- metadata +24 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9d2a8dea7d18fc038c01e427503dc01aa6b24f0
|
4
|
+
data.tar.gz: 8033c5b54ac76371fe1f0f3074f75d10d33e14fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56f54ffdeb952181d59b683e74312c3387bc0edeb037c11b2d658d5a653b0e5eef867d44139c56c2ce6f6179d4d0275c1c70efe7abfd7696cfcbe837605547cb
|
7
|
+
data.tar.gz: 3d980233dd79fd9eac01f56550885d3a02589f1b0b95718dbad2d47aa5d5750b7225f134819a871759e3d9a3f4e4805f4e496ca82b4ee35688f63e9fc76c4ab4
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
sequel-schema-sharding
|
2
2
|
======================
|
3
3
|
|
4
|
+
[](http://badge.fury.io/rb/sequel-schema-sharding)
|
4
5
|
[](https://travis-ci.org/wanelo/sequel-schema-sharding)
|
6
|
+
[](https://codeclimate.com/github/wanelo/sequel-schema-sharding)
|
5
7
|
|
6
8
|
Horizontally shard PostgreSQL tables with the Sequel gem, where each shard
|
7
9
|
lives in its own PostgreSQL schema.
|
@@ -201,7 +203,7 @@ queries do not try to reconnect to a downed master.
|
|
201
203
|
|
202
204
|
```bash
|
203
205
|
> bundle install
|
204
|
-
> bundle exec rake sequel:db:
|
206
|
+
> bundle exec rake sequel:db:test:reset
|
205
207
|
> bundle exec rspec
|
206
208
|
```
|
207
209
|
|
@@ -325,6 +327,18 @@ mapping, but any attempt to read a record inserted via the old mapping
|
|
325
327
|
will pick the wrong shard and return an empty set. DON'T EVER DO THIS.
|
326
328
|
It's really embarrassing.
|
327
329
|
|
330
|
+
### Any problems with other services?
|
331
|
+
|
332
|
+
When integrating with NewRelic, *do not* enable the SQL query plan
|
333
|
+
instrumentation. It can grab a connection that your application is also
|
334
|
+
trying to use... libpq is thread safe, so long as two threads do not
|
335
|
+
try to manipulate the same PGonn object
|
336
|
+
(http://www.postgresql.org/docs/9.3/static/libpq-threading.html).
|
337
|
+
If you see errors such as `PG::UnableToSend: insufficient data in "T" message`
|
338
|
+
or `PG::UnableToSend: extraneous data in "T" message`, this can indicate that
|
339
|
+
multiple threads are accessing the same connection, and data (or random bytes)
|
340
|
+
may have been transposed between queries.
|
341
|
+
|
328
342
|
|
329
343
|
## Contributing
|
330
344
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Plugins
|
3
|
+
module DatasetShardId
|
4
|
+
module InstanceMethods
|
5
|
+
def shard_number
|
6
|
+
@values[:shard_number] if @values
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module DatasetMethods
|
11
|
+
def shard_number
|
12
|
+
@shard_number
|
13
|
+
end
|
14
|
+
|
15
|
+
def shard_number=(id)
|
16
|
+
@shard_number=id
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -77,16 +77,13 @@ module Sequel
|
|
77
77
|
def replica_hash_for(config)
|
78
78
|
return {} if config['replicas'].nil?
|
79
79
|
size = config['replicas'].size
|
80
|
-
i = rand(size)
|
81
80
|
{
|
82
81
|
:servers => {
|
83
82
|
:read_only => ->(db) do
|
84
|
-
choice =
|
83
|
+
choice = rand(size)
|
85
84
|
probe = Sequel::SchemaSharding::DTraceProvider.provider.replica_hash_for
|
86
85
|
probe.fire(choice, size) if probe.enabled?
|
87
|
-
sequel_connection_config_for(config['replicas'][choice])
|
88
|
-
i += 1
|
89
|
-
end
|
86
|
+
sequel_connection_config_for(config['replicas'][choice])
|
90
87
|
end
|
91
88
|
}
|
92
89
|
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Sequel
|
2
|
+
module Postgres
|
3
|
+
class Dataset
|
4
|
+
alias_method :adapter_fetch_rows, :fetch_rows
|
5
|
+
|
6
|
+
def fetch_rows(sql, &block)
|
7
|
+
adapter_fetch_rows(sql) do |r|
|
8
|
+
if self.respond_to?(:shard_number)
|
9
|
+
r[:shard_number] = self.shard_number
|
10
|
+
end
|
11
|
+
block.call r
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -1,16 +1,20 @@
|
|
1
1
|
module Sequel
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
class Database
|
3
|
+
class << self
|
4
|
+
alias_method :sequel_adapter_class, :adapter_class
|
5
|
+
|
6
|
+
def adapter_class(scheme)
|
7
|
+
klass = sequel_adapter_class(scheme)
|
8
|
+
|
9
|
+
begin
|
10
|
+
require "sequel/schema-sharding/extensions/#{scheme}/dataset"
|
11
|
+
rescue LoadError => e
|
9
12
|
end
|
13
|
+
|
14
|
+
klass
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
15
|
-
Sequel::Model.plugin Sequel::SchemaSharding::Extensions::SequelExt
|
16
20
|
Sequel::Model.plugin :validation_helpers
|
@@ -4,11 +4,12 @@ module Sequel
|
|
4
4
|
module SchemaSharding
|
5
5
|
class Finder
|
6
6
|
class Result
|
7
|
-
attr_reader :connection, :schema
|
7
|
+
attr_reader :connection, :schema, :shard_number
|
8
8
|
|
9
|
-
def initialize(connection, schema)
|
9
|
+
def initialize(connection, schema, shard_number)
|
10
10
|
@connection = connection
|
11
11
|
@schema = schema
|
12
|
+
@shard_number = shard_number
|
12
13
|
end
|
13
14
|
end
|
14
15
|
|
@@ -21,7 +22,7 @@ module Sequel
|
|
21
22
|
conn = Sequel::SchemaSharding.connection_manager[physical_shard]
|
22
23
|
schema = Sequel::SchemaSharding.connection_manager.schema_for(table_name, shard_number)
|
23
24
|
|
24
|
-
Result.new(conn, schema)
|
25
|
+
Result.new(conn, schema, shard_number)
|
25
26
|
end
|
26
27
|
|
27
28
|
private
|
@@ -28,6 +28,7 @@ module Sequel
|
|
28
28
|
|
29
29
|
def self.included(base)
|
30
30
|
base.extend(ClassMethods)
|
31
|
+
base.plugin(:dataset_shard_id)
|
31
32
|
end
|
32
33
|
|
33
34
|
module ClassMethods
|
@@ -53,6 +54,7 @@ module Sequel
|
|
53
54
|
ds = result.connection[schema_and_table(result)]
|
54
55
|
ds.row_proc = self
|
55
56
|
dataset_method_modules.each { |m| ds.instance_eval { extend(m) } }
|
57
|
+
ds.shard_number = result.shard_number
|
56
58
|
ds.model = self
|
57
59
|
ds
|
58
60
|
end
|
@@ -71,6 +73,14 @@ module Sequel
|
|
71
73
|
def schema_and_table(result)
|
72
74
|
:"#{result.schema}__#{self.implicit_table_name}"
|
73
75
|
end
|
76
|
+
|
77
|
+
def create(values = {}, &block)
|
78
|
+
sharded_column_value = values[sharded_column]
|
79
|
+
shard_number = result_for(sharded_column_value).shard_number
|
80
|
+
super.tap do |m|
|
81
|
+
m.values[:shard_number] = shard_number
|
82
|
+
end
|
83
|
+
end
|
74
84
|
end
|
75
85
|
|
76
86
|
# The database connection that has the logical shard.
|
data/lib/sequel/tasks/test.rake
CHANGED
@@ -20,5 +20,14 @@ namespace :sequel do
|
|
20
20
|
manager = Sequel::SchemaSharding::DatabaseManager.new
|
21
21
|
manager.drop_databases
|
22
22
|
end
|
23
|
+
|
24
|
+
namespace :test do
|
25
|
+
desc 'Reset test database'
|
26
|
+
task :reset do
|
27
|
+
ENV['RACK_ENV'] = 'test'
|
28
|
+
Rake::Task['sequel:db:drop'].invoke
|
29
|
+
Rake::Task['sequel:db:create'].invoke
|
30
|
+
end
|
31
|
+
end
|
23
32
|
end
|
24
33
|
end
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency 'sequel'
|
22
22
|
spec.add_dependency 'pg'
|
23
23
|
spec.add_dependency 'sequel-replica-failover'
|
24
|
-
spec.add_dependency 'ruby-usdt'
|
24
|
+
spec.add_dependency 'ruby-usdt', '>= 0.2.1'
|
25
25
|
|
26
26
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
27
27
|
spec.add_development_dependency 'rake'
|
@@ -9,6 +9,7 @@ describe Sequel::SchemaSharding::Finder do
|
|
9
9
|
result = Sequel::SchemaSharding::Finder.instance.lookup('boof', 60)
|
10
10
|
expect(result.connection).to be_a(Sequel::Postgres::Database)
|
11
11
|
expect(result.schema).to eq('sequel_logical_boof_01')
|
12
|
+
expect(result.shard_number).to eq(1)
|
12
13
|
end
|
13
14
|
|
14
15
|
xit 'is fast' do
|
@@ -25,8 +25,8 @@ describe Sequel::SchemaSharding, 'Model' do
|
|
25
25
|
klass
|
26
26
|
end
|
27
27
|
|
28
|
-
describe '
|
29
|
-
it '
|
28
|
+
describe 'reading from database' do
|
29
|
+
it 'can return a valid record' do
|
30
30
|
artist = model.create(artist_id: 14, name: 'Paul')
|
31
31
|
expect(artist.id).to_not be_nil
|
32
32
|
read_back_artist = model.by_id(14).first
|
@@ -36,15 +36,28 @@ describe Sequel::SchemaSharding, 'Model' do
|
|
36
36
|
read_back_artist = model.by_id(14).first
|
37
37
|
expect(read_back_artist).to be_nil
|
38
38
|
end
|
39
|
+
|
40
|
+
it 'includes shard number on model instances' do
|
41
|
+
shard_number = model.shard_for(456).shard_number
|
42
|
+
|
43
|
+
model.create(artist_id: 456, name: 'Randy')
|
44
|
+
record = model.by_id(456).first
|
45
|
+
expect(record.shard_number).to eq(shard_number)
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
|
-
describe '
|
42
|
-
it '
|
49
|
+
describe 'writing to database' do
|
50
|
+
it 'can create a valid record' do
|
43
51
|
artist = model.create(artist_id: 234, name: 'Paul')
|
44
52
|
expect(artist).to be_a(model)
|
45
53
|
expect(artist.name).to eql('Paul')
|
46
54
|
artist.destroy
|
47
55
|
end
|
56
|
+
|
57
|
+
it 'includes shard number on model instances' do
|
58
|
+
shard_number = model.shard_for(5432).shard_number
|
59
|
+
expect(model.create(artist_id: 5432, name: 'WOW').shard_number).to eq(shard_number)
|
60
|
+
end
|
48
61
|
end
|
49
62
|
|
50
63
|
describe '#shard_for' do
|
@@ -58,6 +71,10 @@ describe Sequel::SchemaSharding, 'Model' do
|
|
58
71
|
expect(dataset.db.opts[:database]).to eq('sequel_test_shard2')
|
59
72
|
expect(dataset.first_source).to eq(:sequel_logical_artists_17__artists)
|
60
73
|
end
|
74
|
+
|
75
|
+
it 'includes shard_number on dataset' do
|
76
|
+
expect(dataset.shard_number).to eq(17)
|
77
|
+
end
|
61
78
|
end
|
62
79
|
|
63
80
|
describe '#read_only_shard_for' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel-schema-sharding
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Henry
|
@@ -10,90 +10,90 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2014-01-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: sequel
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
|
-
- -
|
19
|
+
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
|
-
- -
|
26
|
+
- - ">="
|
27
27
|
- !ruby/object:Gem::Version
|
28
28
|
version: '0'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: pg
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
32
32
|
requirements:
|
33
|
-
- -
|
33
|
+
- - ">="
|
34
34
|
- !ruby/object:Gem::Version
|
35
35
|
version: '0'
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
|
-
- -
|
40
|
+
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
42
|
version: '0'
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: sequel-replica-failover
|
45
45
|
requirement: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
|
-
- -
|
47
|
+
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '0'
|
50
50
|
type: :runtime
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
|
-
- -
|
54
|
+
- - ">="
|
55
55
|
- !ruby/object:Gem::Version
|
56
56
|
version: '0'
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: ruby-usdt
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
|
-
- -
|
61
|
+
- - ">="
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version:
|
63
|
+
version: 0.2.1
|
64
64
|
type: :runtime
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
|
-
- -
|
68
|
+
- - ">="
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version:
|
70
|
+
version: 0.2.1
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: bundler
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
|
-
- - ~>
|
75
|
+
- - "~>"
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '1.3'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
|
-
- - ~>
|
82
|
+
- - "~>"
|
83
83
|
- !ruby/object:Gem::Version
|
84
84
|
version: '1.3'
|
85
85
|
- !ruby/object:Gem::Dependency
|
86
86
|
name: rake
|
87
87
|
requirement: !ruby/object:Gem::Requirement
|
88
88
|
requirements:
|
89
|
-
- -
|
89
|
+
- - ">="
|
90
90
|
- !ruby/object:Gem::Version
|
91
91
|
version: '0'
|
92
92
|
type: :development
|
93
93
|
prerelease: false
|
94
94
|
version_requirements: !ruby/object:Gem::Requirement
|
95
95
|
requirements:
|
96
|
-
- -
|
96
|
+
- - ">="
|
97
97
|
- !ruby/object:Gem::Version
|
98
98
|
version: '0'
|
99
99
|
description: ''
|
@@ -103,9 +103,9 @@ executables: []
|
|
103
103
|
extensions: []
|
104
104
|
extra_rdoc_files: []
|
105
105
|
files:
|
106
|
-
- .gitignore
|
107
|
-
- .rspec
|
108
|
-
- .travis.yml
|
106
|
+
- ".gitignore"
|
107
|
+
- ".rspec"
|
108
|
+
- ".travis.yml"
|
109
109
|
- CONTRIBUTORS.md
|
110
110
|
- Gemfile
|
111
111
|
- Guardfile
|
@@ -118,6 +118,7 @@ files:
|
|
118
118
|
- examples/sharding.rb
|
119
119
|
- examples/sharding.yml
|
120
120
|
- lib/sequel-schema-sharding.rb
|
121
|
+
- lib/sequel/plugins/dataset_shard_id.rb
|
121
122
|
- lib/sequel/schema-sharding.rb
|
122
123
|
- lib/sequel/schema-sharding/configuration.rb
|
123
124
|
- lib/sequel/schema-sharding/connection_manager.rb
|
@@ -125,6 +126,7 @@ files:
|
|
125
126
|
- lib/sequel/schema-sharding/database_manager/schema_iterator.rb
|
126
127
|
- lib/sequel/schema-sharding/dtrace_provider.rb
|
127
128
|
- lib/sequel/schema-sharding/extensions/migrations_ext.rb
|
129
|
+
- lib/sequel/schema-sharding/extensions/postgres/dataset.rb
|
128
130
|
- lib/sequel/schema-sharding/extensions/sequel_ext.rb
|
129
131
|
- lib/sequel/schema-sharding/finder.rb
|
130
132
|
- lib/sequel/schema-sharding/logger_proxy.rb
|
@@ -158,17 +160,17 @@ require_paths:
|
|
158
160
|
- lib
|
159
161
|
required_ruby_version: !ruby/object:Gem::Requirement
|
160
162
|
requirements:
|
161
|
-
- -
|
163
|
+
- - ">="
|
162
164
|
- !ruby/object:Gem::Version
|
163
165
|
version: '0'
|
164
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
167
|
requirements:
|
166
|
-
- -
|
168
|
+
- - ">="
|
167
169
|
- !ruby/object:Gem::Version
|
168
170
|
version: '0'
|
169
171
|
requirements: []
|
170
172
|
rubyforge_project:
|
171
|
-
rubygems_version: 2.0
|
173
|
+
rubygems_version: 2.2.0
|
172
174
|
signing_key:
|
173
175
|
specification_version: 4
|
174
176
|
summary: Create horizontally sharded Sequel models with Postgres
|