querrel 1.2.0 → 1.3.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/README.md +39 -0
- data/lib/querrel/connected_model_factory.rb +2 -0
- data/lib/querrel/map_reduce.rb +17 -7
- data/lib/querrel/querreller.rb +18 -7
- data/lib/querrel/static_pool.rb +26 -0
- data/lib/querrel/version.rb +1 -1
- data/test/non_instance_test.rb +1 -0
- data/test/static_pool_test.rb +23 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ac00fa1731878f9644eeef4cba1df54454b70d3c
|
4
|
+
data.tar.gz: 3333ac82975cc0ab9a9359ea254db41c97330ded
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa8d8b12c96c966a0b5e755749a175902f4ba5b1808f94d3cdb70179250d6f624eba73d69f754a9e0e642bc10c02960455ac1bafb25fccb69dd44e8980daaef3
|
7
|
+
data.tar.gz: a65135e0097d7ccdad1d7f276ab77adc0cc48f1787db0a413c12afa93920795558157ccda86737eb51a85e589ab86c6f2ed7910b771cb0155a89063e567f41e6
|
data/README.md
CHANGED
@@ -18,6 +18,8 @@ Or install it yourself as:
|
|
18
18
|
|
19
19
|
## Usage
|
20
20
|
|
21
|
+
### Basic
|
22
|
+
|
21
23
|
You can use with Querrel directly via it's top level namespace, or by creating an instance:
|
22
24
|
|
23
25
|
```ruby
|
@@ -28,6 +30,35 @@ all_brands = Querrel.new(['db1', 'db2', 'db3']).query(Brand.all)
|
|
28
30
|
|
29
31
|
Either of the above will give you an array of all the Brand objects from all the given databases. The records will be marked as readonly.
|
30
32
|
|
33
|
+
### Advanced
|
34
|
+
|
35
|
+
`query` will yield a block with the passed in `ActiveRecord::Relation`, this allows you to do additional operations on the results before they are merged, for example you could use pluck:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
all_brand_names = q.query(Brand.all) do |s|
|
39
|
+
s.pluck(:name)
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
There is also a `run` method which instead of running a preprescribed scope and merging, will yield the `ConnectedModelFactory` class which allows you to wrap any ActiveRecord class so that you can query it in the thread, for instance:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
require 'thread'
|
47
|
+
all_brands = Brand.all
|
48
|
+
b_s = Mutex.new
|
49
|
+
all_products = Product.all
|
50
|
+
p_s = Mutex.new
|
51
|
+
|
52
|
+
Querrel.run(on: dbs) do |q|
|
53
|
+
b_s.synchronize { all_brands += q[Brand].all.to_a }
|
54
|
+
p_s.synchronize { all_products += q[Product].all.to_a }
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
At the moment, any queries using `run` and the ConnectedModelFactory won't return objects of the class passed in, but an anonymous class instead. However, `query` can marshall the results back into the original class.
|
59
|
+
|
60
|
+
### Databases
|
61
|
+
|
31
62
|
There are three ways in which you can instruct Querrel which databases to use:
|
32
63
|
|
33
64
|
1. Pass in an array of environments, e.g. `Querrel.new([:customer1, :customer2])`
|
@@ -47,6 +78,14 @@ There are three ways in which you can instruct Querrel which databases to use:
|
|
47
78
|
})
|
48
79
|
```
|
49
80
|
|
81
|
+
### Configuration
|
82
|
+
|
83
|
+
By default Querrel will use a maximum of 20 threads, but you can adjust this using the `:threads` option:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
q = Querrel.new(dbs, threads: 50)
|
87
|
+
```
|
88
|
+
|
50
89
|
## Contributing
|
51
90
|
|
52
91
|
1. Fork it ( https://github.com/meritec/querrel/fork )
|
data/lib/querrel/map_reduce.rb
CHANGED
@@ -6,6 +6,7 @@ module Querrel
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def map(scope, options = {}, &blk)
|
9
|
+
options = @options.merge(options)
|
9
10
|
if options.key?(:on)
|
10
11
|
resolver = ConnectionResolver.new(options[:on], !!options[:db_names])
|
11
12
|
dbs = resolver.configurations.keys
|
@@ -16,29 +17,38 @@ module Querrel
|
|
16
17
|
|
17
18
|
query_model = scope.model
|
18
19
|
results = {}
|
20
|
+
results_semaphore = Mutex.new
|
19
21
|
|
20
|
-
|
22
|
+
pool = StaticPool.new(options[:threads] || 20)
|
21
23
|
dbs.each do |db|
|
22
|
-
|
24
|
+
pool.enqueue do
|
25
|
+
Thread.current[:querrel_connected_models] = []
|
23
26
|
con_spec = retrieve_connection_spec(db, resolver)
|
24
27
|
Thread.current[:querrel_con_spec] = con_spec
|
25
28
|
dynamic_class = ConnectedModelFactory[query_model, con_spec]
|
26
29
|
|
27
30
|
begin
|
28
31
|
local_scope = dynamic_class.all.merge(scope)
|
29
|
-
|
30
|
-
res = yield(local_scope)
|
32
|
+
local_results = if block_given?
|
33
|
+
res = yield(local_scope, ConnectedModelFactory)
|
31
34
|
res.to_a.each(&:readonly!) if res.is_a?(ActiveRecord::Relation)
|
32
35
|
res
|
33
36
|
else
|
34
|
-
local_scope.to_a.
|
37
|
+
local_scope.to_a.map do |r|
|
38
|
+
query_model.instantiate(r.attributes, {}).tap(&:readonly!)
|
39
|
+
end
|
35
40
|
end
|
41
|
+
|
42
|
+
results_semaphore.synchronize { results[db] = local_results }
|
36
43
|
ensure
|
37
|
-
|
44
|
+
Thread.current[:querrel_connected_models].each do |m|
|
45
|
+
m.connection_pool.release_connection
|
46
|
+
end
|
47
|
+
Thread.current[:querrel_connected_models] = nil
|
38
48
|
end
|
39
49
|
end
|
40
50
|
end
|
41
|
-
|
51
|
+
pool.do_your_thang!
|
42
52
|
|
43
53
|
results
|
44
54
|
end
|
data/lib/querrel/querreller.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'querrel/connected_model_factory'
|
2
2
|
require 'querrel/connection_resolver'
|
3
|
+
require 'querrel/static_pool'
|
3
4
|
require 'querrel/map_reduce'
|
4
5
|
|
5
6
|
module Querrel
|
@@ -8,10 +9,12 @@ module Querrel
|
|
8
9
|
attr_accessor :connection_resolver
|
9
10
|
|
10
11
|
def initialize(dbs, options = {})
|
11
|
-
@connection_resolver = ConnectionResolver.new(dbs, options
|
12
|
+
@connection_resolver = ConnectionResolver.new(dbs, options.delete(:db_names))
|
13
|
+
@options = options
|
12
14
|
end
|
13
15
|
|
14
16
|
def run(options = {}, &blk)
|
17
|
+
options = @options.merge(options)
|
15
18
|
if options.key?(:on)
|
16
19
|
resolver = ConnectionResolver.new(options[:on], !!options[:db_names])
|
17
20
|
dbs = resolver.configurations.keys
|
@@ -20,15 +23,23 @@ module Querrel
|
|
20
23
|
dbs = @connection_resolver.configurations.keys
|
21
24
|
end
|
22
25
|
|
23
|
-
|
26
|
+
pool = StaticPool.new(options[:threads] || 20)
|
24
27
|
dbs.each do |db|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
pool.enqueue do
|
29
|
+
begin
|
30
|
+
Thread.current[:querrel_connected_models] = []
|
31
|
+
con_spec = retrieve_connection_spec(db, resolver)
|
32
|
+
Thread.current[:querrel_con_spec] = con_spec
|
33
|
+
yield(ConnectedModelFactory)
|
34
|
+
ensure
|
35
|
+
Thread.current[:querrel_connected_models].each do |m|
|
36
|
+
m.connection_pool.release_connection
|
37
|
+
end
|
38
|
+
Thread.current[:querrel_connected_models] = nil
|
39
|
+
end
|
29
40
|
end
|
30
41
|
end
|
31
|
-
|
42
|
+
pool.do_your_thang!
|
32
43
|
end
|
33
44
|
|
34
45
|
def retrieve_connection_spec(db, resolver)
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Querrel
|
4
|
+
class StaticPool
|
5
|
+
def initialize(size)
|
6
|
+
@size = size
|
7
|
+
@jobs = Queue.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def enqueue(&job)
|
11
|
+
@jobs.push(job)
|
12
|
+
end
|
13
|
+
|
14
|
+
def do_your_thang!
|
15
|
+
threads = Array.new(@size) do
|
16
|
+
Thread.new do
|
17
|
+
while job = @jobs.pop(true) rescue nil
|
18
|
+
job.call
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
threads.each(&:join)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/querrel/version.rb
CHANGED
data/test/non_instance_test.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require_relative 'setup/test_helper'
|
3
|
+
|
4
|
+
class StaticPoolTest < Querrel::Test
|
5
|
+
def test_never_more_than_max_threads
|
6
|
+
max_threads = 10
|
7
|
+
p = Querrel::StaticPool.new(max_threads)
|
8
|
+
|
9
|
+
thread_counts = []
|
10
|
+
thread_semaphore = Mutex.new
|
11
|
+
|
12
|
+
50.times do
|
13
|
+
p.enqueue do
|
14
|
+
thread_semaphore.synchronize do
|
15
|
+
thread_counts << Thread.list.count{ |t| t.status == "run" }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
p.do_your_thang!
|
20
|
+
|
21
|
+
assert thread_counts.all?{ |c| c <= max_threads }
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: querrel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Campbell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- lib/querrel/connection_resolver.rb
|
98
98
|
- lib/querrel/map_reduce.rb
|
99
99
|
- lib/querrel/querreller.rb
|
100
|
+
- lib/querrel/static_pool.rb
|
100
101
|
- lib/querrel/version.rb
|
101
102
|
- querrel.gemspec
|
102
103
|
- test/instance_test.rb
|
@@ -110,6 +111,7 @@ files:
|
|
110
111
|
- test/setup/querrel_test_class.rb
|
111
112
|
- test/setup/schema.rb
|
112
113
|
- test/setup/test_helper.rb
|
114
|
+
- test/static_pool_test.rb
|
113
115
|
- test/test_test.rb
|
114
116
|
homepage: https://github.com/meritec/querrel
|
115
117
|
licenses:
|
@@ -147,4 +149,5 @@ test_files:
|
|
147
149
|
- test/setup/querrel_test_class.rb
|
148
150
|
- test/setup/schema.rb
|
149
151
|
- test/setup/test_helper.rb
|
152
|
+
- test/static_pool_test.rb
|
150
153
|
- test/test_test.rb
|