couchbase 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.markdown CHANGED
@@ -1,3 +1,11 @@
1
+ ## 1.1.3 / 2012-07-27
2
+
3
+ * RCBC-59 Replicate flags in Bucket#cas operation
4
+ * calloc -> xcalloc, free -> xfree
5
+ * RCBC-64 Fix Couchbase::Bucket#dup
6
+ * Make object_space GC protector per-bucket object
7
+ * RCBC-60 Protect exceptions from GC
8
+
1
9
  ## 1.1.2 / 2012-06-05
2
10
 
3
11
  * Upgrade libcouchbase dependency up to 1.0.4
@@ -64,6 +64,7 @@ typedef struct
64
64
  uint32_t timeout;
65
65
  VALUE exception; /* error delivered by error_callback */
66
66
  VALUE on_error_proc; /* is using to deliver errors in async mode */
67
+ VALUE object_space;
67
68
  } bucket_t;
68
69
 
69
70
  typedef struct
@@ -93,7 +94,6 @@ struct key_traits
93
94
  };
94
95
 
95
96
  static VALUE mCouchbase, mError, mJSON, mURI, mMarshal, cBucket, cResult;
96
- static VALUE object_space;
97
97
 
98
98
  static ID sym_add,
99
99
  sym_append,
@@ -142,6 +142,7 @@ static ID sym_add,
142
142
  id_iv_node,
143
143
  id_iv_operation,
144
144
  id_iv_value,
145
+ id_dup,
145
146
  id_load,
146
147
  id_match,
147
148
  id_parse,
@@ -183,6 +184,18 @@ static VALUE eTimeoutError; /*LIBCOUCHBASE_ETIMEDOUT = 0x16*/
183
184
  static VALUE eConnectError; /*LIBCOUCHBASE_CONNECT_ERROR = 0x17*/
184
185
  static VALUE eBucketNotFoundError; /*LIBCOUCHBASE_BUCKET_ENOENT = 0x18*/
185
186
 
187
+ static void
188
+ cb_gc_protect(bucket_t *bucket, VALUE val)
189
+ {
190
+ rb_hash_aset(bucket->object_space, val|1, val);
191
+ }
192
+
193
+ static void
194
+ cb_gc_unprotect(bucket_t *bucket, VALUE val)
195
+ {
196
+ rb_hash_delete(bucket->object_space, val|1);
197
+ }
198
+
186
199
  static VALUE
187
200
  cb_proc_call(VALUE recv, int argc, ...)
