couchbase 1.3.2 → 1.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA512:
3
+ metadata.gz: 6e17257cd0c7c6e0d867ac56962ad7561b8a658bc3bb06b07d82a1c2e6047b0b032b4c1fc6b1e19d4c75762b37be3fca941f5691f74ada008feba7dffaa57ed8
4
+ data.tar.gz: c3283d9b48c266c38f53045841e6b191573f570fa05b6cb9fa13ac9046e24eaab599f38b7f5444bb2555f35a113b763e6813078d860201b90b32a93c9b49513f
5
+ SHA1:
6
+ metadata.gz: 3f5b7a5d5b5960a30be144f90b68a6a697cfd601
7
+ data.tar.gz: 58c37ac51144332757baecff17a3b1677d9ee6c8
@@ -19,4 +19,4 @@ rvm:
19
19
 
20
20
  notifications:
21
21
  email:
22
- - sdk_dev@couchbase.com
22
+ - sergey@couchbase.com
@@ -3,6 +3,56 @@
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.3 (2013-09-12)
7
+
8
+ * [major] RCBC-134 Allow application to use several connections with
9
+ thread-local singleton.
10
+
11
+ * [major] RCBC-135 Fixed invalid memory access which was detected by
12
+ using 'GC.stress = true' in tests.
13
+
14
+ * [major] RCBC-141 Initialize event indexes correctly. The plugin
15
+ didn't trace event callbacks, which might lead to invalid memory
16
+ access during rebalance, where libcouchbase creates/removes a lot of
17
+ events because of a fast-changing topology.
18
+
19
+ * [major] RCBC-137 Add selection options for new IO engines: select
20
+ and iocp.
21
+
22
+ * [major] When setting the username field, check for password
23
+ presence. Fixes segmentation fault in this code:
24
+
25
+ Couchbase.connect(:username => "default", :bucket => "default")
26
+
27
+ * [minor] Allow to determine the version of libcouchbase:
28
+
29
+ Couchbase.libcouchbase_version
30
+
31
+ * [major] RCBC-136 Build shared object for ruby 2.0 on windows. Also
32
+ fixes build script when using latest rake and rake-compiler.
33
+
34
+ * [minor] Fix deprecation warning on ruby 2.x. On newer versions it
35
+ should use `rb_thread_call_without_gvl()`.
36
+
37
+ ext/couchbase_ext/multithread_plugin.c: In function ‘loop_run_poll’:
38
+ ext/couchbase_ext/multithread_plugin.c:772:5: warning: ‘rb_thread_blocking_region’ is deprecated (declared at .../2.0.0-p247-dbg/include/ruby-2.0.0/ruby/intern.h:839) [-Wdeprecated-declarations]
39
+ rb_thread_blocking_region(loop_blocking_poll, args, RUBY_UBF_PROCESS, NULL);
40
+
41
+ * [major] Do not try to compile with plugins for Windows platform.
42
+
43
+ * [major] Force handle to be NULL on `lcb_create()` failure.
44
+ `lcb_create()` can leave garbage in the pointer even if the call
45
+ itself failed. This behaviour could lead to illegal memory access
46
+ on GC.
47
+
48
+ * [minor] Remove usage of `RARRAY_PTR` in favor of `rb_ary_entry`.
49
+ This improves performance significantly on Rubinius and also
50
+ improves compatibility with future CRuby 2.1 which introduces
51
+ generational garbage collection. This results in these arrays not
52
+ having to be rescanned in Rubinius and not marked as shady in
53
+ RBGCENC in CRuby 2.1.
54
+ For more discussion, also see: https://bugs.ruby-lang.org/issues/8399
55
+
6
56
  ## 1.3.2 (2013-07-10)
7
57
 
8
58
  * [major] RCBC-133 Allow application to select the strategy of reading
@@ -130,14 +130,14 @@ cb_params_touch_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
130
130
  rb_raise(rb_eArgError, "must be at least one key");
131
131
  }
132
132
  if (argc == 1) {
133
- VALUE keys = RARRAY_PTR(argv)[0];
133
+ VALUE keys = rb_ary_entry(argv, 0);
134
134
  switch(TYPE(keys)) {
135
135
  case T_ARRAY:
136
136
  /* array of keys as a first argument */
137
137
  params->cmd.touch.array = 1;
138
138
  cb_params_touch_alloc(params, RARRAY_LEN(keys));
139
139
  for (ii = 0; ii < params->cmd.touch.num; ++ii) {
140
- cb_params_touch_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.touch.ttl);
140
+ cb_params_touch_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.touch.ttl);
141
141
  }
142
142
  break;
143
143
  case T_HASH:
@@ -155,7 +155,7 @@ cb_params_touch_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
155
155
  /* just list of arguments */
156
156
  cb_params_touch_alloc(params, argc);
157
157
  for (ii = 0; ii < params->cmd.touch.num; ++ii) {
158
- cb_params_touch_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.touch.ttl);
158
+ cb_params_touch_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.touch.ttl);
159
159
  }
160
160
  }
161
161
  }
@@ -215,14 +215,14 @@ cb_params_remove_parse_arguments(struct cb_params_st *params, int argc, VALUE ar
215
215
  rb_raise(rb_eArgError, "must be at least one key");
216
216
  }
217
217
  if (argc == 1) {
218
- VALUE keys = RARRAY_PTR(argv)[0];
218
+ VALUE keys = rb_ary_entry(argv, 0);
219
219
  switch(TYPE(keys)) {
220
220
  case T_ARRAY:
221
221
  /* array of keys as a first argument */
222
222
  params->cmd.remove.array = 1;
223
223
  cb_params_remove_alloc(params, RARRAY_LEN(keys));
224
224
  for (ii = 0; ii < params->cmd.remove.num; ++ii) {
225
- cb_params_remove_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.remove.cas);
225
+ cb_params_remove_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.remove.cas);
226
226
  }
227
227
  break;
228
228
  case T_HASH:
@@ -240,7 +240,7 @@ cb_params_remove_parse_arguments(struct cb_params_st *params, int argc, VALUE ar
240
240
  /* just list of arguments */
241
241
  cb_params_remove_alloc(params, argc);
242
242
  for (ii = 0; ii < params->cmd.remove.num; ++ii) {
243
- cb_params_remove_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.remove.cas);
243
+ cb_params_remove_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.remove.cas);
244
244
  }
245
245
  }
246
246
  }
@@ -344,7 +344,7 @@ cb_params_store_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
344
344
  }
