couchbase 1.2.3 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -97,7 +97,7 @@ struct cb_bucket_st
97
97
  uint8_t connected; /* non-zero if instance has been connected. it is possible to defer connection with :async option */
98
98
  uint8_t running; /* non-zero if event loop is running */
99
99
  uint8_t trigger_connect_cb_on_set; /* if non-zero, the on_connect callback will be triggered immediately after set */
100
- VALUE default_format; /* should update +default_flags+ on change */
100
+ VALUE transcoder;
101
101
  uint32_t default_flags;
102
102
  time_t default_ttl;
103
103
  time_t default_observe_timeout;
@@ -127,7 +127,8 @@ struct cb_context_st
127
127
  VALUE rv;
128
128
  VALUE exception;
129
129
  VALUE observe_options;
130
- VALUE force_format;
130
+ VALUE transcoder;
131
+ VALUE transcoder_opts;
131
132
  VALUE operation;
132
133
  VALUE headers_val;
133
134
  int headers_built;
@@ -169,8 +170,10 @@ extern VALUE cb_cTimer;
169
170
  /* Modules */
170
171
  extern VALUE cb_mCouchbase;
171
172
  extern VALUE cb_mError;
173
+ extern VALUE cb_mTranscoder;
174
+ extern VALUE cb_mDocument;
175
+ extern VALUE cb_mPlain;
172
176
  extern VALUE cb_mMarshal;
173
- extern VALUE cb_mMultiJson;
174
177
  extern VALUE cb_mURI;
175
178
  extern VALUE em_m;
176
179
 
@@ -203,6 +206,7 @@ extern ID cb_sym_environment;
203
206
  extern ID cb_sym_eventmachine;
204
207
  extern ID cb_sym_extended;
205
208
  extern ID cb_sym_flags;
209
+ extern ID cb_sym_forced;
206
210
  extern ID cb_sym_format;
207
211
  extern ID cb_sym_found;
208
212
  extern ID cb_sym_get;
@@ -239,6 +243,7 @@ extern ID cb_sym_set;
239
243
  extern ID cb_sym_stats;
240
244
  extern ID cb_sym_timeout;
241
245
  extern ID cb_sym_touch;
246
+ extern ID cb_sym_transcoder;
242
247
  extern ID cb_sym_ttl;
243
248
  extern ID cb_sym_type;
244
249
  extern ID cb_sym_unlock;
@@ -336,10 +341,8 @@ int cb_first_value_i(VALUE key, VALUE value, VALUE arg);
336
341
  void cb_build_headers(struct cb_context_st *ctx, const char * const *headers);
337
342
  void cb_maybe_do_loop(struct cb_bucket_st *bucket);
338
343
  VALUE cb_unify_key(struct cb_bucket_st *bucket, VALUE key, int apply_prefix);
339
- VALUE cb_encode_value(VALUE val, uint32_t flags);
340
- VALUE cb_decode_value(VALUE blob, uint32_t flags, VALUE force_format);
341
- uint32_t cb_flags_set_format(uint32_t flags, ID format);
342
- ID cb_flags_get_format(uint32_t flags);
344
+ VALUE cb_encode_value(VALUE transcoder, VALUE val, uint32_t *flags, VALUE options);
345
+ VALUE cb_decode_value(VALUE transcoder, VALUE blob, uint32_t flags, VALUE options);
343
346
  void cb_async_error_notify(struct cb_bucket_st *bucket, VALUE exc);
344
347
 
345
348
 
@@ -388,6 +391,8 @@ VALUE cb_bucket_connected_p(VALUE self);
388
391
  VALUE cb_bucket_async_p(VALUE self);
389
392
  VALUE cb_bucket_quiet_get(VALUE self);
390
393
  VALUE cb_bucket_quiet_set(VALUE self, VALUE val);
394
+ VALUE cb_bucket_transcoder_get(VALUE self);
395
+ VALUE cb_bucket_transcoder_set(VALUE self, VALUE val);
391
396
  VALUE cb_bucket_default_flags_get(VALUE self);
392
397
  VALUE cb_bucket_default_flags_set(VALUE self, VALUE val);
393
398
  VALUE cb_bucket_default_format_get(VALUE self);
@@ -488,6 +493,8 @@ struct cb_params_st
488
493
  lcb_cas_t cas;
489
494
  lcb_datatype_t datatype;
490
495
  VALUE observe;
496
+ VALUE transcoder;
497
+ VALUE transcoder_opts;
491
498
  } store;