188
201
  {
@@ -504,18 +517,18 @@ cb_args_scan_keys(long argc, VALUE argv, bucket_t *bucket, struct key_traits *tr
504
517
  if (nn == 1 && TYPE(keys_ptr[0]) == T_HASH) {
505
518
  /* hash of key-ttl pairs */
506
519
  nn = RHASH_SIZE(keys_ptr[0]);
507
- traits->keys = calloc(nn, sizeof(char *));
508
- traits->lens = calloc(nn, sizeof(size_t));
520
+ traits->keys = xcalloc(nn, sizeof(char *));
521
+ traits->lens = xcalloc(nn, sizeof(size_t));
509
522
  traits->explicit_ttl = 1;
510
523
  traits->mgat = 1;
511
- traits->ttls = calloc(nn, sizeof(time_t));
524
+ traits->ttls = xcalloc(nn, sizeof(time_t));
512
525
  rb_hash_foreach(keys_ptr[0], cb_extract_keys_i, (VALUE)traits);
513
526
  } else {
514
527
  /* the list of keys */
515
528
  traits->nkeys = nn;
516
- traits->keys = calloc(nn, sizeof(char *));
517
- traits->lens = calloc(nn, sizeof(size_t));
518
- traits->ttls = calloc(nn, sizeof(time_t));
529
+ traits->keys = xcalloc(nn, sizeof(char *));
530
+ traits->lens = xcalloc(nn, sizeof(size_t));
531
+ traits->ttls = xcalloc(nn, sizeof(time_t));
519
532
  for (ii = 0; ii < nn; ii++) {
520
533
  key = unify_key(keys_ptr[ii]);
521
534
  rb_ary_push(traits->keys_ary, key);
@@ -577,6 +590,7 @@ storage_callback(libcouchbase_t handle, const void *cookie,
577
590
  rb_ivar_set(exc, id_iv_operation, o);
578
591
  if (NIL_P(ctx->exception)) {
579
592
  ctx->exception = exc;
593
+ cb_gc_protect(bucket, ctx->exception);
580
594
  }
581
595
  }
582
596
  if (bucket->async) { /* asynchronous */
@@ -594,7 +608,7 @@ storage_callback(libcouchbase_t handle, const void *cookie,
594
608
 
595
609
  if (bucket->seqno == 0) {
596
610
  bucket->io->stop_event_loop(bucket->io);
597
- rb_hash_delete(object_space, ctx->proc|1);
611
+ cb_gc_unprotect(bucket, ctx->proc);
598
612
  }
599
613
  (void)handle;
600
614
  }
@@ -617,6 +631,7 @@ delete_callback(libcouchbase_t handle, const void *cookie,
617
631
  rb_ivar_set(exc, id_iv_operation, sym_delete);
618
632
  if (NIL_P(ctx->exception)) {
619
633
  ctx->exception = exc;
634
+ cb_gc_protect(bucket, ctx->exception);
620
635
  }
621
636
  }
622
637
  }
@@ -633,7 +648,7 @@ delete_callback(libcouchbase_t handle, const void *cookie,
633
648
  }
634
649
  if (bucket->seqno == 0) {
635
650
  bucket->io->stop_event_loop(bucket->io);
636
- rb_hash_delete(object_space, ctx->proc|1);
651
+ cb_gc_unprotect(bucket, ctx->proc);
637
652
  }
638
653
  (void)handle;
639
654
  }
@@ -658,26 +673,27 @@ get_callback(libcouchbase_t handle, const void *cookie,
658
673
  rb_ivar_set(exc, id_iv_operation, sym_get);
659
674
  if (NIL_P(ctx->exception)) {
660
675
  ctx->exception = exc;
676
+ cb_gc_protect(bucket, ctx->exception);
661
677
  }
662
678
  }
663
679
  }
664
680
 
665
681
  f = ULONG2NUM(flags);
666
682
  c = ULL2NUM(cas);
683
+ v = Qnil;
667
684
  if (nbytes != 0) {
668
685
  v = decode_value(rb_str_new((const char*)bytes, nbytes), flags, ctx->force_format);
669
686
  if (v == Qundef) {
687
+ if (ctx->exception != Qnil) {
688
+ cb_gc_unprotect(bucket, ctx->exception);
689
+ }
670
690
  ctx->exception = rb_exc_new2(eValueFormatError, "unable to convert value");
671
691
  rb_ivar_set(ctx->exception, id_iv_operation, sym_get);
672
692
  rb_ivar_set(ctx->exception, id_iv_key, k);
673
- v = Qnil;
674
- }
675
- } else {
676
- if (flags_get_format(flags) == sym_plain) {
677
- v = rb_str_new2("");
678
- } else {
679
- v = Qnil;
693
+ cb_gc_protect(bucket, ctx->exception);
680
694
  }
695
+ } else if (flags_get_format(flags) == sym_plain) {
696
+ v = rb_str_new2("");
681
697
  }
682
698
  if (bucket->async) { /* asynchronous */
683
699
  if (ctx->proc != Qnil) {
@@ -702,7 +718,7 @@ get_callback(libcouchbase_t handle, const void *cookie,
702
718
 
703
719
  if (bucket->seqno == 0) {
704
720
  bucket->io->stop_event_loop(bucket->io);
705
- rb_hash_delete(object_space, ctx->proc|1);
721
+ cb_gc_unprotect(bucket, ctx->proc);
706
722
  }
707
723
  (void)handle;
708
724
  }
@@ -721,6 +737,7 @@ flush_callback(libcouchbase_t handle, const void* cookie,
721
737
  rb_ivar_set(exc, id_iv_operation, sym_flush);
722
738
  if (NIL_P(ctx->exception)) {
723
739
  ctx->exception = exc;
740
+ cb_gc_protect(bucket, ctx->exception);
724
741
  }
725
742
  success = Qfalse;
726
743
  }
@@ -744,7 +761,7 @@ flush_callback(libcouchbase_t handle, const void* cookie,
744
761
  bucket->seqno--;
745
762
  if (bucket->seqno == 0) {
746
763
  bucket->io->stop_event_loop(bucket->io);
747
- rb_hash_delete(object_space, ctx->proc|1);
764
+ cb_gc_unprotect(bucket, ctx->proc);
748
765
  }
749
766
  }
750
767
 
@@ -766,6 +783,7 @@ version_callback(libcouchbase_t handle, const void *cookie,
766
783
  rb_ivar_set(exc, id_iv_operation, sym_flush);
767
784
  if (NIL_P(ctx->exception)) {
768
785
  ctx->exception = exc;
786
+ cb_gc_protect(bucket, ctx->exception);
769
787
  }
770
788
  }
771
789
 
@@ -789,7 +807,7 @@ version_callback(libcouchbase_t handle, const void *cookie,
789
807
  bucket->seqno--;
790
808
  if (bucket->seqno == 0) {
791
809
  bucket->io->stop_event_loop(bucket->io);
792
- rb_hash_delete(object_space, ctx->proc|1);
810
+ cb_gc_unprotect(bucket, ctx->proc);
793
811
  }
794
812
  }
795
813
 
@@ -812,6 +830,7 @@ stat_callback(libcouchbase_t handle, const void* cookie,
812
830
  rb_ivar_set(exc, id_iv_operation, sym_stats);
813
831
  if (NIL_P(ctx->exception)) {
814
832
  ctx->exception = exc;
833
+ cb_gc_protect(bucket, ctx->exception);
815
834
  }
816
835
  }
817
836
  if (authority) {
@@ -841,7 +860,7 @@ stat_callback(libcouchbase_t handle, const void* cookie,
841
860
  bucket->seqno--;
842
861
  if (bucket->seqno == 0) {
843
862
  bucket->io->stop_event_loop(bucket->io);
844
- rb_hash_delete(object_space, ctx->proc|1);
863
+ cb_gc_unprotect(bucket, ctx->proc);
845
864
  }
846
865
  }
847
866
  (void)handle;
@@ -864,6 +883,7 @@ touch_callback(libcouchbase_t handle, const void *cookie,
864
883
  rb_ivar_set(exc, id_iv_operation, sym_touch);
865
884
  if (NIL_P(ctx->exception)) {
866
885
  ctx->exception = exc;
886
+ cb_gc_protect(bucket, ctx->exception);
867
887
  }
868
888
  }
869
889
  }
@@ -884,7 +904,7 @@ touch_callback(libcouchbase_t handle, const void *cookie,
884
904
  }
885
905
  if (bucket->seqno == 0) {
886
906
  bucket->io->stop_event_loop(bucket->io);
887
- rb_hash_delete(object_space, ctx->proc|1);
907
+ cb_gc_unprotect(bucket, ctx->proc);
888
908
  }
889
909
  (void)handle;
890
910
  }
@@ -920,6 +940,7 @@ arithmetic_callback(libcouchbase_t handle, const void *cookie,
920
940
  }
921
941
  if (NIL_P(ctx->exception)) {
922
942
  ctx->exception = exc;
943
+ cb_gc_protect(bucket, ctx->exception);
923
944
  }
924
945
  }
925
946
  v = ULL2NUM(value);
@@ -944,7 +965,7 @@ arithmetic_callback(libcouchbase_t handle, const void *cookie,
944
965
  }
945
966
  if (bucket->seqno == 0) {
946
967
  bucket->io->stop_event_loop(bucket->io);
947
- rb_hash_delete(object_space, ctx->proc|1);
968
+ cb_gc_unprotect(bucket, ctx->proc);
948
969
  }
949
970
  (void)handle;
950
971
  }
@@ -980,13 +1001,13 @@ cb_bucket_free(void *ptr)
980
1001
  if (bucket->handle) {
981
1002
  libcouchbase_destroy(bucket->handle);
982
1003
  }
983
- free(bucket->authority);
984
- free(bucket->hostname);
985
- free(bucket->pool);
986
- free(bucket->bucket);
987
- free(bucket->username);
988
- free(bucket->password);
989
- free(bucket);
1004
+ xfree(bucket->authority);
1005
+ xfree(bucket->hostname);
1006
+ xfree(bucket->pool);
1007
+ xfree(bucket->bucket);
1008
+ xfree(bucket->username);
1009
+ xfree(bucket->password);
1010
+ xfree(bucket);
990
1011
  }