345
345
  switch (argc) {
346
346
  case 1:
347
- keys = RARRAY_PTR(argv)[0];
347
+ keys = rb_ary_entry(argv, 0);
348
348
  switch(TYPE(keys)) {
349
349
  case T_HASH:
350
350
  /* key-value pairs */
@@ -360,7 +360,7 @@ cb_params_store_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
360
360
  case 2:
361
361
  /* just key and value */
362
362
  cb_params_store_alloc(params, 1);
363
- cb_params_store_init_item(params, 0, RARRAY_PTR(argv)[0], RARRAY_PTR(argv)[1],
363
+ cb_params_store_init_item(params, 0, rb_ary_entry(argv, 0), rb_ary_entry(argv, 1),
364
364
  params->cmd.store.flags, params->cmd.store.cas, params->cmd.store.ttl);
365
365
  break;
366
366
  default:
@@ -475,15 +475,15 @@ cb_params_get_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
475
475
  rb_raise(rb_eArgError, "must be at least one key");
476
476
  }
477
477
  if (argc == 1) {
478
- VALUE keys = RARRAY_PTR(argv)[0];
478
+ VALUE keys = rb_ary_entry(argv, 0);
479
479
  switch(TYPE(keys)) {
480
480
  case T_ARRAY:
481
481
  /* array of keys as a first argument */
482
482
  params->cmd.get.array = 1;
483
483
  cb_params_get_alloc(params, RARRAY_LEN(keys));
484
484
  for (ii = 0; ii < params->cmd.get.num; ++ii) {
485
- rb_ary_push(params->cmd.get.keys_ary, RARRAY_PTR(keys)[ii]);
486
- cb_params_get_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.get.ttl);
485
+ rb_ary_push(params->cmd.get.keys_ary, rb_ary_entry(keys, ii));
486
+ cb_params_get_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.get.ttl);
487
487
  }
488
488
  break;
489
489
  case T_HASH:
@@ -505,8 +505,8 @@ cb_params_get_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
505
505
  /* just list of arguments */
506
506
  cb_params_get_alloc(params, argc);
507
507
  for (ii = 0; ii < params->cmd.get.num; ++ii) {
508
- rb_ary_push(params->cmd.get.keys_ary, RARRAY_PTR(argv)[ii]);
509
- cb_params_get_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.get.ttl);
508
+ rb_ary_push(params->cmd.get.keys_ary, rb_ary_entry(argv, ii));
509
+ cb_params_get_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.get.ttl);
510
510
  }
511
511
  }
512
512
  }
@@ -589,14 +589,14 @@ cb_params_arith_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
589
589
  rb_raise(rb_eArgError, "must be at least one key");
590
590
  }
591
591
  if (argc == 1) {
592
- VALUE keys = RARRAY_PTR(argv)[0];
592
+ VALUE keys = rb_ary_entry(argv, 0);
593
593
  switch(TYPE(keys)) {
594
594
  case T_ARRAY:
595
595
  /* array of keys as a first argument */
596
596
  params->cmd.arith.array = 1;
597
597
  cb_params_arith_alloc(params, RARRAY_LEN(keys));
598
598
  for (ii = 0; ii < params->cmd.arith.num; ++ii) {
599
- cb_params_arith_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.arith.delta);
599
+ cb_params_arith_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.arith.delta);
600
600
  }
601
601
  break;
602
602
  case T_HASH:
@@ -613,7 +613,7 @@ cb_params_arith_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
613
613
  /* just list of arguments */
614
614
  cb_params_arith_alloc(params, argc);
615
615
  for (ii = 0; ii < params->cmd.arith.num; ++ii) {
616
- cb_params_arith_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.arith.delta);
616
+ cb_params_arith_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.arith.delta);
617
617
  }
618
618
  }
619
619
  }
@@ -643,14 +643,14 @@ cb_params_stats_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
643
643
  lcb_size_t ii;
644
644
 
