couchbase 1.3.3 → 1.3.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
- ---
2
- SHA512:
3
- metadata.gz: 6e17257cd0c7c6e0d867ac56962ad7561b8a658bc3bb06b07d82a1c2e6047b0b032b4c1fc6b1e19d4c75762b37be3fca941f5691f74ada008feba7dffaa57ed8
4
- data.tar.gz: c3283d9b48c266c38f53045841e6b191573f570fa05b6cb9fa13ac9046e24eaab599f38b7f5444bb2555f35a113b763e6813078d860201b90b32a93c9b49513f
5
- SHA1:
6
- metadata.gz: 3f5b7a5d5b5960a30be144f90b68a6a697cfd601
7
- data.tar.gz: 58c37ac51144332757baecff17a3b1677d9ee6c8
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MzUyYTFlYjFlYTg1MWQ3Y2E2YWViNmRjZTc3MTZmNzZjMDBkZThiZg==
5
+ data.tar.gz: !binary |-
6
+ ZGM2ZDgwNGI5NTE0YWZkODJkZTlmOWFlMWU3NWIzMzY4MTExNmE1YQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ YzFjNmM4ZDFkMGIyZDk0YzQ0ZGIzZDY0OGVlNGZhNjEwNDIyY2M0NDdlYTZj
10
+ MTIwZTRlMGQ1MWEzNzc0OTNlZTU1YjUzNjY5OTNlZTZjNDYxNTVkYzc1ZDBk
11
+ MzJiZWQ1M2Y2MmZiNDc3YzU1MGRiNWRlOTQ3ZTVmMDI3OTQ4OTk=
12
+ data.tar.gz: !binary |-
13
+ NDdkMTRhYjEyMDcxMmQ0MzY4ODM4Mjk1ZDY2NDZiZWM0YmYwNzQ4NzEyMjY2
14
+ OGQ0NzdmYTM4ZTQzNzczYjkxNWFlZTQ4NjIwZDdmMGUxYTRiYTE2OGVkNWFk
15
+ YWUzMjRlZGQ4NTUxY2NkNzFkYTBjODlhYzY3YWFiYTkwODY4ZWU=
data/README.markdown CHANGED
@@ -8,10 +8,11 @@ are related libraries available:
8
8
 
9
9
  ## SUPPORT
10
10
 
11
- If you found an issue, please file it in our [JIRA][1]. Also you are
12
- always welcome on `#libcouchbase` channel at [freenode.net IRC servers][2].
11
+ If you find an issue, please file it in our [JIRA][1]. Also you are
12
+ always welcome on the `#libcouchbase` channel at [freenode.net IRC servers][2].
13
13
 
