em-pg-client-12 0.3.4

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 93743ff68b0f04bdcff75b78165fbcbeafc20b96
4
+ data.tar.gz: a05e6cb106bcc02666bc57b9ee98c301d70839c0
5
+ SHA512:
6
+ metadata.gz: 73384a9e88c54ffbc721b00aadded48d82697c128d23bb24679b5196da71a4b29e6432ab19242706dc0ab42d5cc53147ffaf08fe58189181e0d31e3a0166b636
7
+ data.tar.gz: 47a95833438b11d1e142956125b5bed1c22446f7ecb307d9d82ad8231466c96bb30f06326b227ac2a2484cfbc04faaeb627cd6773dd9b92a2641febdb1b558e6
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -0,0 +1,32 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+ env:
8
+ - PGVERSION=9.3 PGBUILD=9.3.4-1-linux-x64
9
+ - PGVERSION=9.0 PGBUILD=9.0.17-1-linux-x64
10
+ - PGVERSION=8.4 PGBUILD=8.4.21-1-linux-x64
11
+ before_install:
12
+ - sudo /etc/init.d/postgresql stop
13
+ - export PGPREFIX=/opt/PostgreSQL/$PGVERSION
14
+ - export PGDATA=$PGPREFIX/data
15
+ - export PATH="$PGPREFIX/bin:$PATH"
16
+ - wget http://get.enterprisedb.com/postgresql/postgresql-$PGBUILD.run
17
+ - chmod +x postgresql-$PGBUILD.run
18
+ - sudo ./postgresql-$PGBUILD.run --mode unattended --unattendedmodeui minimal --prefix
19
+ $PGPREFIX --datadir $PGDATA;
20
+ - sudo sed s/md5\$/trust/g $PGDATA/pg_hba.conf >/tmp/pg_hba.conf.$$
21
+ - sudo mv /tmp/pg_hba.conf.$$ $PGDATA/pg_hba.conf
22
+ - sudo -i -u postgres $PGPREFIX/bin/pg_ctl -D $PGDATA reload
23
+ - PGHOST_UNIX=`netstat -l --protocol=unix|grep PGSQL|awk '{print $NF}'`
24
+ - export PGHOST_UNIX="`dirname $PGHOST_UNIX`"
25
+ - test -n "$PGHOST_UNIX"
26
+ - export PG_CTL_STOP_CMD="sudo -i -u postgres $PGPREFIX/bin/pg_ctl -D $PGDATA stop
27
+ -s -m fast"
28
+ - export PG_CTL_START_CMD="sudo -i -u postgres $PGPREFIX/bin/pg_ctl -D $PGDATA start
29
+ -l $PGDATA/postgresql.log -s -w"
30
+ - export PGUSER=postgres
31
+ - psql -c 'create database test;' -h "$PGHOST_UNIX"
32
+ script: COVERAGE=1 bundle exec rake test_with_coveralls
@@ -0,0 +1 @@
1
+ lib/pg/em/client/*.rb lib/pg/em/*.rb lib/pg/*.rb - benchmarks/*.rb BENCHMARKS.md LICENSE HISTORY.md
@@ -0,0 +1,91 @@
1
+ Benchmarking
2
+ ============
3
+
4
+ Environment
5
+ -----------
6
+
7
+ The machine running tests is Linux CentOS 2.6.18-194.32.1.el5xen #1 SMP with
8
+ Quad Core Xeon X3360 @ 2.83GHz, 4GB RAM.
9
+
10
+ Postgres server version: 9.0.3
11
+ Postgres pqlib version: 9.3
12
+
13
+ Fully Asynchronous vs. poor man's async
14
+ ---------------------------------------
15
+
16
+ The following {file:benchmarks/em_pg.rb benchmark} compares fully
17
+ asynchronous implementation (`em-pg-client`) versus blocking em-pg drivers.
18
+
19
+ The goal of the test is to retrieve (~80000) rows from the same table with
20
+ a lot of text data, in chunks, using parallel connections.
21
+
22
+ The parallel method uses synchrony for simplicity.
23
+
24
+ * `single` is (eventmachine-less) job for retrieving a whole data table in
25
+ one simple query "select * from resources"
26
+ * `parallel` chunk_row_count / concurrency] uses em-pg-client for retrieving
27
+ result in chunks by `chunk_row_count` rows and using `concurrency` parallel
28
+ connections
29
+ * `blocking` chunk_row_count / concurrency is similiar to `parallel` except
30
+ that it uses special patched version of library that uses blocking
31
+ PGConnection methods
32
+
33
+
34
+ ```
35
+ >> benchmark 1000
36
+ user system total real
37
+ single: 80.970000 0.350000 81.320000 (205.592592)
38
+
39
+ parallel 90000/1: 87.380000 0.710000 88.090000 (208.171564)
40
+ parallel 5000/5: 84.250000 3.760000 88.010000 (141.031289)
41
+ parallel 2000/10: 90.190000 4.970000 95.160000 (152.844950)
42
+ parallel 1000/20: 97.070000 5.390000 102.460000 (212.358631)
43
+
44
+ blocking 90000/1: 93.590000 0.610000 94.200000 (230.190776)
45
+ blocking 5000/5: 79.930000 1.810000 81.740000 (223.342432)
46
+ blocking 2000/10: 76.990000 2.820000 79.810000 (225.347169)
47
+ blocking 1000/20: 78.790000 3.230000 82.020000 (225.949107)
48
+ ```
49
+
50
+ As we can see the gain from using asynchronous em-pg-client while
51
+ using `parallel` queries is noticeable (up to ~30%).
52
+
53
+ The `blocking` client however doesn't gain much from parallel execution.
54
+ This was expected because it freezes eventmachine until the whole
55
+ dataset is consumed by the client.
56
+
57
+
58
+ Threads vs. Fibers Streaming Benchmark
59
+ --------------------------------------
60
+
61
+ The following {file:benchmarks/single_row_mode.rb benchmark} compares
62
+ performance of parallel running threads using vanilla PG::Connection driver
63
+ versus EventMachine driven parallel Fibers using PG::EM::Client v0.3.2.
64
+
65
+ Each thread/fiber retrieves first 5000 rows from the same table with
66
+ a lot of text data in a `single_row_mode`. After 5000 rows is retrieved
67
+ the connection is being reset. The process is repeated after all parallel
68
+ running threads/fibers finish their task.
69
+
70
+ Both Thread and Fiber versions use the same chunk of code to retrieve rows.
71
+
72
+ ```
73
+ >> benchmark 400
74
+ user system total real
75
+ threads 400x1: 24.970000 1.090000 26.060000 ( 30.683818)
76
+ threads 80x5: 24.730000 7.020000 31.750000 ( 51.402710)
77
+ threads 40x10: 22.880000 7.460000 30.340000 ( 52.548910)
78
+ threads 20x20: 22.220000 7.130000 29.350000 ( 53.911111)
79
+ threads 10x40: 22.570000 7.620000 30.190000 ( 54.111841)
80
+
81
+ fibers 400x1: 26.040000 1.060000 27.100000 ( 31.619598)
82
+ fibers 80x5: 28.690000 1.140000 29.830000 ( 33.025573)
83
+ fibers 40x10: 28.790000 1.280000 30.070000 ( 33.498418)
84
+ fibers 20x20: 29.100000 1.210000 30.310000 ( 33.289344)
85
+ fibers 10x40: 29.220000 1.340000 30.560000 ( 33.691188)
86
+ ```
87
+
88
+ ```
89
+ AxB - repeat A times running B parallel threads/fibers.
90
+ ```
91
+
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org/"
2
+
3
+ gem 'rake' # Travis-CI complains about it not being here
4
+
5
+ gemspec
@@ -0,0 +1,107 @@
1
+ 0.3.4
2
+
3
+ - spec: fix em_client_on_connect and em_connection_pool tests
4
+ - asynchronous wait_for_notify and wait_for_notify_defer with specs
5
+
6
+ 0.3.3
7
+
8
+ - rake: console for debugging
9
+ - added on_connect callback
10
+ - given block to ConnectionPool.new set as on_connect option fallback
11
+ - spec: connection pool database tests
12
+ - spec: on_connect tests
13
+ - spec: on_connect + on_autoreconnect auto re-connect tests
14
+ - spec: added travis rvm 2.1.0 and updated postgres server versions
15
+ - sugar: on_connect and on_autoreconnect block setters
16
+
17
+ 0.3.2
18
+
19
+ - fix: asynchronous get_result performance
20
+ - fix+specs: query_timeout timer is canceled on connection breakdown
21
+ - comply with pg+specs: asynchronous get_result and get_last_result return nil
22
+ when connection status is not ok
23
+
24
+ 0.3.1
25
+
26
+ - support for asynchronous data streaming in single row mode -
27
+ asynchronous versions of get_result, get_last_result and
28
+ their deferrable variants
29
+ - watcher improvements allowing to reset pending commands
30
+ - minor DRY improvements in code and specs
31
+ - single_row_mode? helper
32
+ - spec: Travis CI and Coverage
33
+
34
+ 0.3.0
35
+
36
+ - dedicated asynchronous connection pool
37
+ - works on windows (with ruby 2.0+): uses PGConn#socket_io object instead of
38
+ #socket file descriptor
39
+ - socket watch handler is not being detached between command calls
40
+ - no more separate em and em-synchrony client
41
+ - api changes: async_exec and async_query command are now fiber-synchronized
42
+ - api changes: other async_* methods are removed or deprecated
43
+ - api changes: asynchronous methods renamed to *_defer
44
+ - transaction() helper method that can be called recursively
45
+ - requirements updated: eventmachine >~ 1.0.0, pg >= 0.17.0, ruby >= 1.9.2
46
+ - spec: more auto re-connect test cases
47
+ - spec: more tests for connection establishing
48
+ - comply with pg: do not close the client on connection failure
49
+ - comply with pg: asynchronous connect_timeout fallbacks to environment variable
50
+ - fix: auto re-connect raises an error if the failed connection had unfinished
51
+ transaction state
52
+ - yardoc docs
53
+
54
+ 0.2.1
55
+
56
+ - support for pg >= 0.14 native PG::Result#check
57
+ - support for pg >= 0.14 native PG::Connection#set_default_encoding
58
+ - fix: connection option Hash argument was modified by Client.new and Client.async_connect
59
+
60
+ 0.2.0
61
+
62
+ - disabled async_autoreconnect by default unless on_autoreconnect is set
63
+ - async_connect sets #internal_encoding to Encoding.default_internal
64
+ - fix: finish connection on async connect_timeout
65
+ - nice errors generated on missing dependencies
66
+ - blocking #reset() should clear async_command_aborted flag
67
+ - less calls to #is_busy in Watcher#notify_readable
68
+ - async_describe_portal() + specs
69
+ - async_describe_prepared() + specs
70
+
71
+ 0.2.0.pre.3
72
+
73
+ - status() returns CONNECTION_BAD for connections with expired query
74
+ - spec: query timeout expiration
75
+ - non-blocking result processing for multiple data query statements sent at once
76
+ - refine code in em-synchrony/pg
77
+ - spec: more detailed tests
78
+ - spec: async_connect
79
+ - spec: autoreconnect
80
+
81
+ 0.2.0.pre.2
82
+
83
+ - errors from consume_input fails deferrable
84
+ - query_timeout now measures only network response timeout,
85
+ so it's not fired for large datasets
86
+
87
+ 0.2.0.pre.1
88
+
89
+ - added query_timeout feature for async query commands
90
+ - added connect_timeout property for async connect/reset
91
+ - fix: async_autoreconnect for tcp/ip connections
92
+ - fix: async_* does not raise errors; errors handled by deferrable
93
+ - rework async_autoreconnect in fully async manner
94
+ - added async_connect() and async_reset()
95
+ - API change: on_reconnect -> on_autoreconnect
96
+
97
+ 0.1.1
98
+
99
+ - added on_reconnect callback
100
+ - docs updated
101
+ - added development dependency for eventmachine >= 1.0.0.beta.1
102
+ - added separate client specs for eventmachine = 0.12.10
103
+ - added error checking to eventmachine specs
104
+
105
+ 0.1.0
106
+
107
+ - first release
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2013 Rafal Michalski (rafal at yeondir dot com)
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,456 @@
1
+ em-pg-client
2
+ ============
3
+
4
+ The Ruby EventMachine driver interface to the PostgreSQL RDBMS. It is based on
5
+ [ruby-pg](https://bitbucket.org/ged/ruby-pg).
6
+
7
+ [![Gem Version][GV img]][Gem Version]
8
+ [![Dependency Status][DS img]][Dependency Status]
9
+ [![Coverage Status][CS img]][Coverage Status]
10
+ [![Build Status][BS img]][Build Status]
11
+
12
+ Author: Rafał Michalski (rafal at yeondir dot com)
13
+
14
+ * http://github.com/royaltm/ruby-em-pg-client
15
+
16
+ Description
17
+ -----------
18
+
19
+ __em-pg-client__ provides {PG::EM::Client} class which inherits
20
+ [PG::Connection](http://deveiate.org/code/pg/PG/Connection.html).
21
+ You can work with {PG::EM::Client} almost the same way you would work
22
+ with PG::Connection.
23
+
24
+ The real difference begins when you turn the EventMachine reactor on.
25
+
26
+ ```ruby
27
+ require 'pg/em'
28
+
29
+ pg = PG::EM::Client.new dbname: 'test'
30
+
31
+ # no async
32
+ pg.query('select * from foo') do |result|
33
+ puts Array(result).inspect
34
+ end
35
+
36
+ # asynchronous
37
+ EM.run do
38
+ Fiber.new do
39
+ pg.query('select * from foo') do |result|
40
+ puts Array(result).inspect
41
+ end
42
+ EM.stop
43
+ end.resume
44
+ end
45
+
46
+ # asynchronous + deferrable
47
+ EM.run do
48
+ df = pg.query_defer('select * from foo')
49
+ df.callback { |result|
50
+ puts Array(result).inspect
51
+ EM.stop
52
+ }
53
+ df.errback {|ex|
54
+ raise ex
55
+ }
56
+ puts "sent"
57
+ end
58
+ ```
59
+
60
+ Features
61
+ --------
62
+
63
+ * Non-blocking / fully asynchronous processing with EventMachine.
64
+ * Event reactor auto-detecting, asynchronous fiber-synchronized command methods
65
+ (the same code can be used regardless of the EventMachine reactor state)
66
+ * Asynchronous EM-style (Deferrable returning) command methods.
67
+ * Fully asynchronous automatic re-connects on connection failures
68
+ (e.g.: RDBMS restarts, network failures).
69
+ * Minimal changes to [PG::Connection](http://deveiate.org/code/pg/PG/Connection.html) API.
70
+ * Configurable timeouts (connect or execute) of asynchronous processing.
71
+ * Dedicated connection pool with dynamic size, supporting asynchronous
72
+ processing and transactions.
73
+ * [Sequel Adapter](https://github.com/fl00r/em-pg-sequel) by Peter Yanovich.
74
+ * Works on windows (requires ruby 2.0) ([issue #7][Issue 7]).
75
+ * Supports asynchronous query data processing in single row mode
76
+ ([issue #12][Issue 12]). See {file:BENCHMARKS.md BENCHMARKING}.
77
+ * __New__ - asynchronous implementation of wait_for_notify
78
+
79
+ Requirements
80
+ ------------
81
+
82
+ * ruby >= 1.9.2 (tested: 2.1.0, 2.0.0-p353, 1.9.3-p374, 1.9.2-p320)
83
+ * https://bitbucket.org/ged/ruby-pg >= 0.17.0
84
+ * [PostgreSQL](http://www.postgresql.org/ftp/source/) RDBMS >= 8.4
85
+ * http://rubyeventmachine.com >= 1.0.0
86
+ * [EM-Synchrony](https://github.com/igrigorik/em-synchrony)
87
+ (optional - not needed for any of the client functionality,
88
+ just wrap your code in a fiber)
89
+
90
+ Install
91
+ -------
92
+
93
+ ```sh
94
+ $ [sudo] gem install em-pg-client
95
+ ```
96
+
97
+ #### Gemfile
98
+
99
+ ```ruby
100
+ gem "em-pg-client", "~> 0.3.4"
101
+ ```
102
+
103
+ #### Github
104
+
105
+ ```
106
+ git clone git://github.com/royaltm/ruby-em-pg-client.git
107
+ ```
108
+
109
+ Usage
110
+ -----
111
+
112
+ ### PG::Connection commands adapted to the EventMachine
113
+
114
+ #### Asynchronous, the EventMachine style:
115
+
116
+ * `Client.connect_defer` (singleton method)
117
+ * `reset_defer`
118
+ * `exec_defer` (alias: `query_defer`)
119
+ * `prepare_defer`
120
+ * `exec_prepared_defer`
121
+ * `describe_prepared_defer`
122
+ * `describe_portal_defer`
123
+
124
+ For arguments of these methods consult their original (without the `_defer`
125
+ suffix) counterparts in the
126
+ [PG::Connection](http://deveiate.org/code/pg/PG/Connection.html) manual.
127
+
128
+ Use `callback` with a block on the returned deferrable object to receive the
129
+ result. In case of `connect_defer` and `reset_defer` the result is an instance
130
+ of the {PG::EM::Client}. The received client is in connected state and ready
131
+ for the queries. Otherwise an instance of the
132
+ [PG::Result](http://deveiate.org/code/pg/PG/Result.html) is received. You may
133
+ `clear` the obtained result object or leave it to `gc`.
134
+
135
+ To detect an error in the executed command call `errback` on the deferrable
136
+ with a block. You should expect an instance of the raised `Exception`
137
+ (usually PG::Error) as the block argument.
138
+
139
+ #### Reactor sensing methods, EM-Synchrony style:
140
+
141
+ * `Client.new` (singleton, alias: `connect`, `open`, `setdb`, `setdblogin`)
142
+ * `reset`
143
+ * `exec` (alias: `query`, `async_exec`, `async_query`)
144
+ * `prepare`
145
+ * `exec_prepared`
146
+ * `describe_prepared`
147
+ * `describe_portal`
148
+
149
+ The above methods call `*_defer` counterparts of themselves and `yield`
150
+ from the current fiber awaiting for the result. The PG::Result instance
151
+ (or PG::EM::Client for `new`) is then returned to the caller.
152
+ If a code block is given, it will be passed the result as an argument.
153
+ In that case the value of the block is returned instead and the result is
154
+ being cleared (or in case of `new` - client is being closed) after block
155
+ terminates.
156
+
157
+ These methods check if EventMachine's reactor is running and the current fiber
158
+ is not a root fiber. Otherwise the parent (thread-blocking) PG::Connection
159
+ methods are being called.
160
+
161
+ You can call asynchronous, fiber aware and blocking methods without finishing
162
+ the connection. You only need to start/stop EventMachine in between the
163
+ asynchronous calls.
164
+
165
+ Although the [em-synchrony](https://github.com/igrigorik/em-synchrony/)
166
+ provides very nice set of tools for the untangled EventMachine, you don't
167
+ really require it to fully benefit from the PG::EM::Client. Just wrap your
168
+ asynchronous code in a fiber:
169
+
170
+ Fiber.new { ... }.resume
171
+
172
+ #### Special options
173
+
174
+ There are four special connection options and one of them is a standard `pg`
175
+ option used by the async methods. You may pass them as one of the __hash__
176
+ options to {PG::EM::Client.new} or {PG::EM::Client.connect_defer} or simply
177
+ use the accessor methods to change them on the fly.
178
+
179
+ The options are:
180
+
181
+ * `connect_timeout`
182
+ * `query_timeout`
183
+ * `async_autoreconnect`
184
+ * `on_autoreconnect`
185
+ * `on_connect`
186
+
187
+ Only `connect_timeout` is a standard `libpq` option, although changing it with
188
+ the accessor method affects asynchronous functions only.
189
+ See {PG::EM::Client} for more details.
190
+
191
+ #### Handling errors
192
+
193
+ Exactly like in `pg`:
194
+
195
+ ```ruby
196
+ EM.synchrony do
197
+ begin
198
+ pg.query('smellect 1')
199
+ rescue => e
200
+ puts "error: #{e.inspect}"
201
+ end
202
+ EM.stop
203
+ end
204
+ ```
205
+
206
+ with *_defer methods:
207
+
208
+ ```ruby
209
+ EM.run do
210
+ pg.query_defer('smellect 1') do |ret|
211
+ if ret.is_a?(Exception)
212
+ puts "PSQL error: #{ret.inspect}"
213
+ end
214
+ end
215
+ end
216
+ ```
217
+
218
+ or
219
+
220
+ ```ruby
221
+ EM.run do
222
+ pg.query_defer('smellect 1').callback do |ret|
223
+ puts "do something with #{ret}"
224
+ end.errback do |err|
225
+ puts "PSQL error: #{err.inspect}"
226
+ end
227
+ end
228
+ ```
229
+
230
+ ### Auto re-connecting in asynchronous mode
231
+
232
+ Connection reset is done in a non-blocking manner using `reset_defer` internally.
233
+
234
+ ```ruby
235
+ EM.run do
236
+ Fiber.new do
237
+ pg = PG::EM::Client.new async_autoreconnect: true
238
+
239
+ try_query = lambda do
240
+ pg.query('select * from foo') do |result|
241
+ puts Array(result).inspect
242
+ end
243
+ end
244
+
245
+ try_query.call
246
+ system 'pg_ctl stop -m fast'
247
+ system 'pg_ctl start -w'
248
+ try_query.call
249
+
250
+ EM.stop
251
+ end.resume
252
+ end
253
+ ```
254
+
255
+ to enable this feature call:
256
+
257
+ ```ruby
258
+ pg.async_autoreconnect = true
259
+ ```
260
+
261
+ Additionally the `on_autoreconnect` callback may be set on the connection.
262
+ It's being invoked after successfull connection restart, just before the
263
+ pending command is sent again to the server.
264
+
265
+ ### Server-sent notifications - async style
266
+
267
+ Not surprisingly, there are two possible ways to wait for notifications,
268
+ one with a deferrable:
269
+
270
+ ```ruby
271
+ pg = PG::EM::Client.new
272
+ EM.run do
273
+ pg.wait_for_notify_defer(7).callback do |notify|
274
+ if notify
275
+ puts "Someone spoke to us on channel: #{notify[:relname]} from #{notify[:be_pid]}"
276
+ else
277
+ puts "Too late, 7 seconds passed"
278
+ end
279
+ end.errback do |ex|
280
+ puts "Connection to deep space lost..."
281
+ end
282
+ pg.query_defer("LISTEN deep_space") do
283
+ pg.query_defer("NOTIFY deep_space") do
284
+ puts "Reaching out... to the other worlds"
285
+ end
286
+ end
287
+ end
288
+ ```
289
+
290
+ and the other, using fibers:
291
+
292
+ ```ruby
293
+ EM.synchrony do
294
+ pg = PG::EM::Client.new
295
+ EM::Synchrony.next_tick do
296
+ pg.query('LISTEN "some channel"')
297
+ pg.query('SELECT pg_notify($1::text,$2::text)', ['some channel', 'with some message'])
298
+ end
299
+ pg.wait_for_notify(10) do |channel, pid, payload|
300
+ puts "I've got notification on #{channel} #{payload}."
301
+ end.tap do |name|
302
+ puts "Whatever, I've been waiting too long already" if name.nil?
303
+ end
304
+ end
305
+ ```
306
+
307
+ As you might have noticed, one does not simply wait for notifications,
308
+ but one can also run some queries on the same connection at the same time,
309
+ if one wishes so.
310
+
311
+ ### Connection Pool
312
+
313
+ Forever alone? Not anymore! There is a dedicated {PG::EM::ConnectionPool}
314
+ class with dynamic pool for both types of asynchronous commands (deferral
315
+ and fiber-synchronized).
316
+
317
+ It also provides a #transaction method which locks the in-transaction
318
+ connection to the calling fiber and allows to execute commands
319
+ on the same connection within a transaction block. The transactions may
320
+ be nested. See also docs for the {PG::EM::Client#transaction} method.
321
+
322
+ #### Parallel async queries
323
+
324
+ ```ruby
325
+ require 'pg/em/connection_pool'
326
+ require 'em-synchrony'
327
+
328
+ EM.synchrony do
329
+ pg = PG::EM::ConnectionPool.new(size: 2, dbname: 'test')
330
+
331
+ multi = EM::Synchrony::Multi.new
332
+ multi.add :foo, pg.query_defer('select pg_sleep(1)')
333
+ multi.add :bar, pg.query_defer('select pg_sleep(1)')
334
+
335
+ start = Time.now
336
+ res = multi.perform
337
+ # around 1 sec.
338
+ puts Time.now - start
339
+
340
+ EM.stop
341
+ end
342
+ ```
343
+
344
+ #### Fiber Concurrency
345
+
346
+ ```ruby
347
+ require 'pg/em/connection_pool'
348
+ require 'em-synchrony'
349
+ require "em-synchrony/fiber_iterator"
350
+
351
+ EM.synchrony do
352
+ concurrency = 5
353
+ queries = (1..10).map {|i| "select pg_sleep(1); select #{i}" }
354
+
355
+ pg = PG::EM::ConnectionPool.new(size: concurrency, dbname: 'test')
356
+
357
+ start = Time.now
358
+ EM::Synchrony::FiberIterator.new(queries, concurrency).each do |query|
359
+ pg.query(query) do |result|
360
+ puts "recv: #{result.getvalue(0,0)}"
361
+ end
362
+ end
363
+ # around 2 secs.
364
+ puts Time.now - start
365
+
366
+ EM.stop
367
+ end
368
+ ```
369
+
370
+ API Changes
371
+ -----------
372
+
373
+ ### 0.2.x -> 0.3.x
374
+
375
+ There is a substantial difference in the API between this and the previous
376
+ releases. The idea behind it was to make this implementation as much
377
+ compatible as possible with the threaded `pg` interface.
378
+ E.g. the `#async_exec` is now an alias to `#exec`.
379
+
380
+ The other reason was to get rid of the ugly em / em-synchrony duality.
381
+
382
+ * There is no separate em-synchrony client version anymore.
383
+ * The methods returning Deferrable have now the `*_defer` suffix.
384
+ * The `#async_exec` and `#async_query` (in <= 0.2 they were deferrable methods)
385
+ are now aliases to `#exec`.
386
+ * The command methods `#exec`, `#query`, `#exec_*`, `#describe_*` are now
387
+ em-synchrony style methods (fiber-synchronized).
388
+ * The following methods were removed:
389
+
390
+ - `#async_prepare`,
391
+ - `#async_exec_prepared`,
392
+ - `#async_describe_prepared`,
393
+ - `#async_describe_portal`
394
+
395
+ as their names were confusing due to the unfortunate `#async_exec`.
396
+
397
+ * The `async_connect` and `#async_reset` are renamed to `connect_defer` and `#reset_defer`
398
+ respectively.
399
+
400
+ ### 0.1.x -> 0.2.x
401
+
402
+ * `on_reconnect` renamed to more accurate `on_autoreconnect`
403
+ (well, it's not used by PG::EM::Client#reset call).
404
+ * `async_autoreconnect` is `false` by default if `on_autoreconnect`
405
+ is __not__ specified as initialization option.
406
+
407
+ Bugs/Limitations
408
+ ----------------
409
+
410
+ * no async support for COPY commands (`get_copy_data`, `put_copy_data`)
411
+ * actually no ActiveRecord support (you are welcome to contribute).
412
+
413
+ TODO:
414
+ -----
415
+
416
+ * more convenient streaming API
417
+ * implement EM adapted version of `get_copy_data`, `put_copy_data`
418
+ * ORM (ActiveRecord and maybe Datamapper) support as separate projects
419
+
420
+ More Info
421
+ ---------
422
+
423
+ This implementation makes use of non-blocking:
424
+ [PGConn#is_busy](http://deveiate.org/code/pg/PG/Connection.html#method-i-is_busy) and
425
+ [PGConn#consume_input](http://deveiate.org/code/pg/PG/Connection.html#method-i-consume_input) methods.
426
+ Depending on the size of queried results and the concurrency level, the gain
427
+ in overall speed and responsiveness of your application might be actually quite huge.
428
+ See {file:BENCHMARKS.md BENCHMARKING}.
429
+
430
+ Thanks
431
+ ------
432
+
433
+ The greetz go to:
434
+
435
+ * [Authors](https://bitbucket.org/ged/ruby-pg/wiki/Home#!copying) of __pg__
436
+ driver (especially for its async-api)
437
+ * Francis Cianfrocca for great reactor framework
438
+ [EventMachine](https://github.com/eventmachine/eventmachine)
439
+ * Ilya Grigorik [igrigorik](https://github.com/igrigorik) for
440
+ [untangling EM with Fibers](http://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers/)
441
+ * Peter Yanovich [fl00r](https://github.com/fl00r) for the
442
+ [em-pg-sequel](https://github.com/fl00r/em-pg-sequel)
443
+ * Andrew Rudenko [prepor](https://github.com/prepor) for the implicit idea
444
+ of the re-usable watcher from his [em-pg](https://github.com/prepor/em-pg).
445
+
446
+ [Gem Version]: https://rubygems.org/gems/em-pg-client
447
+ [Dependency Status]: https://gemnasium.com/royaltm/ruby-em-pg-client
448
+ [Coverage Status]: https://coveralls.io/r/royaltm/ruby-em-pg-client
449
+ [Build Status]: https://travis-ci.org/royaltm/ruby-em-pg-client
450
+ [Issue 7]: https://github.com/royaltm/ruby-em-pg-client/issues/7
451
+ [Issue 12]: https://github.com/royaltm/ruby-em-pg-client/issues/12
452
+ [GV img]: https://badge.fury.io/rb/em-pg-client.png
453
+ [DS img]: https://gemnasium.com/royaltm/ruby-em-pg-client.png
454
+ [CS img]: https://coveralls.io/repos/royaltm/ruby-em-pg-client/badge.png
455
+ [BS img]: https://travis-ci.org/royaltm/ruby-em-pg-client.png
456
+ [BB img]: https://d2weczhvl823v0.cloudfront.net/royaltm/ruby-em-pg-client/trend.png