991
1012
  }
992
1013
 
@@ -998,6 +1019,7 @@ cb_bucket_mark(void *ptr)
998
1019
  if (bucket) {
999
1020
  rb_gc_mark(bucket->exception);
1000
1021
  rb_gc_mark(bucket->on_error_proc);
1022
+ rb_gc_mark(bucket->object_space);
1001
1023
  }
1002
1024
  }
1003
1025
 
@@ -1026,7 +1048,7 @@ do_scan_connection_options(bucket_t *bucket, int argc, VALUE *argv)
1026
1048
 
1027
1049
  arg = rb_funcall(uri_obj, id_user, 0);
1028
1050
  if (arg != Qnil) {
1029
- free(bucket->username);
1051
+ xfree(bucket->username);
1030
1052
  bucket->username = strdup(RSTRING_PTR(arg));
1031
1053
  if (bucket->username == NULL) {
1032
1054
  rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
@@ -1035,7 +1057,7 @@ do_scan_connection_options(bucket_t *bucket, int argc, VALUE *argv)
1035
1057
 
1036
1058
  arg = rb_funcall(uri_obj, id_password, 0);
1037
1059
  if (arg != Qnil) {
1038
- free(bucket->password);
1060
+ xfree(bucket->password);
1039
1061
  bucket->password = strdup(RSTRING_PTR(arg));
1040
1062
  if (bucket->password == NULL) {
1041
1063
  rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
@@ -1043,7 +1065,7 @@ do_scan_connection_options(bucket_t *bucket, int argc, VALUE *argv)
1043
1065
  }
1044
1066
  arg = rb_funcall(uri_obj, id_host, 0);
1045
1067
  if (arg != Qnil) {
1046
- free(bucket->hostname);
1068
+ xfree(bucket->hostname);
1047
1069
  bucket->hostname = strdup(RSTRING_PTR(arg));
1048
1070
  if (bucket->hostname == NULL) {
1049
1071
  rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
@@ -1059,45 +1081,45 @@ do_scan_connection_options(bucket_t *bucket, int argc, VALUE *argv)
1059
1081
  re = rb_reg_new(path_re, sizeof(path_re) - 1, 0);
1060
1082
  match = rb_funcall(re, id_match, 1, arg);
1061
1083
  arg = rb_reg_nth_match(2, match);
1062
- free(bucket->pool);
1084
+ xfree(bucket->pool);
1063
1085
  bucket->pool = strdup(NIL_P(arg) ? "default" : RSTRING_PTR(arg));
1064
1086
  arg = rb_reg_nth_match(4, match);
1065
- free(bucket->bucket);
1087
+ xfree(bucket->bucket);
1066
1088
  bucket->bucket = strdup(NIL_P(arg) ? "default" : RSTRING_PTR(arg));
1067
1089
  }
1068
1090
  if (TYPE(opts) == T_HASH) {
1069
1091
  arg = rb_hash_aref(opts, sym_hostname);
1070
1092
  if (arg != Qnil) {
1071
1093
  if (bucket->hostname) {
1072
- free(bucket->hostname);
1094
+ xfree(bucket->hostname);
1073
1095
  }
1074
1096
  bucket->hostname = strdup(StringValueCStr(arg));
1075
1097
  }
1076
1098
  arg = rb_hash_aref(opts, sym_pool);
1077
1099
  if (arg != Qnil) {
1078
1100
  if (bucket->pool) {
1079
- free(bucket->pool);
1101
+ xfree(bucket->pool);
1080
1102
  }
1081
1103
  bucket->pool = strdup(StringValueCStr(arg));
1082
1104
  }
1083
1105
  arg = rb_hash_aref(opts, sym_bucket);
1084
1106
  if (arg != Qnil) {
1085
1107
  if (bucket->bucket) {
1086
- free(bucket->bucket);
1108
+ xfree(bucket->bucket);
1087
1109
  }
1088
1110
  bucket->bucket = strdup(StringValueCStr(arg));
1089
1111
  }
1090
1112
  arg = rb_hash_aref(opts, sym_username);
1091
1113
  if (arg != Qnil) {
1092
1114
  if (bucket->username) {
1093
- free(bucket->username);
1115
+ xfree(bucket->username);
1094
1116
  }
1095
1117
  bucket->username = strdup(StringValueCStr(arg));
1096
1118
  }
1097
1119
  arg = rb_hash_aref(opts, sym_password);
1098
1120
  if (arg != Qnil) {
1099
1121
  if (bucket->password) {
1100
- free(bucket->password);
1122
+ xfree(bucket->password);
1101
1123
  }
1102
1124
  bucket->password = strdup(StringValueCStr(arg));
1103
1125
  }
@@ -1146,9 +1168,9 @@ do_scan_connection_options(bucket_t *bucket, int argc, VALUE *argv)
1146
1168
  }
1147
1169
  len = strlen(bucket->hostname) + 10;
1148
1170
  if (bucket->authority) {
1149
- free(bucket->authority);
1171
+ xfree(bucket->authority);
1150
1172
  }
1151
- bucket->authority = calloc(len, sizeof(char));
1173
+ bucket->authority = xcalloc(len, sizeof(char));
1152
1174
  if (bucket->authority == NULL) {
1153
1175
  rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1154
1176
  }
@@ -1208,15 +1230,8 @@ do_connect(bucket_t *bucket)
1208
1230
  }
1209
1231
  }
1210
1232
 
1211
- /*
1212
- * Create and initialize new Bucket.
1213
- *
1214
- * @return [Bucket] new instance
1215
- *
1216
- * @see Bucket#initialize
1217
- */
1218
1233
  static VALUE
1219
- cb_bucket_new(int argc, VALUE *argv, VALUE klass)
1234
+ cb_bucket_alloc(VALUE klass)
1220
1235
  {
1221
1236
  VALUE obj;
1222
1237
  bucket_t *bucket;
@@ -1224,7 +1239,6 @@ cb_bucket_new(int argc, VALUE *argv, VALUE klass)
1224
1239
  /* allocate new bucket struct and set it to zero */
1225
1240
  obj = Data_Make_Struct(klass, bucket_t, cb_bucket_mark, cb_bucket_free,
1226
1241
  bucket);
1227
- rb_obj_call_init(obj, argc, argv);
1228
1242
  return obj;
1229
1243
  }
1230
1244
 
@@ -1295,6 +1309,7 @@ cb_bucket_init(int argc, VALUE *argv, VALUE self)
1295
1309
  bucket->default_format = sym_document;
1296
1310
  bucket->on_error_proc = Qnil;
1297
1311
  bucket->timeout = 0;
1312
+ bucket->object_space = rb_hash_new();
1298
1313
 
1299
1314
  do_scan_connection_options(bucket, argc, argv);
1300
1315
  do_connect(bucket);
@@ -1302,6 +1317,60 @@ cb_bucket_init(int argc, VALUE *argv, VALUE self)
1302
1317
  return self;
1303
1318
  }
1304
1319
 
1320
+ /*
1321
+ * Initialize copy
1322
+ *
1323
+ * Initializes copy of the object, used by {Couchbase::Bucket#dup}
1324
+ *
1325
+ * @param orig [Couchbase::Bucket] the source for copy
1326
+ *
1327
+ * @return [Couchbase::Bucket]
1328
+ */
1329
+ static VALUE
1330
+ cb_bucket_init_copy(VALUE copy, VALUE orig)
1331
+ {
1332
+ bucket_t *copy_b;
1333
+ bucket_t *orig_b;
1334
+
1335
+ if (copy == orig)
1336
+ return copy;
1337
+
1338
+ if (TYPE(orig) != T_DATA || TYPE(copy) != T_DATA ||
1339
+ RDATA(orig)->dfree != (RUBY_DATA_FUNC)cb_bucket_free) {
1340
+ rb_raise(rb_eTypeError, "wrong argument type");
1341
+ }
1342
+
1343
+ copy_b = DATA_PTR(copy);
1344
+ orig_b = DATA_PTR(orig);
1345
+
1346
+ copy_b->port = orig_b->port;
1347
+ copy_b->authority = strdup(orig_b->authority);
1348
+ copy_b->hostname = strdup(orig_b->hostname);
1349
+ copy_b->pool = strdup(orig_b->pool);
1350
+ copy_b->bucket = strdup(orig_b->bucket);
1351
+ if (orig_b->username) {
1352
+ copy_b->username = strdup(orig_b->username);
1353
+ }
1354
+ if (orig_b->password) {
1355
+ copy_b->password = strdup(orig_b->password);
1356
+ }
1357
+ copy_b->async = orig_b->async;
1358
+ copy_b->quiet = orig_b->quiet;
1359
+ copy_b->seqno = orig_b->seqno;
1360
+ copy_b->default_format = orig_b->default_format;
1361
+ copy_b->default_flags = orig_b->default_flags;
1362
+ copy_b->default_ttl = orig_b->default_ttl;
1363
+ copy_b->timeout = orig_b->timeout;
1364
+ copy_b->exception = Qnil;
1365
+ if (orig_b->on_error_proc != Qnil) {
1366
+ copy_b->on_error_proc = rb_funcall(orig_b->on_error_proc, id_dup, 0);
1367
+ }
1368
+
1369
+ do_connect(copy_b);
1370
+
1371
+ return copy;
1372
+ }
1373
+
1305
1374
  /*
1306
1375
  * Reconnect the bucket
1307
1376
  *
@@ -1492,7 +1561,7 @@ cb_bucket_hostname_get(VALUE self)
1492
1561
  bucket_t *bucket = DATA_PTR(self);
1493
1562
  if (bucket->handle) {
1494
1563
  if (bucket->hostname) {
1495
- free(bucket->hostname);
1564
+ xfree(bucket->hostname);
1496
1565
  bucket->hostname = NULL;
1497
1566
  }
1498
1567
  bucket->hostname = strdup(libcouchbase_get_host(bucket->handle));
@@ -1528,7 +1597,7 @@ cb_bucket_authority_get(VALUE self)
1528
1597
  (void)cb_bucket_hostname_get(self);
1529
1598
  (void)cb_bucket_port_get(self);
1530
1599
  len = strlen(bucket->hostname) + 10;
1531
- bucket->authority = calloc(len, sizeof(char));
1600
+ bucket->authority = xcalloc(len, sizeof(char));
1532
1601
  if (bucket->authority == NULL) {
1533
1602
  rb_raise(eNoMemoryError, "failed to allocate memory for Bucket");
1534
1603
  }
@@ -1691,7 +1760,7 @@ cb_bucket_delete(int argc, VALUE *argv, VALUE self)
1691
1760
  k = unify_key(k);
1692
1761
  key = RSTRING_PTR(k);
1693
1762
  nkey = RSTRING_LEN(k);
1694
- ctx = calloc(1, sizeof(context_t));
1763
+ ctx = xcalloc(1, sizeof(context_t));
1695
1764
  ctx->quiet = bucket->quiet;
1696
1765
  if (ctx == NULL) {
1697
1766
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
@@ -1710,7 +1779,7 @@ cb_bucket_delete(int argc, VALUE *argv, VALUE self)
1710
1779
  }
1711
1780
  }
1712
1781
  ctx->proc = proc;
1713
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
1782
+ cb_gc_protect(bucket, ctx->proc);
1714
1783
  rv = rb_ary_new();
1715
1784
  ctx->rv = &rv;
1716
1785
  ctx->bucket = bucket;
@@ -1721,7 +1790,7 @@ cb_bucket_delete(int argc, VALUE *argv, VALUE self)
1721
1790
  (const void *)key, nkey, cas);
1722
1791
  exc = cb_check_error(err, "failed to schedule delete request", Qnil);
1723
1792
  if (exc != Qnil) {
1724
- free(ctx);
1793
+ xfree(ctx);
1725
1794
  rb_exc_raise(exc);
1726
1795
  }
1727
1796
  if (bucket->async) {
@@ -1732,8 +1801,9 @@ cb_bucket_delete(int argc, VALUE *argv, VALUE self)
1732
1801
  bucket->io->run_event_loop(bucket->io);
1733
1802
  }
1734
1803
  exc = ctx->exception;
1735
- free(ctx);
1804
+ xfree(ctx);
1736
1805
  if (exc != Qnil) {
1806
+ cb_gc_unprotect(bucket, exc);
1737
1807
  rb_exc_raise(exc);
1738
1808
  }
1739
1809
  return rv;
@@ -1791,7 +1861,7 @@ cb_bucket_store(libcouchbase_storage_t cmd, int argc, VALUE *argv, VALUE self)
1791
1861
  }
1792
1862
  bytes = RSTRING_PTR(v);
1793
1863
  nbytes = RSTRING_LEN(v);
1794
- ctx = calloc(1, sizeof(context_t));
1864
+ ctx = xcalloc(1, sizeof(context_t));
1795
1865
  if (ctx == NULL) {
1796
1866
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
1797
1867
  }
@@ -1799,7 +1869,7 @@ cb_bucket_store(libcouchbase_storage_t cmd, int argc, VALUE *argv, VALUE self)
1799
1869
  ctx->rv = &rv;
1800
1870
  ctx->bucket = bucket;
1801
1871
  ctx->proc = proc;
1802
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
1872
+ cb_gc_protect(bucket, ctx->proc);
1803
1873
  ctx->exception = Qnil;
1804
1874
  seqno = bucket->seqno;
1805
1875
  bucket->seqno++;
@@ -1807,7 +1877,7 @@ cb_bucket_store(libcouchbase_storage_t cmd, int argc, VALUE *argv, VALUE self)
1807
1877
  (const void *)key, nkey, bytes, nbytes, flags, exp, cas);
1808
1878
  exc = cb_check_error(err, "failed to schedule set request", Qnil);
1809
1879
  if (exc != Qnil) {
1810
- free(ctx);
1880
+ xfree(ctx);
1811
1881
  rb_exc_raise(exc);
1812
1882
  }
1813
1883
  if (bucket->async) {
@@ -1818,8 +1888,9 @@ cb_bucket_store(libcouchbase_storage_t cmd, int argc, VALUE *argv, VALUE self)
1818
1888
  bucket->io->run_event_loop(bucket->io);
1819
1889
  }
1820
1890
  exc = ctx->exception;
1821
- free(ctx);
1891
+ xfree(ctx);
1822
1892
  if (exc != Qnil) {
1893
+ cb_gc_unprotect(bucket, exc);
1823
1894
  rb_exc_raise(exc);
1824
1895
  }
1825
1896
  if (bucket->exception != Qnil) {
@@ -1851,7 +1922,7 @@ cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
1851
1922
  rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
1852
1923
  }
1853
1924
  k = unify_key(k);
1854
- ctx = calloc(1, sizeof(context_t));
1925
+ ctx = xcalloc(1, sizeof(context_t));
1855
1926
  if (ctx == NULL) {
1856
1927
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
1857
1928
  }
@@ -1885,7 +1956,7 @@ cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
1885
1956
  ctx->rv = &rv;
1886
1957
  ctx->bucket = bucket;
1887
1958
  ctx->proc = proc;
1888
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
1959
+ cb_gc_protect(bucket, ctx->proc);
1889
1960
  ctx->exception = Qnil;
1890
1961
  ctx->arithm = sign;
1891
1962
  seqno = bucket->seqno;
@@ -1894,7 +1965,7 @@ cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
1894
1965
  (const void *)key, nkey, delta, exp, create, initial);
1895
1966
  exc = cb_check_error(err, "failed to schedule arithmetic request", k);
1896
1967
  if (exc != Qnil) {
1897
- free(ctx);
1968
+ xfree(ctx);
1898
1969
  rb_exc_raise(exc);
1899
1970
  }
1900
1971
  if (bucket->async) {
@@ -1905,8 +1976,9 @@ cb_bucket_arithmetic(int sign, int argc, VALUE *argv, VALUE self)
1905
1976
  bucket->io->run_event_loop(bucket->io);
1906
1977
  }
1907
1978
  exc = ctx->exception;
1908
- free(ctx);
1979
+ xfree(ctx);
1909
1980
  if (exc != Qnil) {
1981
+ cb_gc_unprotect(bucket, exc);
1910
1982
  rb_exc_raise(exc);
1911
1983
  }
1912
1984
  return rv;
@@ -2197,16 +2269,16 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
2197
2269
  rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2198
2270
  }
2199
2271
  rb_funcall(args, id_flatten_bang, 0);
2200
- traits = calloc(1, sizeof(struct key_traits));
2272
+ traits = xcalloc(1, sizeof(struct key_traits));
2201
2273
  nn = cb_args_scan_keys(RARRAY_LEN(args), args, bucket, traits);
2202
- ctx = calloc(1, sizeof(context_t));
2274
+ ctx = xcalloc(1, sizeof(context_t));
2203
2275
  if (ctx == NULL) {
2204
2276
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
2205
2277
  }
2206
2278
  mgat = traits->mgat;
2207
2279
  keys = traits->keys_ary;
2208
2280
  ctx->proc = proc;
2209
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
2281
+ cb_gc_protect(bucket, ctx->proc);
2210
2282
  ctx->bucket = bucket;
2211
2283
  ctx->extended = traits->extended;
2212
2284
  ctx->quiet = traits->quiet;
@@ -2219,13 +2291,13 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
2219
2291
  err = libcouchbase_mget(bucket->handle, (const void *)ctx,
2220
2292
  traits->nkeys, (const void * const *)traits->keys,
2221
2293
  traits->lens, (traits->explicit_ttl) ? traits->ttls : NULL);
2222
- free(traits->keys);
2223
- free(traits->lens);
2224
- free(traits->ttls);
2225
- free(traits);
2294
+ xfree(traits->keys);
2295
+ xfree(traits->lens);
2296
+ xfree(traits->ttls);
2297
+ xfree(traits);
2226
2298
  exc = cb_check_error(err, "failed to schedule get request", Qnil);
2227
2299
  if (exc != Qnil) {
2228
- free(ctx);
2300
+ xfree(ctx);
2229
2301
  rb_exc_raise(exc);
2230
2302
  }
2231
2303
  if (bucket->async) {
@@ -2237,8 +2309,9 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
2237
2309
  }
2238
2310
  exc = ctx->exception;
2239
2311
  extended = ctx->extended;
2240
- free(ctx);
2312
+ xfree(ctx);
2241
2313
  if (exc != Qnil) {
2314
+ cb_gc_unprotect(bucket, exc);
2242
2315
  rb_exc_raise(exc);
2243
2316
  }
2244
2317
  if (bucket->exception != Qnil) {
@@ -2344,14 +2417,14 @@ cb_bucket_touch(int argc, VALUE *argv, VALUE self)
2344
2417
  rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2345
2418
  }
2346
2419
  rb_funcall(args, id_flatten_bang, 0);
2347
- traits = calloc(1, sizeof(struct key_traits));
2420
+ traits = xcalloc(1, sizeof(struct key_traits));
2348
2421
  nn = cb_args_scan_keys(RARRAY_LEN(args), args, bucket, traits);
2349
- ctx = calloc(1, sizeof(context_t));
2422
+ ctx = xcalloc(1, sizeof(context_t));
2350
2423
  if (ctx == NULL) {
2351
2424
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
2352
2425
  }
2353
2426
  ctx->proc = proc;
2354
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
2427
+ cb_gc_protect(bucket, ctx->proc);
2355
2428
  ctx->bucket = bucket;
2356
2429
  rv = rb_hash_new();
2357
2430
  ctx->rv = &rv;
@@ -2361,12 +2434,12 @@ cb_bucket_touch(int argc, VALUE *argv, VALUE self)
2361
2434
  err = libcouchbase_mtouch(bucket->handle, (const void *)ctx,
2362
2435
  traits->nkeys, (const void * const *)traits->keys,
2363
2436
  traits->lens, traits->ttls);
2364
- free(traits->keys);
2365
- free(traits->lens);
2366
- free(traits);
2437
+ xfree(traits->keys);
2438
+ xfree(traits->lens);
2439
+ xfree(traits);
2367
2440
  exc = cb_check_error(err, "failed to schedule touch request", Qnil);
2368
2441
  if (exc != Qnil) {
2369
- free(ctx);
2442
+ xfree(ctx);
2370
2443
  rb_exc_raise(exc);
2371
2444
  }
2372
2445
  if (bucket->async) {
@@ -2377,8 +2450,9 @@ cb_bucket_touch(int argc, VALUE *argv, VALUE self)
2377
2450
  bucket->io->run_event_loop(bucket->io);
2378
2451
  }
2379
2452
  exc = ctx->exception;
2380
- free(ctx);
2453
+ xfree(ctx);
2381
2454
  if (exc != Qnil) {
2455
+ cb_gc_unprotect(bucket, exc);
2382
2456
  rb_exc_raise(exc);
2383
2457
  }
2384
2458
  if (bucket->exception != Qnil) {
@@ -2433,7 +2507,7 @@ cb_bucket_flush(VALUE self)
2433
2507
  if (!bucket->async && rb_block_given_p()) {
2434
2508
  rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2435
2509
  }
2436
- ctx = calloc(1, sizeof(context_t));
2510
+ ctx = xcalloc(1, sizeof(context_t));
2437
2511
  if (ctx == NULL) {
2438
2512
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
2439
2513
  }
@@ -2446,13 +2520,13 @@ cb_bucket_flush(VALUE self)
2446
2520
  } else {
2447
2521
  ctx->proc = Qnil;
2448
2522
  }
2449
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
2523
+ cb_gc_protect(bucket, ctx->proc);
2450
2524
  seqno = bucket->seqno;
2451
2525
  bucket->seqno++;
2452
2526
  err = libcouchbase_flush(bucket->handle, (const void *)ctx);
2453
2527
  exc = cb_check_error(err, "failed to schedule flush request", Qnil);
2454
2528
  if (exc != Qnil) {
2455
- free(ctx);
2529
+ xfree(ctx);
2456
2530
  rb_exc_raise(exc);
2457
2531
  }
2458
2532
  if (bucket->async) {
@@ -2463,8 +2537,9 @@ cb_bucket_flush(VALUE self)
2463
2537
  bucket->io->run_event_loop(bucket->io);
2464
2538
  }
2465
2539
  exc = ctx->exception;
2466
- free(ctx);
2540
+ xfree(ctx);
2467
2541
  if (exc != Qnil) {
2542
+ cb_gc_unprotect(bucket, exc);
2468
2543
  rb_exc_raise(exc);
2469
2544
  }
2470
2545
  return rv;
@@ -2511,7 +2586,7 @@ cb_bucket_version(VALUE self)
2511
2586
  if (!bucket->async && rb_block_given_p()) {
2512
2587
  rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2513
2588
  }
2514
- ctx = calloc(1, sizeof(context_t));
2589
+ ctx = xcalloc(1, sizeof(context_t));
2515
2590
  if (ctx == NULL) {
2516
2591
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
2517
2592
  }
@@ -2524,13 +2599,13 @@ cb_bucket_version(VALUE self)
2524
2599
  } else {
2525
2600
  ctx->proc = Qnil;
2526
2601
  }
2527
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
2602
+ cb_gc_protect(bucket, ctx->proc);
2528
2603
  seqno = bucket->seqno;
2529
2604
  bucket->seqno++;
2530
2605
  err = libcouchbase_server_versions(bucket->handle, (const void *)ctx);
2531
2606
  exc = cb_check_error(err, "failed to schedule version request", Qnil);
2532
2607
  if (exc != Qnil) {
2533
- free(ctx);
2608
+ xfree(ctx);
2534
2609
  rb_exc_raise(exc);
2535
2610
  }
2536
2611
  if (bucket->async) {
@@ -2541,8 +2616,9 @@ cb_bucket_version(VALUE self)
2541
2616
  bucket->io->run_event_loop(bucket->io);
2542
2617
  }
2543
2618
  exc = ctx->exception;
2544
- free(ctx);
2619
+ xfree(ctx);
2545
2620
  if (exc != Qnil) {
2621
+ cb_gc_unprotect(bucket, exc);
2546
2622
  rb_exc_raise(exc);
2547
2623
  }
2548
2624
  return rv;
@@ -2608,7 +2684,7 @@ cb_bucket_stats(int argc, VALUE *argv, VALUE self)
2608
2684
  rb_raise(rb_eArgError, "synchronous mode doesn't support callbacks");
2609
2685
  }
2610
2686
 
2611
- ctx = calloc(1, sizeof(context_t));
2687
+ ctx = xcalloc(1, sizeof(context_t));
2612
2688
  if (ctx == NULL) {
2613
2689
  rb_raise(eNoMemoryError, "failed to allocate memory for context");
2614
2690
  }
@@ -2616,7 +2692,7 @@ cb_bucket_stats(int argc, VALUE *argv, VALUE self)
2616
2692
  ctx->rv = &rv;
2617
2693
  ctx->bucket = bucket;
2618
2694
  ctx->proc = proc;
2619
- rb_hash_aset(object_space, ctx->proc|1, ctx->proc);
2695
+ cb_gc_protect(bucket, ctx->proc);
2620
2696
  ctx->exception = Qnil;
2621
2697
  if (arg != Qnil) {
2622
2698
  arg = unify_key(arg);
@@ -2632,7 +2708,7 @@ cb_bucket_stats(int argc, VALUE *argv, VALUE self)
2632
2708
  key, nkey);
2633
2709
  exc = cb_check_error(err, "failed to schedule stat request", Qnil);
2634
2710
  if (exc != Qnil) {
2635
- free(ctx);
2711
+ xfree(ctx);
2636
2712
  rb_exc_raise(exc);
2637
2713
  }
2638
2714
  if (bucket->async) {
@@ -2643,8 +2719,9 @@ cb_bucket_stats(int argc, VALUE *argv, VALUE self)
2643
2719
  bucket->io->run_event_loop(bucket->io);
2644
2720
  }
2645
2721
  exc = ctx->exception;
2646
- free(ctx);
2722
+ xfree(ctx);
2647
2723
  if (exc != Qnil) {
2724
+ cb_gc_unprotect(bucket, exc);
2648
2725
  rb_exc_raise(exc);
2649
2726
  }
2650
2727
  if (bucket->exception != Qnil) {
@@ -3250,9 +3327,6 @@ Init_couchbase_ext(void)
3250
3327
  * This class in charge of all stuff connected to communication with
3251
3328
  * Couchbase. */
3252
3329
  cBucket = rb_define_class_under(mCouchbase, "Bucket", rb_cObject);
3253
- object_space = rb_hash_new();
3254
- /* @private Hack to avoid GC in some cases */
3255
- rb_define_const(cBucket, "OBJECT_SPACE", object_space);
3256
3330
 
3257
3331
  /* 0x03: Bitmask for flag bits responsible for format */
3258
3332
  rb_define_const(cBucket, "FMT_MASK", INT2FIX(FMT_MASK));
@@ -3272,9 +3346,9 @@ Init_couchbase_ext(void)
3272
3346
  * http://dustin.github.com/2011/02/17/memcached-set.html */
3273
3347
  rb_define_const(cBucket, "FMT_PLAIN", INT2FIX(FMT_PLAIN));
3274
3348
 
3275
- rb_define_singleton_method(cBucket, "new", cb_bucket_new, -1);
3276
-
3349
+ rb_define_alloc_func(cBucket, cb_bucket_alloc);
3277
3350
  rb_define_method(cBucket, "initialize", cb_bucket_init, -1);
3351
+ rb_define_method(cBucket, "initialize_copy", cb_bucket_init_copy, 1);
3278
3352
  rb_define_method(cBucket, "inspect", cb_bucket_inspect, 0);
3279
3353
 
3280
3354
  /* Document-method: seqno
@@ -3441,6 +3515,7 @@ Init_couchbase_ext(void)
3441
3515
  id_arity = rb_intern("arity");
3442
3516
  id_call = rb_intern("call");
3443
3517
  id_dump = rb_intern("dump");
3518
+ id_dup = rb_intern("dup");
3444
3519
  id_flatten_bang = rb_intern("flatten!");
3445
3520
  id_has_key_p = rb_intern("has_key?");
3446
3521
  id_host = rb_intern("host");
@@ -57,12 +57,12 @@ module Couchbase
57
57
  if async?
58
58
  get(key, options) do |ret|
59
59
  val = yield(ret) # get new value from caller
60
- set(ret.key, val, :cas => ret.cas)
60
+ set(ret.key, val, :cas => ret.cas, :flags => ret.flags)
61
61
  end
62
62
  else
63
63
  val, flags, ver = get(key, options)
64
64
  val = yield(val) # get new value from caller
65
- set(key, val, :cas => ver)
65
+ set(key, val, :cas => ver, :flags => flags)
66
66
  end
67
67
  end
68
68
  alias :compare_and_swap :cas
@@ -17,5 +17,5 @@
17
17
 
18
18
  # Couchbase ruby client
19
19
  module Couchbase
20
- VERSION = "1.1.2"
20
+ VERSION = "1.1.3"
21
21
  end
data/test/test_cas.rb CHANGED
@@ -56,4 +56,12 @@ class TestCas < MiniTest::Unit::TestCase
56
56
  assert_equal expected, val
57
57
  end
58
58
 
59
+ def test_flags_replication
60
+ connection = Couchbase.new(:hostname => @mock.host, :port => @mock.port,
61
+ :default_format => :document)
62
+ connection.set(uniq_id, "bar", :flags => 0x100)
63
+ connection.cas(uniq_id) { "baz" }
64
+ _, flags, _ = connection.get(uniq_id, :extended => true)
65
+ assert_equal 0x100, flags
66
+ end
59
67
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: couchbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-05 00:00:00.000000000 Z
12
+ date: 2012-07-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: yajl-ruby
@@ -198,7 +198,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
198
198
  version: '0'
199
199
  segments:
200
200
  - 0
201
- hash: 3642413217279850203
201
+ hash: 4020867822083884443
202
202
  required_rubygems_version: !ruby/object:Gem::Requirement
203
203
  none: false
204
204
  requirements:
@@ -207,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
207
207
  version: '0'
208
208
  segments:
209
209
  - 0
210
- hash: 3642413217279850203
210
+ hash: 4020867822083884443
211
211
  requirements: []
212
212
  rubyforge_project:
213
213
  rubygems_version: 1.8.24