645
645
  if (argc == 1) {
646
- VALUE keys = RARRAY_PTR(argv)[0];
646
+ VALUE keys = rb_ary_entry(argv, 0);
647
647
  switch(TYPE(keys)) {
648
648
  case T_ARRAY:
649
649
  /* array of keys as a first argument */
650
650
  params->cmd.stats.array = 1;
651
651
  cb_params_stats_alloc(params, RARRAY_LEN(keys));
652
652
  for (ii = 0; ii < params->cmd.stats.num; ++ii) {
653
- cb_params_stats_init_item(params, ii, RARRAY_PTR(keys)[ii]);
653
+ cb_params_stats_init_item(params, ii, rb_ary_entry(keys, ii));
654
654
  }
655
655
  break;
656
656
  default:
@@ -665,7 +665,7 @@ cb_params_stats_parse_arguments(struct cb_params_st *params, int argc, VALUE arg
665
665
  /* just list of arguments */
666
666
  cb_params_stats_alloc(params, argc);
667
667
  for (ii = 0; ii < params->cmd.stats.num; ++ii) {
668
- cb_params_stats_init_item(params, ii, RARRAY_PTR(argv)[ii]);
668
+ cb_params_stats_init_item(params, ii, rb_ary_entry(argv, ii));
669
669
  }
670
670
  }
671
671
  }
@@ -698,14 +698,14 @@ cb_params_observe_parse_arguments(struct cb_params_st *params, int argc, VALUE a
698
698
  rb_raise(rb_eArgError, "must be at least one key");
699
699
  }
700
700
  if (argc == 1) {
701
- VALUE keys = RARRAY_PTR(argv)[0];
701
+ VALUE keys = rb_ary_entry(argv, 0);
702
702
  switch(TYPE(keys)) {
703
703
  case T_ARRAY:
704
704
  /* array of keys as a first argument */
705
705
  params->cmd.observe.array = 1;
706
706
  cb_params_observe_alloc(params, RARRAY_LEN(keys));
707
707
  for (ii = 0; ii < params->cmd.observe.num; ++ii) {
708
- cb_params_observe_init_item(params, ii, RARRAY_PTR(keys)[ii]);
708
+ cb_params_observe_init_item(params, ii, rb_ary_entry(keys, ii));
709
709
  }
710
710
  break;
711
711
  default:
@@ -717,7 +717,7 @@ cb_params_observe_parse_arguments(struct cb_params_st *params, int argc, VALUE a
717
717
  /* just list of arguments */
718
718
  cb_params_observe_alloc(params, argc);
719
719
  for (ii = 0; ii < params->cmd.observe.num; ++ii) {
720
- cb_params_observe_init_item(params, ii, RARRAY_PTR(argv)[ii]);
720
+ cb_params_observe_init_item(params, ii, rb_ary_entry(argv, ii));
721
721
  }
722
722
  }
723
723
  }
@@ -771,7 +771,7 @@ cb_params_unlock_parse_options(struct cb_params_st *params, VALUE options)
771
771
  cb_params_unlock_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
772
772
  {
773
773
  if (argc == 1) {
774
- VALUE keys = RARRAY_PTR(argv)[0];
774
+ VALUE keys = rb_ary_entry(argv, 0);
775
775
  switch(TYPE(keys)) {
776
776
  case T_HASH:
777
777
  /* key-cas pairs */
@@ -847,7 +847,7 @@ do_params_build(VALUE ptr)
847
847
  VALUE argv = params->args;
848
848
 
849
849
  /* extract options */
850
- if (argc > 1 && TYPE(RARRAY_PTR(argv)[argc-1]) == T_HASH) {
850
+ if (argc > 1 && TYPE(rb_ary_entry(argv, argc-1)) == T_HASH) {
851
851
  opts = rb_ary_pop(argv);
852
852
  --argc;
853
853
  } else {
@@ -865,7 +865,7 @@ do_params_build(VALUE ptr)
865
865
  case cb_cmd_remove:
866
866
  params->cmd.remove.quiet = params->bucket->quiet;
867
867
  if (argc == 2) {
868
- int type = TYPE(RARRAY_PTR(argv)[1]);
868
+ int type = TYPE(rb_ary_entry(argv, 1));
869
869
  if (type == T_FIXNUM || type == T_BIGNUM) {
870
870
  /* allow form delete("foo", 0xdeadbeef) */
871
871
  --argc;
@@ -906,7 +906,7 @@ do_params_build(VALUE ptr)
906
906
  params->cmd.arith.initial = params->bucket->default_arith_init;
907
907
  params->cmd.arith.delta = 1;
908
908
  params->cmd.arith.ttl = params->bucket->default_ttl;
909
- if (argc == 2 && TYPE(RARRAY_PTR(argv)[1]) == T_FIXNUM) {
909
+ if (argc == 2 && TYPE(rb_ary_entry(argv, 1)) == T_FIXNUM) {
910
910
  /* allow form incr("foo", 1) */
911
911
  --argc;
912
912
  params->cmd.arith.delta = NUM2ULL(rb_ary_pop(argv)) & INT64_MAX;
@@ -926,7 +926,7 @@ do_params_build(VALUE ptr)
926
926
  case cb_cmd_unlock:
927
927
  params->cmd.unlock.quiet = params->bucket->quiet;
928
928
  if (argc == 2) {
929
- int type = TYPE(RARRAY_PTR(argv)[1]);
929
+ int type = TYPE(rb_ary_entry(argv, 1));
930
930
  if (type == T_FIXNUM || type == T_BIGNUM) {
931
931
  /* allow form unlock("foo", 0xdeadbeef) */
932
932
  --argc;
@@ -97,7 +97,9 @@ cb_bucket_mark(void *ptr)
97
97
  rb_gc_mark(bucket->on_error_proc);
98
98
  rb_gc_mark(bucket->on_connect_proc);
99
99
  rb_gc_mark(bucket->key_prefix_val);
100
- st_foreach(bucket->object_space, cb_bucket_mark_object_i, (st_data_t)bucket);
100
+ if (bucket->object_space) {
101
+ st_foreach(bucket->object_space, cb_bucket_mark_object_i, (st_data_t)bucket);
102
+ }
101
103
  }
102
104
  }
103
105
 
@@ -260,7 +262,12 @@ do_scan_connection_options(struct cb_bucket_st *bucket, int argc, VALUE *argv)
260
262
  if (arg != Qnil) {
261
263
  if (arg == cb_sym_default) {
262
264
  bucket->engine = cb_sym_default;
263
- #ifndef _WIN32
265
+ } else if (arg == cb_sym_select) {
266
+ bucket->engine = cb_sym_select;
267
+ #ifdef _WIN32
268
+ } else if (arg == cb_sym_iocp) {
269
+ bucket->engine = cb_sym_iocp;
270
+ #else
264
271
  } else if (arg == cb_sym_libev) {
265
272
  bucket->engine = cb_sym_libev;
266
273
  } else if (arg == cb_sym_libevent) {
@@ -317,11 +324,7 @@ do_connect(struct cb_bucket_st *bucket)
317
324
  struct lcb_create_st create_opts;
318
325
 
319
326
  if (bucket->handle) {
320
- lcb_destroy(bucket->handle);
321
- lcb_destroy_io_ops(bucket->io);
322
- bucket->handle = NULL;
323
- bucket->io = NULL;
324
- bucket->connected = 0;
327
+ cb_bucket_disconnect(bucket->self);
325
328
  }
326
329
 
327
330
  {
@@ -331,6 +334,12 @@ do_connect(struct cb_bucket_st *bucket)
331
334
 
332
335
  if (bucket->engine == cb_sym_libevent) {
333
336
  ciops.v.v0.type = LCB_IO_OPS_LIBEVENT;
337
+ } else if (bucket->engine == cb_sym_select) {
338
+ ciops.v.v0.type = LCB_IO_OPS_SELECT;
339
+ #ifdef _WIN32
340
+ } else if (bucket->engine == cb_sym_iocp) {
341
+ ciops.v.v0.type = LCB_IO_OPS_IOCP;
342
+ #endif
334
343
  } else if (bucket->engine == cb_sym_libev) {
335
344
  ciops.v.v0.type = LCB_IO_OPS_LIBEV;
336
345
  } else if (bucket->engine == cb_sym_eventmachine) {
@@ -359,11 +368,12 @@ do_connect(struct cb_bucket_st *bucket)
359
368
  create_opts.v.v1.type = bucket->type;
360
369
  create_opts.v.v1.host = RTEST(bucket->node_list) ? RSTRING_PTR(bucket-> node_list) : RSTRING_PTR(bucket->authority);
361
370
  create_opts.v.v1.user = RTEST(bucket->username) ? RSTRING_PTR(bucket->username) : NULL;
362
- create_opts.v.v1.passwd = RTEST(bucket->username) ? RSTRING_PTR(bucket->password) : NULL;
371
+ create_opts.v.v1.passwd = RTEST(bucket->password) ? RSTRING_PTR(bucket->password) : NULL;
363
372
  create_opts.v.v1.bucket = RSTRING_PTR(bucket->bucket);
364
373
  create_opts.v.v1.io = bucket->io;
365
374
  err = lcb_create(&bucket->handle, &create_opts);
366
375
  if (err != LCB_SUCCESS) {
376
+ bucket->handle = NULL;
367
377
  rb_exc_raise(cb_check_error(err, "failed to create libcouchbase instance", Qnil));
368
378
  }
369
379
  lcb_set_cookie(bucket->handle, bucket);
@@ -388,10 +398,7 @@ do_connect(struct cb_bucket_st *bucket)
388
398
  }
389
399
  err = lcb_connect(bucket->handle);
390
400
  if (err != LCB_SUCCESS) {
391
- lcb_destroy(bucket->handle);
392
- lcb_destroy_io_ops(bucket->io);
393
- bucket->handle = NULL;
394
- bucket->io = NULL;
401
+ cb_bucket_disconnect(bucket->self);
395
402
  rb_exc_raise(cb_check_error(err, "failed to connect libcouchbase instance to server", Qnil));
396
403
  }
397
404
  bucket->exception = Qnil;
@@ -402,10 +409,7 @@ do_connect(struct cb_bucket_st *bucket)
402
409
  if (!bucket->async) {
403
410
  lcb_wait(bucket->handle);
404
411
  if (bucket->exception != Qnil) {
405
- lcb_destroy(bucket->handle);
406
- lcb_destroy_io_ops(bucket->io);
407
- bucket->handle = NULL;
408
- bucket->io = NULL;
412
+ cb_bucket_disconnect(bucket->self);
409
413
  rb_exc_raise(bucket->exception);
410
414
  }
411
415
  }
@@ -484,6 +488,8 @@ cb_bucket_alloc(VALUE klass)
484
488
  * @option options [Symbol] :engine (:default) the IO engine to use
485
489
  * Currently following engines are supported:
486
490
  * :default :: Built-in engine (multi-thread friendly)
491
+ * :select :: select(2) IO plugin from libcouchbase
492
+ * :iocp :: "I/O Completion Ports" plugin from libcouchbase (windows only)
487
493
  * :libevent :: libevent IO plugin from libcouchbase (optional)
488
494
  * :libev :: libev IO plugin from libcouchbase (optional)
489
495
  * :eventmachine :: EventMachine plugin (builtin, but requires EM gem and ruby 1.9+)
@@ -73,6 +73,7 @@ ID cb_sym_hostname;
73
73
  ID cb_sym_http_request;
74
74
  ID cb_sym_increment;
75
75
  ID cb_sym_initial;
76
+ ID cb_sym_iocp;
76
77
  ID cb_sym_key_prefix;
77
78
  ID cb_sym_libev;
78
79
  ID cb_sym_libevent;
@@ -97,6 +98,7 @@ ID cb_sym_put;
97
98
  ID cb_sym_quiet;
98
99
  ID cb_sym_replace;
99
100
  ID cb_sym_replica;
101
+ ID cb_sym_select;
100
102
  ID cb_sym_send_threshold;
101
103
  ID cb_sym_set;
102
104
  ID cb_sym_stats;
@@ -183,6 +185,16 @@ VALUE cb_eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x19 */
183
185
  VALUE cb_eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x1a */
184
186
  VALUE cb_eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x1b */
185
187
  VALUE cb_eBadHandleError; /* LCB_EBADHANDLE = 0x1c */
188
+ VALUE cb_eServerBug; /* LCB_SERVER_BUG = 0x1d */
189
+ VALUE cb_ePluginVersionMismatch; /* LCB_PLUGIN_VERSION_MISMATCH = 0x1e */
190
+ VALUE cb_eInvalidHostFormat; /* LCB_INVALID_HOST_FORMAT = 0x1f */
191
+ VALUE cb_eInvalidChar; /* LCB_INVALID_CHAR = 0x20 */
192
+ VALUE cb_eDurabilityTooMany; /* LCB_DURABILITY_ETOOMANY = 0x21 */
193
+ VALUE cb_eDuplicateCommands; /* LCB_DUPLICATE_COMMANDS = 0x22 */
194
+ VALUE cb_eNoMatchingServer; /* LCB_NO_MATCHING_SERVER = 0x23 */
195
+ VALUE cb_eBadEnvironment; /* LCB_BAD_ENVIRONMENT = 0x24 */
196
+ VALUE cb_eBusy; /* LCB_BUSY = 0x25 */
197
+ VALUE cb_eInvalidUsername; /* LCB_INVALID_USERNAME = 0x26 */
186
198
 
187
199
  /* Default Strings */
188
200
  VALUE cb_vStrDefault;
@@ -198,6 +210,14 @@ cb_intern_string(VALUE ar, const char *str)
198
210
  return tmp;
199
211
  }
200
212
 
213
+ static VALUE
214
+ cb_libcouchbase_version(VALUE self)
215
+ {
216
+ const char *ver = lcb_get_version(NULL);
217
+ (void)self;
218
+ return STR_NEW_CSTR(ver);
219
+ }
220
+
201
221
  /* Ruby Extension initializer */
202
222
  void
203
223
  Init_couchbase_ext(void)
@@ -209,6 +229,15 @@ Init_couchbase_ext(void)
209
229
 
210
230
  cb_mURI = rb_const_get(rb_cObject, rb_intern("URI"));
211
231
  cb_mCouchbase = rb_define_module("Couchbase");
232
+ /* Document-method: libcouchbase_version
233
+ *
234
+ * @since 1.3.3
235
+ *
236
+ * Version of the libcouchbase library currently loaded
237
+ * @return [String]
238
+ */
239
+ rb_define_singleton_method(cb_mCouchbase, "libcouchbase_version", cb_libcouchbase_version, 0);
240
+
212
241
  cb_mTranscoder = rb_const_get(cb_mCouchbase, rb_intern("Transcoder"));
213
242
  cb_mDocument = rb_const_get(cb_mTranscoder, rb_intern("Document"));
214
243
  cb_mMarshal = rb_const_get(cb_mTranscoder, rb_intern("Marshal"));
@@ -436,12 +465,108 @@ Init_couchbase_ext(void)
436
465
  /* Document-class: Couchbase::Error::DlsymFailed
437
466
  * dlsym() failed
438
467
  *
439
- * Failed to locate the requested cb_symbol in the shared object
468
+ * Failed to locate the requested symbol in the shared object
440
469
  *
441
470
  * @since 1.2.0
442
471
  */
443
472
  cb_eDlsymFailedError = rb_define_class_under(cb_mError, "DlsymFailed", cb_eBaseError);
444
473
 
474
+ /* Document-class: Couchbase::Error::ServerBug
475
+ * Server Bug
476
+ *
477
+ * Unexpected usage of the server protocol, like unexpected
478
+ * response. If you've received this error code, please record your
479
+ * steps and file the issue at:
480
+ *
481
+ * http://www.couchbase.com/issues/browse/MB
482
+ *
483
+ * @since 1.3.3
484
+ */
485
+ cb_eServerBug = rb_define_class_under(cb_mError, "ServerBug", cb_eBaseError);
486
+
487
+ /* Document-class: Couchbase::Error::PluginVersionMismatch
488
+ * Plugin Version Mismatch
489
+ *
490
+ * Libcouchbase cannot load the plugin because of version mismatch
491
+ *
492
+ * @since 1.3.3
493
+ */
494
+ cb_ePluginVersionMismatch = rb_define_class_under(cb_mError, "PluginVersionMismatch", cb_eBaseError);
495
+
496
+ /* Document-class: Couchbase::Error::InvalidHostFormat
497
+ * Invalid Host Format
498
+ *
499
+ * The bootstrap hosts list use an invalid/unsupported format
500
+ *
501
+ * @since 1.3.3
502
+ */
503
+ cb_eInvalidHostFormat = rb_define_class_under(cb_mError, "InvalidHostFormat", cb_eBaseError);
504
+
505
+ /* Document-class: Couchbase::Error::InvalidChar
506
+ * Invalid Character
507
+ *
508
+ * Invalid character used in the path component of an URL
509
+ *
510
+ * @since 1.3.3
511
+ */
512
+ cb_eInvalidChar = rb_define_class_under(cb_mError, "InvalidChar", cb_eBaseError);
513
+
514
+ /* Document-class: Couchbase::Error::DurabilityTooMany
515
+ * Too Many Nodes
516
+ *
517
+ * Too many nodes were requested for the observe criteria
518
+ *
519
+ * @since 1.3.3
520
+ */
521
+ cb_eDurabilityTooMany = rb_define_class_under(cb_mError, "DurabilityTooMany", cb_eBaseError);
522
+
523
+ /* Document-class: Couchbase::Error::DuplicateCommands
524
+ * Duplicate Commands
525
+ *
526
+ * The same key was passed multiple times in a command list
527
+ *
528
+ * @since 1.3.3
529
+ */
530
+ cb_eDuplicateCommands = rb_define_class_under(cb_mError, "DuplicateCommands", cb_eBaseError);
531
+
532
+ /* Document-class: Couchbase::Error::NoMatchingServer
533
+ * No Matching Server
534
+ *
535
+ * The config says that there is no server yet at that
536
+ * position (-1 in the cluster topology map)
537
+ *
538
+ * @since 1.3.3
539
+ */
540
+ cb_eNoMatchingServer = rb_define_class_under(cb_mError, "NoMatchingServer", cb_eBaseError);
541
+
542
+ /* Document-class: Couchbase::Error::BadEnvironment
543
+ * Busy
544
+ *
545
+ * An operation has not yet completed
546
+ *
547
+ * @since 1.3.3
548
+ */
549
+ cb_eBadEnvironment = rb_define_class_under(cb_mError, "BadEnvironment", cb_eBaseError);
550
+
551
+ /* Document-class: Couchbase::Error::Busy
552
+ * Invalid Character
553
+ *
554
+ * Invalid character used in the path component of an URL
555
+ *
556
+ * @since 1.3.3
557
+ */
558
+ cb_eBusy = rb_define_class_under(cb_mError, "Busy", cb_eBaseError);
559
+
560
+ /* Document-class: Couchbase::Error::InvalidUsername
561
+ * Invalid Username
562
+ *
563
+ * Administrator account must not be used to access the data
564
+ * in the bucket
565
+ *
566
+ * @since 1.3.3
567
+ */
568
+ cb_eInvalidUsername = rb_define_class_under(cb_mError, "InvalidUsername", cb_eBaseError);
569
+
445
570
  /* Document-class: Couchbase::Error::HTTP
446
571
  * HTTP error with status code
447
572
  *
@@ -484,7 +609,10 @@ Init_couchbase_ext(void)
484
609
  * 0x1a :: LCB_CLIENT_ENOMEM (Out of memory on the client)
485
610
  * 0x1b :: LCB_CLIENT_ETMPFAIL (Temporary failure on the client)
486
611
  * 0x1c :: LCB_EBADHANDLE (Invalid handle type)
487
- *
612
+ * 0x1d :: LCB_SERVER_BUG (Server bug)
613
+ * 0x1e :: LCB_PLUGIN_VERSION_MISMATCH (Plugin version mismatch)
614
+ * 0x1f :: LCB_INVALID_HOST_FORMAT (Invalid host format)
615
+ * 0x20 :: LCB_INVALID_CHAR (Invalid character)
488
616
  *
489
617
  * @since 1.0.0
490
618
  *
@@ -1189,6 +1317,7 @@ Init_couchbase_ext(void)
1189
1317
  cb_sym_http_request = ID2SYM(rb_intern("http_request"));
1190
1318
  cb_sym_increment = ID2SYM(rb_intern("increment"));
1191
1319
  cb_sym_initial = ID2SYM(rb_intern("initial"));
1320
+ cb_sym_iocp = ID2SYM(rb_intern("iocp"));
1192
1321
  cb_sym_key_prefix = ID2SYM(rb_intern("key_prefix"));
1193
1322
  cb_sym_libev = ID2SYM(rb_intern("libev"));
1194
1323
  cb_sym_libevent = ID2SYM(rb_intern("libevent"));
@@ -1213,6 +1342,7 @@ Init_couchbase_ext(void)
1213
1342
  cb_sym_quiet = ID2SYM(rb_intern("quiet"));
1214
1343
  cb_sym_replace = ID2SYM(rb_intern("replace"));
1215
1344
  cb_sym_replica = ID2SYM(rb_intern("replica"));
1345
+ cb_sym_select = ID2SYM(rb_intern("select"));
1216
1346
  cb_sym_send_threshold = ID2SYM(rb_intern("send_threshold"));
1217
1347
  cb_sym_set = ID2SYM(rb_intern("set"));
1218
1348
  cb_sym_stats = ID2SYM(rb_intern("stats"));
@@ -22,6 +22,10 @@
22
22
  #include <st.h>
23
23
  #endif
24
24
 
25
+ #ifdef HAVE_RUBY_THREAD_H
26
+ #include <ruby/thread.h>
27
+ #endif
28
+
25
29
  #include "couchbase_config.h"
26
30
  #ifdef HAVE_RB_FIBER_YIELD
27
31
  #define BUILD_EVENTMACHINE_PLUGIN
@@ -217,6 +221,7 @@ extern ID cb_sym_hostname;
217
221
  extern ID cb_sym_http_request;
218
222
  extern ID cb_sym_increment;
219
223
  extern ID cb_sym_initial;
224
+ extern ID cb_sym_iocp;
220
225
  extern ID cb_sym_key_prefix;
221
226
  extern ID cb_sym_libev;
222
227
  extern ID cb_sym_libevent;
@@ -241,6 +246,7 @@ extern ID cb_sym_put;
241
246
  extern ID cb_sym_quiet;
242
247
  extern ID cb_sym_replace;
243
248
  extern ID cb_sym_replica;
249
+ extern ID cb_sym_select;
244
250
  extern ID cb_sym_send_threshold;
245
251
  extern ID cb_sym_set;
246
252
  extern ID cb_sym_stats;
@@ -326,6 +332,17 @@ extern VALUE cb_eBucketNotFoundError; /* LCB_BUCKET_ENOENT = 0x19 */
326
332
  extern VALUE cb_eClientNoMemoryError; /* LCB_CLIENT_ENOMEM = 0x1a */
327
333
  extern VALUE cb_eClientTmpFailError; /* LCB_CLIENT_ETMPFAIL = 0x1b */
328
334
  extern VALUE cb_eBadHandleError; /* LCB_EBADHANDLE = 0x1c */
335
+ extern VALUE cb_eServerBug; /* LCB_SERVER_BUG = 0x1d */
336
+ extern VALUE cb_ePluginVersionMismatch; /* LCB_PLUGIN_VERSION_MISMATCH = 0x1e */
337
+ extern VALUE cb_eInvalidHostFormat; /* LCB_INVALID_HOST_FORMAT = 0x1f */
338
+ extern VALUE cb_eInvalidChar; /* LCB_INVALID_CHAR = 0x20 */
339
+ extern VALUE cb_eDurabilityTooMany; /* LCB_DURABILITY_ETOOMANY = 0x21 */
340
+ extern VALUE cb_eDuplicateCommands; /* LCB_DUPLICATE_COMMANDS = 0x22 */
341
+ extern VALUE cb_eNoMatchingServer; /* LCB_NO_MATCHING_SERVER = 0x23 */
342
+ extern VALUE cb_eBadEnvironment; /* LCB_BAD_ENVIRONMENT = 0x24 */
343
+ extern VALUE cb_eBusy; /* LCB_BUSY = 0x25 */
344
+ extern VALUE cb_eInvalidUsername; /* LCB_INVALID_USERNAME = 0x26 */
345
+
329
346
 
330
347
  /* Default Strings */
331
348
  extern VALUE cb_vStrDefault;
@@ -128,14 +128,14 @@ end
128
128
 
129
129
  unless try_compile(<<-SRC)
130
130
  #include <libcouchbase/couchbase.h>
131
+ #include <stdio.h>
131
132
 
132
133
  int main() {
133
- lcb_get_replica_cmd_t cmd;
134
- cmd.v.v1.strategy = 42;
134
+ printf("User not found: %d\\n", LCB_INVALID_USERNAME);
135
135
  return 0;
136
136
  }
137
137
  SRC
138
- die("You must install libcouchbase >= 2.0.7\nSee http://www.couchbase.com/communities/c/ for more details")
138
+ die("You must install libcouchbase >= 2.1.3\nSee http://www.couchbase.com/communities/c/ for more details")
139
139
  end
140
140
 
141
141
  have_library("couchbase", "lcb_verify_compiler_setup", "libcouchbase/couchbase.h") # just to add -lcouchbase properly
@@ -151,6 +151,7 @@ have_func("gethrtime")
151
151
  have_func("rb_hash_lookup2")
152
152
  have_func("rb_thread_fd_select")
153
153
  have_func("rb_thread_blocking_region")
154
+ have_func("rb_thread_call_without_gvl")
154
155
  have_func("poll", "poll.h")
155
156
  have_func("ppoll", "poll.h")
156
157
  have_func("rb_fiber_yield")
@@ -36,19 +36,23 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
36
36
  }
37
37
  }
38
38
 
39
- flags = ULONG2NUM(resp->v.v0.flags);
40
- cas = ULL2NUM(resp->v.v0.cas);
41
- raw = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
42
- val = cb_decode_value(ctx->transcoder, raw, resp->v.v0.flags, ctx->transcoder_opts);
43
- if (rb_obj_is_kind_of(val, rb_eStandardError)) {
44
- VALUE exc_str = rb_funcall(val, cb_id_to_s, 0);
45
- VALUE msg = rb_funcall(rb_mKernel, cb_id_sprintf, 3,
46
- rb_str_new2("unable to convert value for key \"%s\": %s"), key, exc_str);
47
- ctx->exception = rb_exc_new3(cb_eValueFormatError, msg);
48
- rb_ivar_set(ctx->exception, cb_id_iv_operation, cb_sym_get);
49
- rb_ivar_set(ctx->exception, cb_id_iv_key, key);
50
- rb_ivar_set(ctx->exception, cb_id_iv_inner_exception, val);
51
- val = Qnil;
39
+ if (error == LCB_SUCCESS) {
40
+ flags = ULONG2NUM(resp->v.v0.flags);
41
+ cas = ULL2NUM(resp->v.v0.cas);
42
+ raw = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
43
+ val = cb_decode_value(ctx->transcoder, raw, resp->v.v0.flags, ctx->transcoder_opts);
44
+ if (rb_obj_is_kind_of(val, rb_eStandardError)) {
45
+ VALUE exc_str = rb_funcall(val, cb_id_to_s, 0);
46
+ VALUE msg = rb_funcall(rb_mKernel, cb_id_sprintf, 3,
47
+ rb_str_new2("unable to convert value for key \"%s\": %s"), key, exc_str);
48
+ ctx->exception = rb_exc_new3(cb_eValueFormatError, msg);
49
+ rb_ivar_set(ctx->exception, cb_id_iv_operation, cb_sym_get);
50
+ rb_ivar_set(ctx->exception, cb_id_iv_key, key);
51
+ rb_ivar_set(ctx->exception, cb_id_iv_inner_exception, val);
52
+ val = Qnil;
53
+ }
54
+ } else {
55
+ val = flags = cas = Qnil;
52
56
  }
53
57
  if (bucket->async) { /* asynchronous */
54
58
  if (ctx->proc != Qnil) {
@@ -291,11 +295,14 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
291
295
  return rv; /* return as a hash {key => [value, flags, cas], ...} */
292
296
  }
293
297
  if (params.cmd.get.num > 1 || params.cmd.get.array) {
294
- VALUE *keys_ptr, ret;
298
+ VALUE keys, ret;
295
299
  ret = rb_ary_new();
296
- keys_ptr = RARRAY_PTR(params.cmd.get.keys_ary);
300
+ /* make sure ret is guarded so not invisible in a register
301
+ * when stack scanning */
302
+ RB_GC_GUARD(ret);
303
+ keys = params.cmd.get.keys_ary;
297
304
  for (ii = 0; ii < params.cmd.get.num; ++ii) {
298
- rb_ary_push(ret, rb_hash_aref(rv, keys_ptr[ii]));
305
+ rb_ary_push(ret, rb_hash_aref(rv, rb_ary_entry(keys, ii)));
299
306
  }
300
307
  return ret; /* return as an array [value1, value2, ...] */
301
308
  } else {
@@ -433,6 +433,7 @@ callbacks_push(rb_mt_callbacks *callbacks, rb_mt_event *event)
433
433
  callbacks->capa = new_capa;
434
434
  callbacks->events = new_events;
435
435
  }
436
+ event->loop_index = callbacks->count;
436
437
  callbacks->events[callbacks->count] = event;
437
438
  callbacks->count++;
438
439
  }
@@ -457,6 +458,8 @@ callbacks_run(rb_mt_callbacks *callbacks)
457
458
  for(i = 0; i < callbacks->count; i++) {
458
459
  rb_mt_event *cb = callbacks->events[i];
459
460
  if (cb) {
461
+ cb->loop_index = -1;
462
+ callbacks->events[i] = NULL;
460
463
  cb->handler(cb->socket, cb->actual_flags, cb->cb_data);
461
464
  }
462
465
  }
@@ -725,7 +728,7 @@ lp_arg_alloc(lp_arg **args)
725
728
  return Data_Make_Struct(rb_cObject, lp_arg, 0, lp_arg_free, *args);
726
729
  }
727
730
 
728
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
731
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
729
732
  static VALUE
730
733
  loop_blocking_poll(void *argp)
731
734
  {
@@ -768,7 +771,10 @@ retry:
768
771
  args->ts = HRTIME_INFINITY;
769
772
  }
770
773
 
771
- #ifdef HAVE_RB_THREAD_BLOCKING_REGION
774
+
775
+ #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
776
+ rb_thread_call_without_gvl((void *(*)(void*))loop_blocking_poll, args, RUBY_UBF_IO, 0);
777
+ #elif defined(HAVE_RB_THREAD_BLOCKING_REGION)
772
778
  rb_thread_blocking_region(loop_blocking_poll, args, RUBY_UBF_PROCESS, NULL);
773
779
  #else
774
780
  if (rb_thread_alone()) {
@@ -235,6 +235,36 @@ cb_check_error_with_status(lcb_error_t rc, const char *msg, VALUE key,
235
235
  case LCB_EBADHANDLE:
236
236
  klass = cb_eBadHandleError;
237
237
  break;
238
+ case LCB_SERVER_BUG:
239
+ klass = cb_eServerBug;
240
+ break;
241
+ case LCB_PLUGIN_VERSION_MISMATCH:
242
+ klass = cb_ePluginVersionMismatch;
243
+ break;
244
+ case LCB_INVALID_HOST_FORMAT:
245
+ klass = cb_eInvalidHostFormat;
246
+ break;
247
+ case LCB_INVALID_CHAR:
248
+ klass = cb_eInvalidChar;
249
+ break;
250
+ case LCB_DURABILITY_ETOOMANY:
251
+ klass = cb_eDurabilityTooMany;
252
+ break;
253
+ case LCB_DUPLICATE_COMMANDS:
254
+ klass = cb_eDuplicateCommands;
255
+ break;
256
+ case LCB_NO_MATCHING_SERVER:
257
+ klass = cb_eBadEnvironment;
258
+ break;
259
+ case LCB_BAD_ENVIRONMENT:
260
+ klass = cb_eBadEnvironment;
261
+ break;
262
+ case LCB_BUSY:
263
+ klass = cb_eBusyError;
264
+ break;
265
+ case LCB_INVALID_USERNAME:
266
+ klass = cb_eInvalidUsername;
267
+ break;
238
268
  case LCB_ERROR:
239
269
  /* fall through */
240
270
  default:
@@ -375,8 +405,8 @@ do_encode(VALUE *args)
375
405
  if (RARRAY_LEN(ret) != 2) {
376
406
  rb_raise(rb_eArgError, "#dump method of transcoder should return two items");
377
407
  }
378
- *flags = NUM2ULONG(RARRAY_PTR(ret)[1]);
379
- return RARRAY_PTR(ret)[0];
408
+ *flags = NUM2ULONG(rb_ary_entry(ret, 1));
409
+ return rb_ary_entry(ret, 0);
380
410
  }
381
411
 
382
412
  static VALUE
@@ -77,7 +77,7 @@ module Couchbase
77
77
 
78
78
  # @private the thread local storage
79
79
  def thread_storage
80
- Thread.current[:couchbase] ||= { :pid => Process.pid }
80
+ Thread.current[:couchbase] ||= { :pid => Process.pid, :bucket => {} }
81
81
  end
82
82
 
83
83
  # @private resets thread local storage if process ids don't match
@@ -100,10 +100,42 @@ module Couchbase
100
100
  # @example
101
101
  # Couchbase.bucket.set("foo", "bar")
102
102
  #
103
+ # @example Set connection options using Hash
104
+ # Couchbase.connection_options = {:node_list => ["example.com:8091"]}
105
+ # Couchbase.bucket("slot1").set("foo", "bar")
106
+ # Couchbase.bucket("slot1").bucket #=> "default"
107
+ # Couchbase.connection_options[:bucket] = "test"
108
+ # Couchbase.bucket("slot2").bucket #=> "test"
109
+ #
110
+ # @example Set connection options using URI
111
+ # Couchbase.connection_options = "http://example.com:8091/pools"
112
+ # Couchbase.bucket("slot1").set("foo", "bar")
113
+ # Couchbase.bucket("slot1").bucket #=> "default"
114
+ # Couchbase.connection_options = "http://example.com:8091/pools/buckets/test"
115
+ # Couchbase.bucket("slot2").bucket #=> "test"
116
+ #
117
+ # @example Use named slots to keep a connection
118
+ # Couchbase.connection_options = {
119
+ # :node_list => ["example.com", "example.org"],
120
+ # :bucket => "users"
121
+ # }
122
+ # Couchbase.bucket("users").set("john", {"balance" => 0})
123
+ # Couchbase.connection_options[:bucket] = "orders"
124
+ # Couchbase.bucket("other").set("john:1", {"products" => [42, 66]})
125
+ #
103
126
  # @return [Bucket]
104
- def bucket
127
+ def bucket(name = nil)
105
128
  verify_connection!
106
- thread_storage[:bucket] ||= connect(connection_options)
129
+ name ||= case @connection_options
130
+ when Hash
131
+ @connection_options[:bucket]
132
+ when String
133
+ path = URI.parse(@connection_options).path
134
+ path[%r(^(/pools/([A-Za-z0-9_.-]+)(/buckets/([A-Za-z0-9_.-]+))?)?), 3] || "default"
135
+ else
136
+ "default"
137
+ end
138
+ thread_storage[:bucket][name] ||= connect(connection_options)
107
139
  end
108
140
 
109
141
  # Set a connection instance for current thread
@@ -111,10 +143,12 @@ module Couchbase
111
143
  # @since 1.1.0
112
144
  #
113
145
  # @return [Bucket]
114
- def bucket=(connection)
146
+ def bucket=(connection, name = nil)
115
147
  verify_connection!
116
- thread_storage[:bucket] = connection
148
+ name ||= @connection_options && @connection_options[:bucket] || "default"
149
+ thread_storage[:bucket][name] = connection
117
150
  end
151
+ alias set_bucket bucket=
118
152
 
119
153
  end
120
154
 
@@ -17,5 +17,5 @@
17
17
 
18
18
  # Couchbase ruby client
19
19
  module Couchbase
20
- VERSION = "1.3.2"
20
+ VERSION = "1.3.3"
21
21
  end
@@ -22,6 +22,14 @@ def gemspec
22
22
  @clean_gemspec ||= eval(File.read(File.expand_path('../../couchbase.gemspec', __FILE__)))
23
23
  end
24
24
 
25
+ version_router = lambda do |t|
26
+ File.open(t.name, 'wb') do |f|
27
+ f.write <<-RUBY
28
+ require "couchbase/\#{RUBY_VERSION.sub(/\\.\\d+$/, '')}/couchbase_ext"
29
+ RUBY
30
+ end
31
+ end
32
+
25
33
  # Setup compile tasks. Configuration can be passed via ENV.
26
34
  # Example:
27
35
  # rake compile with_libcouchbase_include=/opt/couchbase/include
@@ -33,13 +41,14 @@ end
33
41
  #
34
42
  Rake::ExtensionTask.new("couchbase_ext", gemspec) do |ext|
35
43
  ext.cross_compile = true
36
- ext.cross_platform = [ENV['HOST'] || "i386-mingw32"]
44
+ ext.cross_platform = ENV['HOST'] || "i386-mingw32"
37
45
  if ENV['RUBY_CC_VERSION']
38
46
  ext.lib_dir = "lib/couchbase"
39
47
  end
40
48
  ext.cross_compiling do |spec|
41
49
  spec.files.delete("lib/couchbase/couchbase_ext.so")
42
50
  spec.files.push("lib/couchbase_ext.rb", Dir["lib/couchbase/1.{8,9}/couchbase_ext.so"])
51
+ file "#{ext.tmp_dir}/#{ext.cross_platform}/stage/lib/couchbase_ext.rb", &version_router
43
52
  end
44
53
 
45
54
  CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
@@ -84,12 +93,14 @@ namespace :ports do
84
93
  directory "ports"
85
94
 
86
95
  task :libcouchbase => ["ports"] do
87
- recipe = MiniPortile.new "libcouchbase", "2.0.7"
96
+ recipe = MiniPortile.new "libcouchbase", "2.1.3"
88
97
  recipe.files << "http://packages.couchbase.com/clients/c/libcouchbase-#{recipe.version}.tar.gz"
98
+
89
99
  recipe.configure_options.push("--disable-debug",
90
100
  "--disable-dependency-tracking",
91
101
  "--disable-couchbasemock",
92
102
  "--disable-cxx",
103
+ "--disable-plugins",
93
104
  "--disable-examples",
94
105
  "--disable-tools")
95
106
  recipe.cook
@@ -97,19 +108,13 @@ namespace :ports do
97
108
  end
98
109
  end
99
110
 
100
- file "lib/couchbase_ext.rb" do
101
- File.open("lib/couchbase_ext.rb", 'wb') do |f|
102
- f.write <<-RUBY
103
- require "couchbase/\#{RUBY_VERSION.sub(/\\.\\d+$/, '')}/couchbase_ext"
104
- RUBY
105
- end
106
- end
107
-
111
+ file "lib/couchbase_ext.rb", &version_router
108
112
  task :cross => ["lib/couchbase_ext.rb", "ports:libcouchbase"]
109
113
 
110
114
  desc "Package gem for windows"
111
115
  task "package:windows" => :package do
112
116
  sh("env RUBY_CC_VERSION=1.8.7 RBENV_VERSION=1.8.7-p370 rbenv exec bundle exec rake cross compile")
113
117
  sh("env RUBY_CC_VERSION=1.9.2 RBENV_VERSION=1.9.2-p320 rbenv exec bundle exec rake cross compile")
114
- sh("env RUBY_CC_VERSION=1.8.7:1.9.2 RBENV_VERSION=1.9.2-p320 rbenv exec bundle exec rake cross native gem")
118
+ sh("env RUBY_CC_VERSION=2.0.0 RBENV_VERSION=2.0.0-p247 rbenv exec bundle exec rake cross compile")
119
+ sh("env RUBY_CC_VERSION=1.8.7:1.9.2:2.0.0 RBENV_VERSION=1.9.2-p320 rbenv exec bundle exec rake cross native gem")
115
120
  end
@@ -119,6 +119,12 @@ class TestBucket < MiniTest::Test
119
119
  def test_it_raises_error_with_wrong_credentials
120
120
  with_mock do |mock|
121
121
  assert_raises Couchbase::Error::Auth do
122
+ Couchbase.new(:hostname => mock.host,
123
+ :port => mock.port,
124
+ :bucket => 'default',
125
+ :password => 'wrong_password')
126
+ end
127
+ assert_raises Couchbase::Error::InvalidUsername do
122
128
  Couchbase.new(:hostname => mock.host,
123
129
  :port => mock.port,
124
130
  :bucket => 'default',
@@ -130,7 +136,7 @@ class TestBucket < MiniTest::Test
130
136
 
131
137
  def test_it_unable_to_connect_to_protected_buckets_with_wrong_credentials
132
138
  with_mock(:buckets_spec => 'protected:secret') do |mock|
133
- assert_raises Couchbase::Error::Auth do
139
+ assert_raises Couchbase::Error::InvalidUsername do
134
140
  Couchbase.new(:hostname => mock.host,
135
141
  :port => mock.port,
136
142
  :bucket => 'protected',
@@ -234,4 +240,11 @@ class TestBucket < MiniTest::Test
234
240
  end
235
241
  end
236
242
 
243
+ def test_it_doesnt_try_to_destroy_handle_in_case_of_lcb_create_failure
244
+ assert_raises(Couchbase::Error::InvalidHostFormat) do
245
+ Couchbase.connect(:hostname => "foobar:baz")
246
+ end
247
+ GC.start # make sure it won't touch handle in finalizer
248
+ end
249
+
237
250
  end
metadata CHANGED
@@ -1,13 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchbase
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
- prerelease:
6
- segments:
7
- - 1
8
- - 3
9
- - 2
10
- version: 1.3.2
4
+ version: 1.3.3
11
5
  platform: ruby
12
6
  authors:
13
7
  - Couchbase
@@ -15,160 +9,103 @@ autorequire:
15
9
  bindir: bin
16
10
  cert_chain: []
17
11
 
18
- date: 2013-07-10 00:00:00 +03:00
19
- default_executable:
12
+ date: 2013-09-13 00:00:00 Z
20
13
  dependencies:
21
14
  - !ruby/object:Gem::Dependency
15
+ prerelease: false
22
16
  type: :runtime
17
+ name: yaji
23
18
  requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
19
  requirements:
26
20
  - - ~>
27
21
  - !ruby/object:Gem::Version
28
- hash: 23
29
- segments:
30
- - 0
31
- - 3
32
- - 2
33
22
  version: 0.3.2
34
- name: yaji
35
23
  version_requirements: *id001
36
- prerelease: false
37
24
  - !ruby/object:Gem::Dependency
25
+ prerelease: false
38
26
  type: :runtime
27
+ name: multi_json
39
28
  requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
29
  requirements:
42
30
  - - ~>
43
31
  - !ruby/object:Gem::Version
44
- hash: 15
45
- segments:
46
- - 1
47
- - 0
48
32
  version: "1.0"
49
- name: multi_json
50
33
  version_requirements: *id002
51
- prerelease: false
52
34
  - !ruby/object:Gem::Dependency
35
+ prerelease: false
53
36
  type: :runtime
37
+ name: connection_pool
54
38
  requirement: &id003 !ruby/object:Gem::Requirement
55
- none: false
56
39
  requirements:
57
40
  - - ~>
58
41
  - !ruby/object:Gem::Version
59
- hash: 23
60
- segments:
61
- - 1
62
- - 0
63
- - 0
64
42
  version: 1.0.0
65
- name: connection_pool
66
43
  version_requirements: *id003
67
- prerelease: false
68
44
  - !ruby/object:Gem::Dependency
45
+ prerelease: false
69
46
  type: :development
47
+ name: rake
70
48
  requirement: &id004 !ruby/object:Gem::Requirement
71
- none: false
72
49
  requirements:
73
- - - ">="
50
+ - &id007
51
+ - ">="
74
52
  - !ruby/object:Gem::Version
75
- hash: 3
76
- segments:
77
- - 0
78
53
  version: "0"
79
- name: rake
80
54
  version_requirements: *id004
81
- prerelease: false
82
55
  - !ruby/object:Gem::Dependency
56
+ prerelease: false
83
57
  type: :development
58
+ name: minitest
84
59
  requirement: &id005 !ruby/object:Gem::Requirement
85
- none: false
86
60
  requirements:
87
61
  - - ~>
88
62
  - !ruby/object:Gem::Version
89
- hash: 63
90
- segments:
91
- - 5
92
- - 0
93
- - 4
94
63
  version: 5.0.4
95
- name: minitest
96
64
  version_requirements: *id005
97
- prerelease: false
98
65
  - !ruby/object:Gem::Dependency
66
+ prerelease: false
99
67
  type: :development
68
+ name: rake-compiler
100
69
  requirement: &id006 !ruby/object:Gem::Requirement
101
- none: false
102
70
  requirements:
103
71
  - - ">="
104
72
  - !ruby/object:Gem::Version
105
- hash: 9
106
- segments:
107
- - 0
108
- - 7
109
- - 5
110
73
  version: 0.7.5
111
- name: rake-compiler
112
74
  version_requirements: *id006
113
- prerelease: false
114
75
  - !ruby/object:Gem::Dependency
115
- type: :development
116
- requirement: &id007 !ruby/object:Gem::Requirement
117
- none: false
118
- requirements:
119
- - - ">="
120
- - !ruby/object:Gem::Version
121
- hash: 3
122
- segments:
123
- - 0
124
- version: "0"
125
- name: mini_portile
126
- version_requirements: *id007
127
76
  prerelease: false
128
- - !ruby/object:Gem::Dependency
129
77
  type: :development
78
+ name: mini_portile
130
79
  requirement: &id008 !ruby/object:Gem::Requirement
131
- none: false
132
80
  requirements:
133
- - - ~>
134
- - !ruby/object:Gem::Version
135
- hash: 19
136
- segments:
137
- - 1
138
- - 1
139
- - 0
140
- version: 1.1.0
141
- name: yajl-ruby
81
+ - *id007
142
82
  version_requirements: *id008
143
- prerelease: false
144
83
  - !ruby/object:Gem::Dependency
84
+ prerelease: false
145
85
  type: :development
86
+ name: yajl-ruby
146
87
  requirement: &id009 !ruby/object:Gem::Requirement
147
- none: false
148
88
  requirements:
149
- - - ">="
89
+ - - ~>
150
90
  - !ruby/object:Gem::Version
151
- hash: 3
152
- segments:
153
- - 0
154
- version: "0"
155
- name: active_support
91
+ version: 1.1.0
156
92
  version_requirements: *id009
157
- prerelease: false
158
93
  - !ruby/object:Gem::Dependency
94
+ prerelease: false
159
95
  type: :development
96
+ name: active_support
160
97
  requirement: &id010 !ruby/object:Gem::Requirement
161
- none: false
162
98
  requirements:
163
- - - ">="
164
- - !ruby/object:Gem::Version
165
- hash: 3
166
- segments:
167
- - 0
168
- version: "0"
169
- name: eventmachine
99
+ - *id007
170
100
  version_requirements: *id010
101
+ - !ruby/object:Gem::Dependency
171
102
  prerelease: false
103
+ type: :development
104
+ name: eventmachine
105
+ requirement: &id011 !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - *id007
108
+ version_requirements: *id011
172
109
  description: The official client library for use with Couchbase Server.
173
110
  email: support@couchbase.com
174
111
  executables: []
@@ -268,39 +205,50 @@ files:
268
205
  - test/test_unlock.rb
269
206
  - test/test_utils.rb
270
207
  - test/test_version.rb
271
- has_rdoc: true
272
208
  homepage: http://couchbase.org
273
209
  licenses:
274
210
  - ASL-2
211
+ metadata: {}
212
+
275
213
  post_install_message:
276
214
  rdoc_options: []
277
215
 
278
216
  require_paths:
279
217
  - lib
280
218
  required_ruby_version: !ruby/object:Gem::Requirement
281
- none: false
282
219
  requirements:
283
- - - ">="
284
- - !ruby/object:Gem::Version
285
- hash: 3
286
- segments:
287
- - 0
288
- version: "0"
220
+ - *id007
289
221
  required_rubygems_version: !ruby/object:Gem::Requirement
290
- none: false
291
222
  requirements:
292
- - - ">="
293
- - !ruby/object:Gem::Version
294
- hash: 3
295
- segments:
296
- - 0
297
- version: "0"
223
+ - *id007
298
224
  requirements: []
299
225
 
300
226
  rubyforge_project:
301
- rubygems_version: 1.6.2
227
+ rubygems_version: 2.1.3
302
228
  signing_key:
303
- specification_version: 3
229
+ specification_version: 4
304
230
  summary: Couchbase ruby driver
305
- test_files: []
306
-
231
+ test_files:
232
+ - test/profile/.gitignore
233
+ - test/profile/Gemfile
234
+ - test/profile/benchmark.rb
235
+ - test/setup.rb
236
+ - test/test_arithmetic.rb
237
+ - test/test_async.rb
238
+ - test/test_bucket.rb
239
+ - test/test_cas.rb
240
+ - test/test_couchbase.rb
241
+ - test/test_couchbase_connection_pool.rb
242
+ - test/test_couchbase_rails_cache_store.rb
243
+ - test/test_delete.rb
244
+ - test/test_errors.rb
245
+ - test/test_eventmachine.rb
246
+ - test/test_format.rb
247
+ - test/test_get.rb
248
+ - test/test_stats.rb
249
+ - test/test_store.rb
250
+ - test/test_timer.rb
251
+ - test/test_touch.rb
252
+ - test/test_unlock.rb
253
+ - test/test_utils.rb
254
+ - test/test_version.rb