14
- Documentation: [http://rdoc.info/gems/couchbase](http://rdoc.info/gems/couchbase)
14
+ Documentation: [http://docs.couchbase.com/couchbase-sdk-ruby-1.3/](http://docs.couchbase.com/couchbase-sdk-ruby-1.3/)
15
+ API Documentation: [http://www.couchbase.com/autodocs/](http://www.couchbase.com/autodocs/)
15
16
 
16
17
  ## INSTALL
17
18
 
@@ -39,7 +40,7 @@ your OS release:
39
40
  # Ubuntu 10.04 Lucid Lynx (Debian stable or testing)
40
41
  deb http://packages.couchbase.com/ubuntu lucid lucid/main
41
42
 
42
- Import Couchbase PGP key:
43
+ Import the Couchbase PGP key:
43
44
 
44
45
  wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
45
46
 
@@ -47,7 +48,7 @@ Then install them
47
48
 
48
49
  $ sudo apt-get update && sudo apt-get install libcouchbase-dev
49
50
 
50
- Again, if you need preview versions, just use another repositories in
51
+ Again, if you need a preview of a future version, just use another repository in
51
52
  your `couchbase.list`
52
53
 
53
54
  # Ubuntu 11.10 Oneiric Ocelot (Debian unstable)
@@ -72,8 +73,8 @@ Then to install libcouchbase itself, run:
72
73
 
73
74
  $ sudo yum update && sudo yum install libcouchbase-devel
74
75
 
75
- We have preview repositories for RPMs too, use them if you need to try
76
- fresh version of couchbase gem:
76
+ We have preview repositories for RPMs too, use them if you want to try
77
+ the latest version of libcouchbase:
77
78
 
78
79
  [couchbase]
79
80
  name = Couchbase package repository
@@ -85,8 +86,8 @@ fresh version of couchbase gem:
85
86
 
86
87
  ### Windows
87
88
 
88
- There no additional dependencies for Windows systems. The gem carry
89
- prebuilt binary for it.
89
+ There are no additional dependencies for Windows systems. The gem carries
90
+ a prebuilt binary for it.
90
91
 
91
92
  ### Couchbase gem
92
93
 
@@ -96,12 +97,12 @@ Now install the couchbase gem itself
96
97
 
97
98
  ## USAGE
98
99
 
99
- First of all you need to load library:
100
+ First, you need to load the library:
100
101
 
101
102
  require 'couchbase'
102
103
 
103
- There are several ways to establish new connection to Couchbase Server.
104
- By default it uses the `http://localhost:8091/pools/default/buckets/default`
104
+ There are several ways to establish a new connection to Couchbase Server.
105
+ By default it uses `http://localhost:8091/pools/default/buckets/default`
105
106
  as the endpoint. The client will automatically adjust configuration when
106
107
  the cluster will rebalance its nodes when nodes are added or deleted
107
108
  therefore this client is "smart".
@@ -122,13 +123,13 @@ The hash parameters take precedence on string URL.
122
123
  If you worry about state of your nodes or not sure what node is alive,
123
124
  you can pass the list of nodes and the library will iterate over it
124
125
  until finds the working one. From that moment it won't use **your**
125
- list, because node list from cluster config is more actual.
126
+ list, because node list from cluster config carries more detail.
126
127
 
127
128
  c = Couchbase.connect(:bucket => "mybucket",
128
129
  :node_list => ['example.com:8091', example.net'])
129
130
 
130
- There is also handy method `Couchbase.bucket` which uses thread local
131
- storage to keep the reference to default connection. You can set the
131
+ There is also a handy method `Couchbase.bucket` which uses thread local
132
+ storage to keep a reference to a connection. You can set the
132
133
  connection options via `Couchbase.connection_options`:
133
134
 
134
135
  Couchbase.connection_options = {:bucket => 'blog'}
@@ -137,9 +138,9 @@ connection options via `Couchbase.connection_options`:
137
138
 
138
139
  The library supports both synchronous and asynchronous mode. In
139
140
  asynchronous mode all operations will return control to caller
140
- without blocking current thread. You can pass the block to method and it
141
+ without blocking current thread. You can pass a block to the method and it
141
142
  will be called with result when the operation will be completed. You
142
- need to run event loop when you scheduled your operations:
143
+ need to run the event loop once you've scheduled your operations:
143
144
 
144
145
  c = Couchbase.connect
145
146
  c.run do |conn|
@@ -155,7 +156,7 @@ The handlers could be nested
155
156
  end
156
157
  end
157
158
 
158
- The asynchronous callback receives instance of `Couchbase::Result` which
159
+ The asynchronous callback receives an instance of `Couchbase::Result` which
159
160
  responds to several methods to figure out what was happened:
160
161
 
161
162
  * `success?`. Returns `true` if operation succed.
@@ -171,7 +172,7 @@ responds to several methods to figure out what was happened:
171
172
 
172
173
  * `cas`. The CAS version tag.
173
174
 
174
- * `node`. Node address. It is used in flush and stats commands.
175
+ * `node`. Node address. This is used in the flush and stats commands.
175
176
 
176
177
  * `operation`. The symbol, representing an operation.
177
178
 
@@ -186,14 +187,14 @@ used. It can be set in following fashions:
186
187
  handler = lambda {|opcode, key, exc| }
187
188
  c.on_error = handler
188
189
 
189
- By default connection uses `:quiet` mode. This mean it won't raise
190
- exceptions when the given key is not exists:
190
+ By default connections use `:quiet` mode. This mean it won't raise
191
+ exceptions when the given key does not exist:
191
192
 
192
193
  c.get("missing-key") #=> nil
193
194
 
194
195
  It could be useful when you are trying to make you code a bit efficient
195
196
  by avoiding exception handling. (See `#add` and `#replace` operations).
196
- You can turn on these exception by passing `:quiet => false` when you
197
+ You can turn on these exceptions by passing `:quiet => false` when you
197
198
  are instantiating the connection or change corresponding attribute:
198
199
 
199
200
  c.quiet = false
@@ -278,7 +279,7 @@ Hash-like syntax
278
279
 
279
280
  ### Add
280
281
 
281
- Add command will fail if the key already exists. It accepts the same
282
+ The add command will fail if the key already exists. It accepts the same
282
283
  options as set command above.
283
284
 
284
285
  c.add("foo", "bar")
@@ -338,8 +339,10 @@ Couchbase::Error::DeltaBadval if the delta or value is not a number.
338
339
  c.incr("missing2", :create => true) #=> 0
339
340
  c.incr("missing2", :create => true) #=> 1
340
341
 
341
- Note that it isn't the same as increment/decrement in ruby, which is
342
- performed on client side with following `set` operation:
342
+ Note that it isn't the same as increment/decrement in ruby. A
343
+ Couchbase increment is atomic on a distributed system. The
344
+ Ruby incement could ovewrite intermediate values with multiple
345
+ clients, as shown with following `set` operation:
343
346
 
344
347
  c["foo"] = 10
345
348
  c["foo"] -= 20 #=> -10
@@ -469,9 +472,9 @@ To execute view you need to fetch it from design document `_design/blog`:
469
472
  blog.views #=> ["recent_posts"]
470
473
  blog.recent_posts #=> [#<Couchbase::ViewRow:9855800 @id="hello-world" @key="2009/01/15 15:52:20" @value="Hello World" @doc=nil @meta={} @views=[]>, ...]
471
474
 
472
- Gem uses streaming parser to access view results so you can iterate them
473
- easily and if your code won't keep links to the documents GC might free
474
- them as soon as it decide they are unreachable, because parser doesn't
475
+ The gem uses a streaming parser to access view results so you can iterate them
476
+ easily. If your code doesn't keep links to the documents the GC might free
477
+ them as soon as it decides they are unreachable, because the parser doesn't
475
478
  store global JSON tree.
476
479
 
477
480
  blog.recent_posts.each do |doc|
@@ -499,7 +502,7 @@ You can also use Enumerator to iterate view results
499
502
  acc
500
503
  end
501
504
 
502
- The Couchbase server could generate errors during view execution with
505
+ Couchbase Server could generate errors during view execution with
503
506
  `200 OK` and partial results. By default the library raises exception as
504
507
  soon as errors detected in the result stream, but you can define the
505
508
  callback `on_error` to intercept these errors and do something more
@@ -569,6 +572,69 @@ choose from several asynchronous IO options:
569
572
  end
570
573
  end
571
574
 
575
+ ## HACKING
576
+
577
+ Clone the repository. For starters, you can use github mirror, but
578
+ make sure you have read and understand [CONTRIBUTING.markdown][10] if
579
+ you are going to send us patches.
580
+
581
+ $ git clone git://github.com/couchbase/couchbase-ruby-client.git
582
+ $ cd couchbase-ruby-client
583
+
584
+ Install all development dependencies. You can use any ruby version
585
+ since 1.8.7, but make sure your changes work at least on major
586
+ releases (1.8.7, 1.9.3, 2.0.0 and 2.1.0 at the moment):
587
+
588
+ $ gem install bundler
589
+ $ bundle install
590
+
591
+ Don't forget to write the tests. You can find examples in the `tests/`
592
+ directory. To run tests with a mock just compile extension and run the
593
+ `test` task, it will download a test mock of couchbase cluster as a
594
+ part of the process (the mock is generally slower, but easier to
595
+ setup):
596
+
597
+ $ rake compile test
598
+
599
+ If you have real Couchbase server installed somewhere, you can pass
600
+ its address using environment variable `COUCHBASE_SERVER` like this:
601
+
602
+ $ COUCHBASE_SERVER=localhost:8091 rake compile test
603
+
604
+ And finally, you can package the gem with your awesome changes. For
605
+ UNIX-like systems a regular source-based package will be enough, so the
606
+ command below will produce `pkg/couchbase-VERSION.gem`, where
607
+ `VERSION` is the current version from file `lib/couchbase/version.rb`:
608
+
609
+ $ rake package
610
+
611
+ The Windows operating system usually doesn't have a build environment
612
+ installed. This is why we are cross-compiling blobs for Windows from
613
+ UNIX-like boxes. To do it you need to install mingw and the
614
+ [rake-compiler][11] and then build a variety of ruby versions currently
615
+ supported on Windows. An example config looks like this:
616
+
617
+ $ rake-compiler update-config
618
+ Updating /home/avsej/.rake-compiler/config.yml
619
+ Found Ruby version 1.8.7 for platform i386-mingw32 (/home/avsej/.rake-compiler/ruby/i686-w64-mingw32/ruby-1.8.7-p374/lib/ruby/1.8/i386-mingw32/rbconfig.rb)
620
+ Found Ruby version 1.9.3 for platform i386-mingw32 (/home/avsej/.rake-compiler/ruby/i686-w64-mingw32/ruby-1.9.3-p448/lib/ruby/1.9.1/i386-mingw32/rbconfig.rb)
621
+ Found Ruby version 2.0.0 for platform i386-mingw32 (/home/avsej/.rake-compiler/ruby/i686-w64-mingw32/ruby-2.0.0-p247/lib/ruby/2.0.0/i386-mingw32/rbconfig.rb)
622
+ Found Ruby version 2.1.0 for platform i386-mingw32 (/home/avsej/.rake-compiler/ruby/i686-w64-mingw32/ruby-2.1.0/lib/ruby/2.1.0/i386-mingw32/rbconfig.rb)
623
+ Found Ruby version 1.9.3 for platform x64-mingw32 (/home/avsej/.rake-compiler/ruby/x86_64-w64-mingw32/ruby-1.9.3-p448/lib/ruby/1.9.1/x64-mingw32/rbconfig.rb)
624
+ Found Ruby version 2.0.0 for platform x64-mingw32 (/home/avsej/.rake-compiler/ruby/x86_64-w64-mingw32/ruby-2.0.0-p247/lib/ruby/2.0.0/x64-mingw32/rbconfig.rb)
625
+ Found Ruby version 2.1.0 for platform x64-mingw32 (/home/avsej/.rake-compiler/ruby/x86_64-w64-mingw32/ruby-2.1.0/lib/ruby/2.1.0/x64-mingw32/rbconfig.rb)
626
+
627
+ Before you build, check relevant ruby and libcouchbase versions in
628
+ `tasks/compile.rake`. After that you can run the `package:windows`
629
+ task and you will find all artifacts in `pkg/` directory:
630
+
631
+ $ rake package:windows
632
+ $ ls -1 pkg/*.gem
633
+ pkg/couchbase-1.3.4.gem
634
+ pkg/couchbase-1.3.4-x64-mingw32.gem
635
+ pkg/couchbase-1.3.4-x86-mingw32.gem
636
+
637
+
572
638
  [1]: http://couchbase.com/issues/browse/RCBC
573
639
  [2]: http://freenode.net/irc_servers.shtml
574
640
  [3]: http://www.couchbase.com/develop/c/current
@@ -578,4 +644,6 @@ choose from several asynchronous IO options:
578
644
  [7]: https://github.com/couchbase/couchbase-ruby-model
579
645
  [8]: http://www.couchbase.com/develop/c/current
580
646
  [9]: http://rubygems.org/gems/eventmachine
647
+ [10]: https://github.com/couchbase/couchbase-ruby-client/blob/master/CONTRIBUTING.markdown
648
+ [11]: https://github.com/luislavena/rake-compiler
581
649
 
@@ -3,6 +3,32 @@
3
3
  This document is a list of user visible feature changes and important
4
4
  bugfixes. Do not forget to update this doc in every important patch.
5
5
 
6
+ ## 1.3.4 (2014-01-08)
7
+
8
+ * [major] Build 64-bit versions of the extensions for Windows
9
+ platform. Also support ruby 2.0 and 2.1.
10
+
11
+ * [minor] Update hacking section in README
12
+
13
+ * [minor] Fix gemspec warnings regarding versions of the dependencies.
14
+ Now it honours semantic versioning and doesn't use strict versions.
15
+
16
+ * [major] RCBC-151 Return CAS in extended mode for incr/decr
17
+
18
+ * [minor] RCBC-150 Update list of options on `Cluster.create_bucket`.
19
+ Added new options: `:replica_index`, `:flush_enabled`,
20
+ `:parallel_db_and_view_compaction`.
21
+
22
+ * [major] Allow retries on Couchbase::Bucket#cas collisions. Now it
23
+ takes a `:retry` Fixnum option that specifies the maximum number of
24
+ times the method should retry the entire get/update/set operation
25
+ when a `Couchbase::Error::KeyExists` error is encountered due to a
26
+ concurrent update from another writer between its `#get` and `#set`
27
+ calls.
28
+
29
+ * [major] MD5 and truncate ActiveSupport::Cache keys that are longer
30
+ than 250 characters.
31
+
6
32
  ## 1.3.3 (2013-09-12)
7
33
 
8
34
  * [major] RCBC-134 Allow application to use several connections with
data/Rakefile CHANGED
@@ -15,8 +15,6 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
- require 'bundler/gem_tasks'
19
-
20
18
  Dir['tasks/*.rake'].sort.each { |f| load f }
21
19
 
22
20
  task :default => [:clobber, :compile, :test]
data/couchbase.gemspec CHANGED
@@ -35,15 +35,15 @@ Gem::Specification.new do |s|
35
35
  s.extensions = `git ls-files -- ext/**/extconf.rb`.split("\n")
36
36
  s.require_paths = ['lib']
37
37
 
38
- s.add_runtime_dependency 'yaji', '~> 0.3.2'
38
+ s.add_runtime_dependency 'yaji', '~> 0.3', '>= 0.3.2'
39
39
  s.add_runtime_dependency 'multi_json', '~> 1.0'
40
- s.add_runtime_dependency 'connection_pool', '~> 1.0.0'
40
+ s.add_runtime_dependency 'connection_pool', '~> 1.0', '>= 1.0.0'
41
41
 
42
42
  s.add_development_dependency 'rake'
43
- s.add_development_dependency 'minitest', '~> 5.0.4'
44
- s.add_development_dependency 'rake-compiler', '>= 0.7.5'
45
- s.add_development_dependency 'mini_portile'
46
- s.add_development_dependency 'yajl-ruby', '~> 1.1.0'
43
+ s.add_development_dependency 'minitest', '~> 5.0', '>= 5.0.4'
44
+ s.add_development_dependency 'rake-compiler', '~> 0.7', '>= 0.7.5'
45
+ s.add_development_dependency 'mini_portile', '~> 0.5', '>= 0.5.2'
46
+ s.add_development_dependency 'yajl-ruby', '~> 1.1', '>= 1.1.0'
47
47
  s.add_development_dependency 'active_support'
48
48
  s.add_development_dependency 'eventmachine'
49
49
  end
@@ -89,6 +89,7 @@ cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
89
89
  params.cmd.arith.sign = sign;
90
90
  cb_params_build(&params);
91
91
  ctx = cb_context_alloc_common(bucket, proc, params.cmd.arith.num);
92
+ ctx->extended = params.cmd.arith.extended;
92
93
  err = lcb_arithmetic(bucket->handle, (const void *)ctx,
93
94
  params.cmd.arith.num, params.cmd.arith.ptr);
94
95
  cb_params_destroy(&params);
@@ -338,7 +338,7 @@ do_connect(struct cb_bucket_st *bucket)
338
338
  ciops.v.v0.type = LCB_IO_OPS_SELECT;
339
339
  #ifdef _WIN32
340
340
  } else if (bucket->engine == cb_sym_iocp) {
341
- ciops.v.v0.type = LCB_IO_OPS_IOCP;
341
+ ciops.v.v0.type = LCB_IO_OPS_WINIOCP;
342
342
  #endif
343
343
  } else if (bucket->engine == cb_sym_libev) {
344
344
  ciops.v.v0.type = LCB_IO_OPS_LIBEV;
@@ -46,8 +46,12 @@ end
46
46
  $CFLAGS << ' -std=c99 -Wall -Wextra '
47
47
  if ENV['DEBUG']
48
48
  $CFLAGS << ' -O0 -ggdb3 -pedantic '
49
+ else
50
+ $CFLAGS << ' -O2'
51
+ $LDFLAGS << ' -Wl,--strip-debug' if RbConfig::CONFIG['target_os'] =~ /mingw32/
49
52
  end
50
53
 
54
+
51
55
  if RbConfig::CONFIG['target_os'] =~ /mingw32/
52
56
  dir_config("libcouchbase")
53
57
  else
@@ -97,6 +101,7 @@ else
97
101
  dir_config("libcouchbase", HEADER_DIRS, LIB_DIRS)
98
102
  end
99
103
 
104
+
100
105
  if COMMON_HEADERS !~ /"ruby\.h"/
101
106
  (COMMON_HEADERS ||= "") << %(\n#include "ruby.h"\n)
102
107
  end
@@ -126,6 +131,8 @@ def die(message)
126
131
  abort
127
132
  end
128
133
 
134
+ install_notice = "You must install libcouchbase >= 2.1.3\nSee http://www.couchbase.com/communities/c/ for more details"
135
+
129
136
  unless try_compile(<<-SRC)
130
137
  #include <libcouchbase/couchbase.h>
131
138
  #include <stdio.h>
@@ -135,10 +142,11 @@ unless try_compile(<<-SRC)
135
142
  return 0;
136
143
  }
137
144
  SRC
138
- die("You must install libcouchbase >= 2.1.3\nSee http://www.couchbase.com/communities/c/ for more details")
145
+ die(install_notice)
139
146
  end
140
147
 
141
- have_library("couchbase", "lcb_verify_compiler_setup", "libcouchbase/couchbase.h") # just to add -lcouchbase properly
148
+ # just to add -lcouchbase properly
149
+ have_library("couchbase", "lcb_verify_compiler_setup", "libcouchbase/couchbase.h") or die(install_notice)
142
150
  have_header("mach/mach_time.h")
143
151
  have_header("stdint.h") or die("Failed to locate stdint.h")
144
152
  have_header("sys/time.h")
@@ -550,7 +550,7 @@ typedef fd_set rb_fdset_t;
550
550
 
551
551
  typedef struct loop_select_arg {
552
552
  rb_mt_loop *loop;
553
- rb_fdset_t in, out;
553
+ rb_fdset_t in, out, exc;
554
554
  } ls_arg;
555
555
 
556
556
  static void
@@ -574,7 +574,7 @@ loop_run_select(VALUE argp)
574
574
  {
575
575
  ls_arg *args = (ls_arg*) argp;
576
576
  rb_mt_loop *loop = args->loop;
577
- rb_fdset_t *in = NULL, *out = NULL;
577
+ rb_fdset_t *in = NULL, *out = NULL, *exc = NULL;
578
578
  struct timeval timeout;
579
579
  struct timeval *timeoutp = NULL;
580
580
  int result, max = 0;
@@ -598,21 +598,26 @@ loop_run_select(VALUE argp)
598
598
  uint32_t i;
599
599
  rb_fd_init(&args->in);
600
600
  rb_fd_init(&args->out);
601
+ rb_fd_init(&args->exc);
601
602
  for(i = 0; i < loop->events.count; i++) {
602
603
  rb_mt_socket_list *list = &loop->events.sockets[i];
603
- if (list->flags & LCB_READ_EVENT) {
604
- in = &args->in;
605
- rb_fd_set(list->socket, in);
606
- }
607
- if (list->flags & LCB_WRITE_EVENT) {
608
- out = &args->out;
609
- rb_fd_set(list->socket, out);
604
+ if (list->flags != 0) {
605
+ if (list->flags & LCB_READ_EVENT) {
606
+ in = &args->in;
607
+ rb_fd_set(list->socket, in);
608
+ }
609
+ if (list->flags & LCB_WRITE_EVENT) {
610
+ out = &args->out;
611
+ rb_fd_set(list->socket, out);
612
+ }
613
+ exc = &args->exc;
614
+ rb_fd_set(list->socket, exc);
610
615
  }
611
616
  }
612
617
  max = events_max_fd(&loop->events) + 1;
613
618
  }
614
619
 
615
- result = rb_thread_fd_select(max, in, out, NULL, timeoutp);
620
+ result = rb_thread_fd_select(max, in, out, exc, timeoutp);
616
621
 
617
622
  if (result < 0) {
618
623
  rb_sys_fail("rb_thread_fd_select");
@@ -636,6 +641,10 @@ loop_run_select(VALUE argp)
636
641
  flags |= LCB_WRITE_EVENT;
637
642
  result--;
638
643
  }
644
+ if (exc && rb_fd_isset(list->socket, exc)) {
645
+ flags = LCB_ERROR_EVENT | LCB_WRITE_EVENT;
646
+ result--;
647
+ }
639
648
  if (flags) {
640
649
  loop_enque_events(&loop->callbacks, sock, flags);
641
650
  }