492
499
  struct {
493
500
  /* number of items */
@@ -509,7 +516,8 @@ struct cb_params_st
509
516
  /* arguments given in form of hash key-ttl to "get and touch" */
510
517
  unsigned int gat : 1;
511
518
  lcb_time_t ttl;
512
- VALUE forced_format;
519
+ VALUE transcoder;
520
+ VALUE transcoder_opts;
513
521
  VALUE keys_ary;
514
522
  } get;
515
523
  struct {
@@ -526,7 +534,8 @@ struct cb_params_st
526
534
  lcb_uint64_t initial;
527
535
  lcb_uint64_t delta;
528
536
  int sign;
529
- VALUE format;
537
+ VALUE transcoder;
538
+ VALUE transcoder_opts;
530
539
  lcb_datatype_t datatype;
531
540
  } arith;
532
541
  struct {
@@ -22,7 +22,7 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
22
22
  {
23
23
  struct cb_context_st *ctx = (struct cb_context_st *)cookie;
24
24
  struct cb_bucket_st *bucket = ctx->bucket;
25
- VALUE key, val, flags, cas, exc = Qnil, res;
25
+ VALUE key, val, flags, cas, exc = Qnil, res, raw;
26
26
 
27
27
  ctx->nqueries--;
28
28
  key = STR_NEW((const char*)resp->v.v0.key, resp->v.v0.nkey);
@@ -38,22 +38,17 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
38
38
 
39
39
  flags = ULONG2NUM(resp->v.v0.flags);
40
40
  cas = ULL2NUM(resp->v.v0.cas);
41
- val = Qnil;
42
- if (resp->v.v0.nbytes != 0) {
43
- VALUE raw = STR_NEW((const char*)resp->v.v0.bytes, resp->v.v0.nbytes);
44
- val = cb_decode_value(raw, resp->v.v0.flags, ctx->force_format);
45
- if (rb_obj_is_kind_of(val, rb_eStandardError)) {
46
- VALUE exc_str = rb_funcall(val, cb_id_to_s, 0);
47
- VALUE msg = rb_funcall(rb_mKernel, cb_id_sprintf, 3,
48
- rb_str_new2("unable to convert value for key '%s': %s"), key, exc_str);
49
- ctx->exception = rb_exc_new3(cb_eValueFormatError, msg);
50
- rb_ivar_set(ctx->exception, cb_id_iv_operation, cb_sym_get);
51
- rb_ivar_set(ctx->exception, cb_id_iv_key, key);
52
- rb_ivar_set(ctx->exception, cb_id_iv_inner_exception, val);
53
- val = raw;
54
- }
55
- } else if (cb_flags_get_format(resp->v.v0.flags) == cb_sym_plain) {
56
- val = cb_vStrEmpty;
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;
57
52
  }
58
53
  if (bucket->async) { /* asynchronous */
59
54
  if (ctx->proc != Qnil) {
@@ -96,8 +91,8 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
96
91
  * @param keys [String, Symbol, Array] One or several keys to fetch
97
92
  * @param options [Hash] Options for operation.
98
93
  * @option options [true, false] :extended (false) If set to +true+, the
99
- * operation will return tuple +[value, flags, cas]+, otherwise (by
100
- * default) it returns just value.
94
+ * operation will return a tuple +[value, flags, cas]+, otherwise (by
95
+ * default) it returns just the value.
101
96
  * @option options [Fixnum] :ttl (self.default_ttl) Expiry time for key.
102
97
  * Values larger than 30*24*60*60 seconds (30 days) are interpreted as
103
98
  * absolute times (from the epoch).
@@ -128,7 +123,7 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
128
123
  * +cas+).
129
124
  *
130
125
  * @return [Object, Array, Hash] the value(s) (or tuples in extended mode)
131
- * assiciated with the key.
126
+ * associated with the key.
132
127
  *
133
128
  * @raise [Couchbase::Error::NotFound] if the key is missing in the
134
129
  * bucket.
@@ -137,7 +132,7 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
137
132
  *
138
133
  * @raise [ArgumentError] when passing the block in synchronous mode
139
134
  *
140
- * @example Get single value in quite mode (the default)
135
+ * @example Get single value in quiet mode (the default)
141
136
  * c.get("foo") #=> the associated value or nil
142
137
  *
143
138
  * @example Use alternative hash-like syntax
@@ -199,7 +194,7 @@ cb_get_callback(lcb_t handle, const void *cookie, lcb_error_t error, const lcb_g
199
194
  * @param options [Hash] Options for operation. (see options definition
200
195
  * above)
201
196
  *
202
- * @return [Hash] the values (or tuples in extended mode) assiciated with
197
+ * @return [Hash] the values (or tuples in extended mode) associated with
203
198
  * the keys.
204
199
  *
205
200
  * @example Get and touch multiple keys
@@ -239,7 +234,8 @@ cb_bucket_get(int argc, VALUE *argv, VALUE self)
239
234
  ctx = cb_context_alloc_common(bucket, proc, params.cmd.get.num);
240
235
  ctx->extended = params.cmd.get.extended;
241
236
  ctx->quiet = params.cmd.get.quiet;
242
- ctx->force_format = params.cmd.get.forced_format;
237
+ ctx->transcoder = params.cmd.get.transcoder;
238
+ ctx->transcoder_opts = params.cmd.get.transcoder_opts;
243
239
  if (params.cmd.get.replica) {
244
240
  err = lcb_get_replica(bucket->handle, (const void *)ctx,
245
241
  params.cmd.get.num, params.cmd.get.ptr_gr);
@@ -201,7 +201,7 @@ cb_bucket_store(lcb_storage_t cmd, int argc, VALUE *argv, VALUE self)
201
201
  * @option options [Symbol] :format (self.default_format) The
202
202
  * representation for storing the value in the bucket. For more info see
203
203
  * {Bucket#default_format}.
204
- * @option options [Fixnum] :cas The CAS value for an object. This value
204
+ * @option options [Fixnum] :cas The CAS value for an object. This value is
205
205
  * created on the server and is guaranteed to be unique for each value of
206
206
  * a given key. This value is used to provide simple optimistic
207
207
  * concurrency control when multiple clients or threads try to update an
@@ -360,89 +360,33 @@ cb_check_error(lcb_error_t rc, const char *msg, VALUE key)
360
360
  return cb_check_error_with_status(rc, msg, key, 0);
361
361
  }
362
362
 
363
-
364
- uint32_t
365
- cb_flags_set_format(uint32_t flags, ID format)
366
- {
367
- flags &= ~((uint32_t)CB_FMT_MASK); /* clear format bits */
368
-
369
- if (format == cb_sym_document) {
370
- return flags | CB_FMT_DOCUMENT;
371
- } else if (format == cb_sym_marshal) {
372
- return flags | CB_FMT_MARSHAL;
373
- } else if (format == cb_sym_plain) {
374
- return flags | CB_FMT_PLAIN;
375
- }
376
- return flags; /* document is the default */
377
- }
378
-
379
- ID
380
- cb_flags_get_format(uint32_t flags)
381
- {
382
- flags &= CB_FMT_MASK; /* select format bits */
383
-
384
- switch (flags) {
385
- case CB_FMT_DOCUMENT:
386
- return cb_sym_document;
387
- case CB_FMT_MARSHAL:
388
- return cb_sym_marshal;
389
- case CB_FMT_PLAIN:
390
- /* fall through */
391
- default:
392
- /* all other formats treated as plain */
393
- return cb_sym_plain;
394
- }
395
- }
396
-
397
-
398
363
  static VALUE
399
364
  do_encode(VALUE *args)
400
365
  {
401
366
  VALUE val = args[0];
402
- uint32_t flags = ((uint32_t)args[1] & CB_FMT_MASK);
403
-
404
- switch (flags) {
405
- case CB_FMT_DOCUMENT:
406
- return rb_funcall(cb_mMultiJson, cb_id_dump, 1, val);
407
- case CB_FMT_MARSHAL:
408
- return rb_funcall(cb_mMarshal, cb_id_dump, 1, val);
409
- case CB_FMT_PLAIN:
410
- /* fall through */
411
- default:
412
- /* all other formats treated as plain */
413
- return val;
367
+ uint32_t *flags = (uint32_t *)args[1];
368
+ VALUE transcoder = args[2];
369
+ VALUE options = args[3];
370
+ VALUE ret;
371
+
372
+ ret = rb_funcall(transcoder, cb_id_dump, 3, val, ULONG2NUM(*flags), options);
373
+ Check_Type(ret, T_ARRAY);
374
+ if (RARRAY_LEN(ret) != 2) {
375
+ rb_raise(rb_eArgError, "#dump method of transcoder should return two items");
414
376
  }
377
+ *flags = NUM2ULONG(RARRAY_PTR(ret)[1]);
378
+ return RARRAY_PTR(ret)[0];
415
379
  }
416
380
 
417
381
  static VALUE
418
382
  do_decode(VALUE *args)
419
383
  {
420
384
  VALUE blob = args[0];
421
- VALUE force_format = args[2];
422
-
423
- if (TYPE(force_format) == T_SYMBOL) {
424
- if (force_format == cb_sym_document) {
425
- return rb_funcall(cb_mMultiJson, cb_id_load, 1, blob);
426
- } else if (force_format == cb_sym_marshal) {
427
- return rb_funcall(cb_mMarshal, cb_id_load, 1, blob);
428
- } else { /* cb_sym_plain and any other cb_symbol */
429
- return blob;
430
- }
431
- } else {
432
- uint32_t flags = ((uint32_t)args[1] & CB_FMT_MASK);
433
-
434
- switch (flags) {
435
- case CB_FMT_DOCUMENT:
436
- return rb_funcall(cb_mMultiJson, cb_id_load, 1, blob);
437
- case CB_FMT_MARSHAL:
438
- return rb_funcall(cb_mMarshal, cb_id_load, 1, blob);
439
- case CB_FMT_PLAIN:
440
- /* fall through */
441
- default:
442
- /* all other formats treated as plain */
443
- return blob;
444
- }
445
- }
385
+ VALUE transcoder = args[2];
386
+ VALUE flags = args[1];
387
+ VALUE options = args[3];
388
+
389
+ return rb_funcall(transcoder, cb_id_load, 3, blob, ULONG2NUM(flags), options);
446
390
  }
447
391
 
448
392
  static VALUE
@@ -453,20 +397,27 @@ coding_failed(VALUE unused, VALUE exc)
453
397
  }
454
398
 
455
399
  VALUE
456
- cb_encode_value(VALUE val, uint32_t flags)
400
+ cb_encode_value(VALUE transcoder, VALUE val, uint32_t *flags, VALUE options)
457
401
  {
458
- VALUE blob, args[2];
402
+ VALUE args[4];
459
403
 
460
404
  args[0] = val;
461
405
  args[1] = (VALUE)flags;
462
- blob = rb_rescue(do_encode, (VALUE)args, coding_failed, 0);
463
- return blob; /* bytestring or exception object */
406
+ args[2] = transcoder;
407
+ args[3] = options;
408
+
409
+ /* if nil, just pass value through */
410
+ if (NIL_P(args[2])) {
411
+ return val;
412
+ }
413
+ /* bytestring or exception object */
414
+ return rb_rescue(do_encode, (VALUE)args, coding_failed, 0);
464
415
  }
465
416
 
466
417
  VALUE
467
- cb_decode_value(VALUE blob, uint32_t flags, VALUE force_format)
418
+ cb_decode_value(VALUE transcoder, VALUE blob, uint32_t flags, VALUE options)
468
419
  {
469
- VALUE val, args[3];
420
+ VALUE args[4];
470
421
 
471
422
  /* first it must be bytestring */
472
423
  if (TYPE(blob) != T_STRING) {
@@ -474,9 +425,15 @@ cb_decode_value(VALUE blob, uint32_t flags, VALUE force_format)
474
425
  }
475
426
  args[0] = blob;
476
427
  args[1] = (VALUE)flags;
477
- args[2] = (VALUE)force_format;
478
- val = rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
479
- return val; /* the value or exception object */
428
+ args[2] = transcoder;
429
+ args[3] = options;
430
+
431
+ /* if nil, just pass blob through */
432
+ if (NIL_P(args[2])) {
433
+ return blob;
434
+ }
435
+ /* the value or exception object */
436
+ return rb_rescue(do_decode, (VALUE)args, coding_failed, 0);
480
437
  }
481
438
 
482
439
  void
@@ -55,9 +55,15 @@ module ActiveSupport
55
55
  options[:default_ttl] ||= options.delete(:expires_in)
56
56
  options[:default_format] ||= :marshal
57
57
  options[:key_prefix] ||= options.delete(:namespace)
58
+ options[:connection_pool] ||= options.delete(:connection_pool)
58
59
  args.push(options)
59
- @data = ::Couchbase::Bucket.new(*args)
60
- @lock = Monitor.new
60
+
61
+ if options[:connection_pool]
62
+ @data = ::Couchbase::ConnectionPool.new(options[:connection_pool], *args)
63
+ else
64
+ @data = ::Couchbase::Bucket.new(*args)
65
+ @data.extend(Threadsafe)
66
+ end
61
67
  end
62
68
 
63
69
  # Fetches data from the cache, using the given key.
@@ -184,9 +190,7 @@ module ActiveSupport
184
190
  options[:format] = :plain
185
191
  end
186
192
  instrument(:read_multi, names, options) do
187
- @lock.synchronize do
188
- @data.get(names, options)
189
- end
193
+ @data.get(names, options)
190
194
  end
191
195
  rescue ::Couchbase::Error::Base => e
192
196
  logger.error("#{e.class}: #{e.message}") if logger
@@ -247,9 +251,7 @@ module ActiveSupport
247
251
  options[:create] = true
248
252
  instrument(:increment, name, options) do |payload|
249
253
  payload[:amount] = amount if payload
250
- @lock.synchronize do
251
- @data.incr(name, amount, options)
252
- end
254
+ @data.incr(name, amount, options)
253
255
  end
254
256
  rescue ::Couchbase::Error::Base => e
255
257
  logger.error("#{e.class}: #{e.message}") if logger
@@ -281,9 +283,7 @@ module ActiveSupport
281
283
  options[:create] = true
282
284
  instrument(:decrement, name, options) do |payload|
283
285
  payload[:amount] = amount if payload
284
- @lock.synchronize do
285
- @data.decr(name, amount, options)
286
- end
286
+ @data.decr(name, amount, options)
287
287
  end
288
288
  rescue ::Couchbase::Error::Base => e
289
289
  logger.error("#{e.class}: #{e.message}") if logger
@@ -297,18 +297,14 @@ module ActiveSupport
297
297
  #
298
298
  # @return [Hash]
299
299
  def stats(*arg)
300
- @lock.synchronize do
301
- @data.stats(*arg)
302
- end
300
+ @data.stats(*arg)
303
301
  end
304
302
 
305
303
  protected
306
304
 
307
305
  # Read an entry from the cache.
308
306
  def read_entry(key, options) # :nodoc:
309
- @lock.synchronize do
310
- @data.get(key, options)
311
- end
307
+ @data.get(key, options)
312
308
  rescue ::Couchbase::Error::Base => e
313
309
  logger.error("#{e.class}: #{e.message}") if logger
314
310
  raise if @raise_errors
@@ -325,9 +321,7 @@ module ActiveSupport
325
321
  if ttl = options.delete(:expires_in)
326
322
  options[:ttl] ||= ttl
327
323
  end
328
- @lock.synchronize do
329
- @data.send(method, key, value, options)
330
- end
324
+ @data.send(method, key, value, options)
331
325
  rescue ::Couchbase::Error::Base => e
332
326
  logger.error("#{e.class}: #{e.message}") if logger
333
327
  raise if @raise_errors
@@ -336,9 +330,7 @@ module ActiveSupport
336
330
 
337
331
  # Delete an entry from the cache.
338
332
  def delete_entry(key, options) # :nodoc:
339
- @lock.synchronize do
340
- @data.delete(key, options)
341
- end
333
+ @data.delete(key, options)
342
334
  rescue ::Couchbase::Error::Base => e
343
335
  logger.error("#{e.class}: #{e.message}") if logger
344
336
  raise if @raise_errors
@@ -367,6 +359,51 @@ module ActiveSupport
367
359
  key.respond_to?(:to_param) ? key.to_param : key
368
360
  end
369
361
 
362
+ module Threadsafe
363
+ def self.extended(obj)
364
+ obj.init_threadsafe
365
+ end
366
+
367
+ def get(*)
368
+ @lock.synchronize do
369
+ super
370
+ end
371
+ end
372
+
373
+ def send(*)
374
+ @lock.synchronize do
375
+ super
376
+ end
377
+ end
378
+
379
+ def delete(*)
380
+ @lock.synchronize do
381
+ super
382
+ end
383
+ end
384
+
385
+ def incr(*)
386
+ @lock.synchronize do
387
+ super
388
+ end
389
+ end
390
+
391
+ def decr(*)
392
+ @lock.synchronize do
393
+ super
394
+ end
395
+ end
396
+
397
+ def stats(*)
398
+ @lock.synchronize do
399
+ super
400
+ end
401
+ end
402
+
403
+ def init_threadsafe
404
+ @lock = Monitor.new
405
+ end
406
+ end
370
407
  end
371
408
  end
372
409
  end