jmoses-couchbase 1.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.gitignore +15 -0
  2. data/.travis.yml +22 -0
  3. data/.yardopts +5 -0
  4. data/CONTRIBUTING.markdown +75 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +201 -0
  7. data/Makefile +3 -0
  8. data/README.markdown +665 -0
  9. data/RELEASE_NOTES.markdown +819 -0
  10. data/Rakefile +20 -0
  11. data/couchbase.gemspec +49 -0
  12. data/examples/chat-em/Gemfile +7 -0
  13. data/examples/chat-em/README.markdown +45 -0
  14. data/examples/chat-em/server.rb +82 -0
  15. data/examples/chat-goliath-grape/Gemfile +5 -0
  16. data/examples/chat-goliath-grape/README.markdown +50 -0
  17. data/examples/chat-goliath-grape/app.rb +67 -0
  18. data/examples/chat-goliath-grape/config/app.rb +20 -0
  19. data/examples/transcoders/Gemfile +3 -0
  20. data/examples/transcoders/README.markdown +59 -0
  21. data/examples/transcoders/cb-zcat +40 -0
  22. data/examples/transcoders/cb-zcp +45 -0
  23. data/examples/transcoders/gzip_transcoder.rb +49 -0
  24. data/examples/transcoders/options.rb +54 -0
  25. data/ext/couchbase_ext/.gitignore +4 -0
  26. data/ext/couchbase_ext/arguments.c +956 -0
  27. data/ext/couchbase_ext/arithmetic.c +316 -0
  28. data/ext/couchbase_ext/bucket.c +1373 -0
  29. data/ext/couchbase_ext/context.c +65 -0
  30. data/ext/couchbase_ext/couchbase_ext.c +1364 -0
  31. data/ext/couchbase_ext/couchbase_ext.h +644 -0
  32. data/ext/couchbase_ext/delete.c +163 -0
  33. data/ext/couchbase_ext/eventmachine_plugin.c +452 -0
  34. data/ext/couchbase_ext/extconf.rb +169 -0
  35. data/ext/couchbase_ext/get.c +316 -0
  36. data/ext/couchbase_ext/gethrtime.c +129 -0
  37. data/ext/couchbase_ext/http.c +432 -0
  38. data/ext/couchbase_ext/multithread_plugin.c +1090 -0
  39. data/ext/couchbase_ext/observe.c +171 -0
  40. data/ext/couchbase_ext/plugin_common.c +171 -0
  41. data/ext/couchbase_ext/result.c +129 -0
  42. data/ext/couchbase_ext/stats.c +163 -0
  43. data/ext/couchbase_ext/store.c +542 -0
  44. data/ext/couchbase_ext/timer.c +192 -0
  45. data/ext/couchbase_ext/touch.c +186 -0
  46. data/ext/couchbase_ext/unlock.c +176 -0
  47. data/ext/couchbase_ext/utils.c +551 -0
  48. data/ext/couchbase_ext/version.c +142 -0
  49. data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
  50. data/lib/active_support/cache/couchbase_store.rb +430 -0
  51. data/lib/couchbase.rb +155 -0
  52. data/lib/couchbase/bucket.rb +457 -0
  53. data/lib/couchbase/cluster.rb +119 -0
  54. data/lib/couchbase/connection_pool.rb +58 -0
  55. data/lib/couchbase/constants.rb +12 -0
  56. data/lib/couchbase/result.rb +26 -0
  57. data/lib/couchbase/transcoder.rb +120 -0
  58. data/lib/couchbase/utils.rb +62 -0
  59. data/lib/couchbase/version.rb +21 -0
  60. data/lib/couchbase/view.rb +506 -0
  61. data/lib/couchbase/view_row.rb +272 -0
  62. data/lib/ext/multi_json_fix.rb +56 -0
  63. data/lib/rack/session/couchbase.rb +108 -0
  64. data/tasks/benchmark.rake +6 -0
  65. data/tasks/compile.rake +160 -0
  66. data/tasks/test.rake +100 -0
  67. data/tasks/util.rake +21 -0
  68. data/test/profile/.gitignore +1 -0
  69. data/test/profile/Gemfile +6 -0
  70. data/test/profile/benchmark.rb +195 -0
  71. data/test/setup.rb +178 -0
  72. data/test/test_arithmetic.rb +185 -0
  73. data/test/test_async.rb +316 -0
  74. data/test/test_bucket.rb +276 -0
  75. data/test/test_cas.rb +235 -0
  76. data/test/test_couchbase.rb +77 -0
  77. data/test/test_couchbase_connection_pool.rb +77 -0
  78. data/test/test_couchbase_rails_cache_store.rb +361 -0
  79. data/test/test_delete.rb +120 -0
  80. data/test/test_errors.rb +82 -0
  81. data/test/test_eventmachine.rb +70 -0
  82. data/test/test_format.rb +164 -0
  83. data/test/test_get.rb +407 -0
  84. data/test/test_stats.rb +57 -0
  85. data/test/test_store.rb +216 -0
  86. data/test/test_timer.rb +42 -0
  87. data/test/test_touch.rb +97 -0
  88. data/test/test_unlock.rb +119 -0
  89. data/test/test_utils.rb +58 -0
  90. data/test/test_version.rb +52 -0
  91. metadata +353 -0
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby
2
+ # Author:: Couchbase <info@couchbase.com>
3
+ # Copyright:: 2013 Couchbase, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'bundler'
20
+ Bundler.setup
21
+
22
+ require 'couchbase'
23
+
24
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
25
+ require 'gzip_transcoder'
26
+ require 'options'
27
+
28
+ STDERR.puts "Run with arguments: #{OPTIONS.inspect}"
29
+ begin
30
+ conn = Couchbase.connect(OPTIONS)
31
+ conn.transcoder = GzipTranscoder.new
32
+
33
+ ARGV.each do |filename|
34
+ STDERR.print "store \"#{filename}\" ... "
35
+ if File.exists?(filename)
36
+ conn.set(filename, File.read(filename))
37
+ STDERR.puts "ok"
38
+ else
39
+ STDERR.puts "not found"
40
+ end
41
+ end
42
+ rescue Couchbase::Error::Base => ex
43
+ STDERR.puts "ERROR: #{ex}"
44
+ exit 1
45
+ end
@@ -0,0 +1,49 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2013 Couchbase, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'zlib'
19
+ require 'stringio'
20
+
21
+ # This class wraps any other transcoder and performs compression
22
+ # using zlib
23
+ class GzipTranscoder
24
+ FMT_GZIP = 0x04
25
+
26
+ def initialize(base = nil)
27
+ @base = base || Couchbase::Transcoder::Plain
28
+ end
29
+
30
+ def dump(obj, flags, options = {})
31
+ obj, flags = @base.dump(obj, flags, options)
32
+ io = StringIO.new
33
+ gz = Zlib::GzipWriter.new(io)
34
+ gz.write(obj)
35
+ gz.close
36
+ [io.string, flags|FMT_GZIP]
37
+ end
38
+
39
+ def load(blob, flags, options = {})
40
+ # decompress value only if gzip flag set
41
+ if (flags & FMT_GZIP) == FMT_GZIP
42
+ io = StringIO.new(blob)
43
+ gz = Zlib::GzipReader.new(io)
44
+ blob = gz.read
45
+ gz.close
46
+ end
47
+ @base.load(blob, flags, options)
48
+ end
49
+ end
@@ -0,0 +1,54 @@
1
+ # Author:: Couchbase <info@couchbase.com>
2
+ # Copyright:: 2013 Couchbase, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'optparse'
19
+
20
+ # just output extra empty line on CTRL-C
21
+ trap("INT") do
22
+ STDERR.puts
23
+ exit
24
+ end
25
+
26
+ OPTIONS = {
27
+ :bucket => "default",
28
+ :hostname => "127.0.0.1",
29
+ :port => 8091,
30
+ :username => nil,
31
+ :password => nil
32
+ }
33
+
34
+ OptionParser.new do |opts|
35
+ opts.banner = "Usage: #{$0} [options] keys"
36
+ opts.on("-h", "--hostname HOSTNAME", "Hostname to connect to (default: #{OPTIONS[:hostname]}:#{OPTIONS[:port]})") do |v|
37
+ host, port = v.split(':')
38
+ OPTIONS[:hostname] = host.empty? ? '127.0.0.1' : host
39
+ OPTIONS[:port] = port.to_i > 0 ? port.to_i : 8091
40
+ end
41
+ opts.on("-u", "--user USERNAME", "Username to log with (default: none)") do |v|
42
+ OPTIONS[:username] = v
43
+ end
44
+ opts.on("-p", "--password PASSWORD", "Password to log with (default: none)") do |v|
45
+ OPTIONS[:password] = v
46
+ end
47
+ opts.on("-b", "--bucket NAME", "Name of the bucket to connect to (default: #{OPTIONS[:bucket]})") do |v|
48
+ OPTIONS[:bucket] = v
49
+ end
50
+ opts.on_tail("-?", "--help", "Show this message") do
51
+ STDERR.puts opts
52
+ exit
53
+ end
54
+ end.parse!
@@ -0,0 +1,4 @@
1
+ *.log
2
+ *.o
3
+ Makefile
4
+ couchbase_config.h
@@ -0,0 +1,956 @@
1
+ /* vim: ft=c et ts=8 sts=4 sw=4 cino=
2
+ *
3
+ * Copyright 2011, 2012 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+
18
+ #include "couchbase_ext.h"
19
+
20
+ #define _alloc_data_for_s(type, _type, size, items, ptr) do {\
21
+ lcb_size_t ii; \
22
+ \
23
+ params->cmd.type.num = size; \
24
+ params->cmd.type.items = calloc(size, sizeof(_type)); \
25
+ if (params->cmd.type.items == NULL) { \
26
+ rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for arguments"); \
27
+ } \
28
+ params->cmd.type.ptr = calloc(size, sizeof(_type *)); \
29
+ if (params->cmd.type.ptr == NULL) { \
30
+ rb_raise(cb_eClientNoMemoryError, "failed to allocate memory for arguments"); \
31
+ } \
32
+ for (ii = 0; ii < size; ++ii) { \
33
+ params->cmd.type.ptr[ii] = params->cmd.type.items + ii; \
34
+ } \
35
+ } while(0)
36
+
37
+ #define _alloc_data_for(type, _type) _alloc_data_for_s(type, _type, size, items, ptr)
38
+
39
+
40
+ #define _release_data_for_s(type, items, ptr) \
41
+ free(params->cmd.type.items); \
42
+ free(params->cmd.type.ptr);
43
+
44
+ #define _release_data_for(type) _release_data_for_s(type, items, ptr)
45
+
46
+ static VALUE
47
+ get_transcoder(struct cb_bucket_st *bucket, VALUE override, int compat, VALUE opts)
48
+ {
49
+ VALUE ret = Qundef;
50
+
51
+ /* override with symbol */
52
+ if (TYPE(override) == T_SYMBOL) {
53
+ if (override == cb_sym_document) {
54
+ ret = cb_mDocument;
55
+ } else if (override == cb_sym_marshal) {
56
+ ret = cb_mMarshal;
57
+ } else if (override == cb_sym_plain) {
58
+ ret = cb_mPlain;
59
+ }
60
+ } else if (!compat) {
61
+ /* override with transcoder */
62
+ if (rb_respond_to(override, cb_id_dump)
63
+ && rb_respond_to(override, cb_id_load)) {
64
+ ret = override;
65
+ }
66
+ /* nil is also valid */
67
+ if (NIL_P(override)) {
68
+ ret = Qnil;
69
+ }
70
+ }
71
+ if (ret == Qundef) {
72
+ return bucket->transcoder;
73
+ } else {
74
+ rb_hash_aset(opts, cb_sym_forced, Qtrue);
75
+ return ret;
76
+ }
77
+ }
78
+
79
+ /* TOUCH */
80
+
81
+ static void
82
+ cb_params_touch_alloc(struct cb_params_st *params, lcb_size_t size)
83
+ {
84
+ _alloc_data_for(touch, lcb_touch_cmd_t);
85
+ }
86
+
87
+ static void
88
+ cb_params_touch_init_item(struct cb_params_st *params, lcb_size_t idx, VALUE key_obj, lcb_time_t exptime)
89
+ {
90
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
91
+ rb_ary_push(params->ensurance, key_obj);
92
+ params->cmd.touch.items[idx].v.v0.key = RSTRING_PTR(key_obj);
93
+ params->cmd.touch.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
94
+ params->cmd.touch.items[idx].v.v0.exptime = exptime;
95
+ params->npayload += RSTRING_LEN(key_obj) + sizeof(exptime);
96
+ }
97
+
98
+ static int
99
+ cb_params_touch_extract_keys_i(VALUE key, VALUE value, VALUE arg)
100
+ {
101
+ struct cb_params_st *params = (struct cb_params_st *)arg;
102
+ cb_params_touch_init_item(params, params->idx++, key, NUM2ULONG(value));
103
+ return ST_CONTINUE;
104
+ }
105
+
106
+ static void
107
+ cb_params_touch_parse_options(struct cb_params_st *params, VALUE options)
108
+ {
109
+ VALUE tmp;
110
+
111
+ if (NIL_P(options)) {
112
+ return;
113
+ }
114
+ tmp = rb_hash_aref(options, cb_sym_ttl);
115
+ if (tmp != Qnil) {
116
+ params->cmd.touch.ttl = NUM2ULONG(tmp);
117
+ }
118
+ tmp = rb_hash_lookup2(options, cb_sym_quiet, Qundef);
119
+ if (tmp != Qundef) {
120
+ params->cmd.touch.quiet = RTEST(tmp);
121
+ }
122
+ }
123
+
124
+ static void
125
+ cb_params_touch_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
126
+ {
127
+ lcb_size_t ii;
128
+
129
+ if (argc < 1) {
130
+ rb_raise(rb_eArgError, "must be at least one key");
131
+ }
132
+ if (argc == 1) {
133
+ VALUE keys = rb_ary_entry(argv, 0);
134
+ switch(TYPE(keys)) {
135
+ case T_ARRAY:
136
+ /* array of keys as a first argument */
137
+ params->cmd.touch.array = 1;
138
+ cb_params_touch_alloc(params, RARRAY_LEN(keys));
139
+ for (ii = 0; ii < params->cmd.touch.num; ++ii) {
140
+ cb_params_touch_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.touch.ttl);
141
+ }
142
+ break;
143
+ case T_HASH:
144
+ /* key-ttl pairs */
145
+ cb_params_touch_alloc(params, RHASH_SIZE(keys));
146
+ rb_hash_foreach(keys, cb_params_touch_extract_keys_i,
147
+ (VALUE)params);
148
+ break;
149
+ default:
150
+ /* single key */
151
+ cb_params_touch_alloc(params, 1);
152
+ cb_params_touch_init_item(params, 0, keys, params->cmd.touch.ttl);
153
+ }
154
+ } else {
155
+ /* just list of arguments */
156
+ cb_params_touch_alloc(params, argc);
157
+ for (ii = 0; ii < params->cmd.touch.num; ++ii) {
158
+ cb_params_touch_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.touch.ttl);
159
+ }
160
+ }
161
+ }
162
+
163
+
164
+ /* REMOVE */
165
+
166
+ static void
167
+ cb_params_remove_alloc(struct cb_params_st *params, lcb_size_t size)
168
+ {
169
+ _alloc_data_for(remove, lcb_remove_cmd_t);
170
+ }
171
+
172
+ static void
173
+ cb_params_remove_init_item(struct cb_params_st *params, lcb_size_t idx, VALUE key_obj, lcb_cas_t cas)
174
+ {
175
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
176
+ rb_ary_push(params->ensurance, key_obj);
177
+ params->cmd.remove.items[idx].v.v0.key = RSTRING_PTR(key_obj);
178
+ params->cmd.remove.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
179
+ params->cmd.remove.items[idx].v.v0.cas = cas;
180
+ params->npayload += RSTRING_LEN(key_obj);
181
+ }
182
+
183
+ static int
184
+ cb_params_remove_extract_keys_i(VALUE key, VALUE value, VALUE arg)
185
+ {
186
+ struct cb_params_st *params = (struct cb_params_st *)arg;
187
+ cb_params_remove_init_item(params, params->idx++, key, NUM2ULL(value));
188
+ return ST_CONTINUE;
189
+ }
190
+
191
+ static void
192
+ cb_params_remove_parse_options(struct cb_params_st *params, VALUE options)
193
+ {
194
+ VALUE tmp;
195
+
196
+ if (NIL_P(options)) {
197
+ return;
198
+ }
199
+ tmp = rb_hash_lookup2(options, cb_sym_quiet, Qundef);
200
+ if (tmp != Qundef) {
201
+ params->cmd.remove.quiet = RTEST(tmp);
202
+ }
203
+ tmp = rb_hash_aref(options, cb_sym_cas);
204
+ if (tmp != Qnil) {
205
+ params->cmd.remove.cas = NUM2ULL(tmp);
206
+ }
207
+ }
208
+
209
+ static void
210
+ cb_params_remove_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
211
+ {
212
+ lcb_size_t ii;
213
+
214
+ if (argc < 1) {
215
+ rb_raise(rb_eArgError, "must be at least one key");
216
+ }
217
+ if (argc == 1) {
218
+ VALUE keys = rb_ary_entry(argv, 0);
219
+ switch(TYPE(keys)) {
220
+ case T_ARRAY:
221
+ /* array of keys as a first argument */
222
+ params->cmd.remove.array = 1;
223
+ cb_params_remove_alloc(params, RARRAY_LEN(keys));
224
+ for (ii = 0; ii < params->cmd.remove.num; ++ii) {
225
+ cb_params_remove_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.remove.cas);
226
+ }
227
+ break;
228
+ case T_HASH:
229
+ /* key-cas pairs */
230
+ cb_params_remove_alloc(params, RHASH_SIZE(keys));
231
+ rb_hash_foreach(keys, cb_params_remove_extract_keys_i,
232
+ (VALUE)params);
233
+ break;
234
+ default:
235
+ /* single key */
236
+ cb_params_remove_alloc(params, 1);
237
+ cb_params_remove_init_item(params, 0, keys, params->cmd.remove.cas);
238
+ }
239
+ } else {
240
+ /* just list of arguments */
241
+ cb_params_remove_alloc(params, argc);
242
+ for (ii = 0; ii < params->cmd.remove.num; ++ii) {
243
+ cb_params_remove_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.remove.cas);
244
+ }
245
+ }
246
+ }
247
+
248
+
249
+ /* STORE */
250
+ static void
251
+ cb_params_store_alloc(struct cb_params_st *params, lcb_size_t size)
252
+ {
253
+ _alloc_data_for(store, lcb_store_cmd_t);
254
+ }
255
+
256
+ static void
257
+ cb_params_store_init_item(struct cb_params_st *params, lcb_size_t idx,
258
+ VALUE key_obj, VALUE value_obj, lcb_uint32_t flags, lcb_cas_t cas,
259
+ lcb_time_t exptime)
260
+ {
261
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
262
+ value_obj = cb_encode_value(params->cmd.store.transcoder, value_obj, &flags, params->cmd.store.transcoder_opts);
263
+ if (rb_obj_is_kind_of(value_obj, rb_eStandardError)) {
264
+ VALUE exc_str = rb_funcall(value_obj, cb_id_to_s, 0);
265
+ VALUE msg = rb_funcall(rb_mKernel, cb_id_sprintf, 3,
266
+ rb_str_new2("unable to convert value for key \"%s\": %s"), key_obj, exc_str);
267
+ VALUE exc = rb_exc_new3(cb_eValueFormatError, msg);
268
+ rb_ivar_set(exc, cb_id_iv_inner_exception, value_obj);
269
+ rb_exc_raise(exc);
270
+ }
271
+ /* the value must be string after conversion */
272
+ if (TYPE(value_obj) != T_STRING) {
273
+ VALUE val = rb_any_to_s(value_obj);
274
+ rb_raise(cb_eValueFormatError, "unable to convert value for key \"%s\" to string: %s", RSTRING_PTR(key_obj), RSTRING_PTR(val));
275
+ }
276
+ rb_ary_push(params->ensurance, key_obj);
277
+ rb_ary_push(params->ensurance, value_obj);
278
+ params->cmd.store.items[idx].v.v0.datatype = params->cmd.store.datatype;
279
+ params->cmd.store.items[idx].v.v0.operation = params->cmd.store.operation;
280
+ params->cmd.store.items[idx].v.v0.key = RSTRING_PTR(key_obj);
281
+ params->cmd.store.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
282
+ params->cmd.store.items[idx].v.v0.bytes = RSTRING_PTR(value_obj);
283
+ params->cmd.store.items[idx].v.v0.nbytes = RSTRING_LEN(value_obj);
284
+ params->cmd.store.items[idx].v.v0.flags = flags;
285
+ params->cmd.store.items[idx].v.v0.cas = cas;
286
+ params->cmd.store.items[idx].v.v0.exptime = exptime;
287
+ params->npayload += RSTRING_LEN(key_obj) + RSTRING_LEN(value_obj) + sizeof(flags) + sizeof(exptime);
288
+ }
289
+
290
+ static int
291
+ cb_params_store_extract_keys_i(VALUE key, VALUE value, VALUE arg)
292
+ {
293
+ struct cb_params_st *params = (struct cb_params_st *)arg;
294
+ cb_params_store_init_item(params, params->idx++, key, value,
295
+ params->cmd.store.flags, 0, params->cmd.store.ttl);
296
+ return ST_CONTINUE;
297
+ }
298
+
299
+ static void
300
+ cb_params_store_parse_options(struct cb_params_st *params, VALUE options)
301
+ {
302
+ VALUE tmp;
303
+
304
+ if (NIL_P(options)) {
305
+ return;
306
+ }
307
+ tmp = rb_hash_aref(options, cb_sym_flags);
308
+ if (tmp != Qnil) {
309
+ params->cmd.store.flags = (lcb_uint32_t)NUM2ULONG(tmp);
310
+ }
311
+ tmp = rb_hash_aref(options, cb_sym_ttl);
312
+ if (tmp != Qnil) {
313
+ params->cmd.store.ttl = NUM2ULONG(tmp);
314
+ }
315
+ tmp = rb_hash_aref(options, cb_sym_cas);
316
+ if (tmp != Qnil) {
317
+ params->cmd.store.cas = NUM2ULL(tmp);
318
+ }
319
+ tmp = rb_hash_aref(options, cb_sym_observe);
320
+ if (tmp != Qnil) {
321
+ Check_Type(tmp, T_HASH);
322
+ rb_funcall(params->bucket->self, cb_id_verify_observe_options, 1, tmp);
323
+ params->cmd.store.observe = tmp;
324
+ }
325
+ tmp = rb_hash_aref(options, cb_sym_format);
326
+ if (tmp != Qnil) {
327
+ params->cmd.store.transcoder = get_transcoder(params->bucket,
328
+ tmp, 1, params->cmd.store.transcoder_opts);
329
+ }
330
+ tmp = rb_hash_lookup2(options, cb_sym_transcoder, Qundef);
331
+ if (tmp != Qundef) {
332
+ params->cmd.store.transcoder = get_transcoder(params->bucket,
333
+ tmp, 0, params->cmd.store.transcoder_opts);
334
+ }
335
+ }
336
+
337
+ static void
338
+ cb_params_store_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
339
+ {
340
+ VALUE keys;
341
+
342
+ if (argc < 1) {
343
+ rb_raise(rb_eArgError, "the key and value must be specified");
344
+ }
345
+ switch (argc) {
346
+ case 1:
347
+ keys = rb_ary_entry(argv, 0);
348
+ switch(TYPE(keys)) {
349
+ case T_HASH:
350
+ /* key-value pairs */
351
+ cb_params_store_alloc(params, RHASH_SIZE(keys));
352
+ rb_hash_foreach(keys, cb_params_store_extract_keys_i,
353
+ (VALUE)params);
354
+ break;
355
+ default:
356
+ rb_raise(rb_eArgError, "there must be either Hash with key-value pairs"
357
+ " or two separate arguments: key and value");
358
+ }
359
+ break;
360
+ case 2:
361
+ /* just key and value */
362
+ cb_params_store_alloc(params, 1);
363
+ cb_params_store_init_item(params, 0, rb_ary_entry(argv, 0), rb_ary_entry(argv, 1),
364
+ params->cmd.store.flags, params->cmd.store.cas, params->cmd.store.ttl);
365
+ break;
366
+ default:
367
+ rb_raise(rb_eArgError, "too many arguments");
368
+ }
369
+ }
370
+
371
+
372
+ /* GET */
373
+ static void
374
+ cb_params_get_alloc(struct cb_params_st *params, lcb_size_t size)
375
+ {
376
+ if (RTEST(params->cmd.get.replica)) {
377
+ _alloc_data_for_s(get, lcb_get_replica_cmd_t, size, items_gr, ptr_gr);
378
+ } else {
379
+ _alloc_data_for(get, lcb_get_cmd_t);
380
+ }
381
+ }
382
+
383
+ static void
384
+ cb_params_get_init_item(struct cb_params_st *params, lcb_size_t idx,
385
+ VALUE key_obj, lcb_time_t exptime)
386
+ {
387
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
388
+ rb_ary_push(params->ensurance, key_obj);
389
+ if (RTEST(params->cmd.get.replica)) {
390
+ params->cmd.get.items_gr[idx].version = 1;
391
+ params->cmd.get.items_gr[idx].v.v1.key = RSTRING_PTR(key_obj);
392
+ params->cmd.get.items_gr[idx].v.v1.nkey = RSTRING_LEN(key_obj);
393
+ if (params->cmd.get.replica == cb_sym_first || params->cmd.get.replica == Qtrue) {
394
+ params->cmd.get.items_gr[idx].v.v1.strategy = LCB_REPLICA_FIRST;
395
+ } else if (params->cmd.get.replica == cb_sym_all) {
396
+ params->cmd.get.items_gr[idx].v.v1.strategy = LCB_REPLICA_ALL;
397
+ } else {
398
+ params->cmd.get.items_gr[idx].v.v1.strategy = LCB_REPLICA_SELECT;
399
+ params->cmd.get.items_gr[idx].v.v1.index = FIX2INT(params->cmd.get.replica);
400
+ }
401
+ } else {
402
+ params->cmd.get.items[idx].v.v0.key = RSTRING_PTR(key_obj);
403
+ params->cmd.get.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
404
+ params->cmd.get.items[idx].v.v0.exptime = exptime;
405
+ params->cmd.get.items[idx].v.v0.lock = params->cmd.get.lock;
406
+ params->npayload += sizeof(exptime);
407
+ }
408
+ params->npayload += RSTRING_LEN(key_obj);
409
+ }
410
+
411
+ static int
412
+ cb_params_get_extract_keys_i(VALUE key, VALUE value, VALUE arg)
413
+ {
414
+ struct cb_params_st *params = (struct cb_params_st *)arg;
415
+ rb_ary_push(params->cmd.get.keys_ary, key);
416
+ cb_params_get_init_item(params, params->idx++, key, NUM2ULONG(value));
417
+ return ST_CONTINUE;
418
+ }
419
+
420
+ static void
421
+ cb_params_get_parse_options(struct cb_params_st *params, VALUE options)
422
+ {
423
+ VALUE tmp;
424
+
425
+ if (NIL_P(options)) {
426
+ return;
427
+ }
428
+ tmp = rb_hash_aref(options, cb_sym_replica);
429
+ if (tmp == Qtrue || tmp == cb_sym_all || tmp == cb_sym_first) {
430
+ params->cmd.get.replica = tmp;
431
+ } else if (TYPE(tmp) == T_FIXNUM) {
432
+ int nr = NUM2INT(tmp);
433
+ int max = lcb_get_num_replicas(params->bucket->handle);
434
+ if (nr < 0 || nr >= max) {
435
+ rb_raise(rb_eArgError, "replica index should be in interval 0...%d", max);
436
+ }
437
+ params->cmd.get.replica = tmp;
438
+ }
439
+ params->cmd.get.extended = RTEST(rb_hash_aref(options, cb_sym_extended));
440
+ params->cmd.get.assemble_hash = RTEST(rb_hash_aref(options, cb_sym_assemble_hash));
441
+ tmp = rb_hash_lookup2(options, cb_sym_quiet, Qundef);
442
+ if (tmp != Qundef) {
443
+ params->cmd.get.quiet = RTEST(tmp);
444
+ }
445
+ tmp = rb_hash_aref(options, cb_sym_format);
446
+ if (tmp != Qnil) {
447
+ params->cmd.get.transcoder = get_transcoder(params->bucket,
448
+ tmp, 1, params->cmd.get.transcoder_opts);
449
+ }
450
+ tmp = rb_hash_lookup2(options, cb_sym_transcoder, Qundef);
451
+ if (tmp != Qundef) {
452
+ params->cmd.get.transcoder = get_transcoder(params->bucket,
453
+ tmp, 0, params->cmd.get.transcoder_opts);
454
+ }
455
+ tmp = rb_hash_aref(options, cb_sym_ttl);
456
+ if (tmp != Qnil) {
457
+ params->cmd.get.ttl = NUM2ULONG(tmp);
458
+ }
459
+ /* boolean or number of seconds to lock */
460
+ tmp = rb_hash_aref(options, cb_sym_lock);
461
+ if (tmp != Qnil) {
462
+ params->cmd.get.lock = RTEST(tmp);
463
+ if (TYPE(tmp) == T_FIXNUM) {
464
+ params->cmd.get.ttl = NUM2ULONG(tmp);
465
+ }
466
+ }
467
+ }
468
+
469
+ static void
470
+ cb_params_get_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
471
+ {
472
+ lcb_size_t ii;
473
+
474
+ if (argc < 1) {
475
+ rb_raise(rb_eArgError, "must be at least one key");
476
+ }
477
+ if (argc == 1) {
478
+ VALUE keys = rb_ary_entry(argv, 0);
479
+ switch(TYPE(keys)) {
480
+ case T_ARRAY:
481
+ /* array of keys as a first argument */
482
+ params->cmd.get.array = 1;
483
+ cb_params_get_alloc(params, RARRAY_LEN(keys));
484
+ for (ii = 0; ii < params->cmd.get.num; ++ii) {
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
+ }
488
+ break;
489
+ case T_HASH:
490
+ /* key-ttl pairs */
491
+ if (params->cmd.get.replica) {
492
+ rb_raise(rb_eArgError, "must be either list of key or single key");
493
+ }
494
+ params->cmd.get.gat = 1;
495
+ cb_params_get_alloc(params, RHASH_SIZE(keys));
496
+ rb_hash_foreach(keys, cb_params_get_extract_keys_i, (VALUE)params);
497
+ break;
498
+ default:
499
+ /* single key */
500
+ cb_params_get_alloc(params, 1);
501
+ rb_ary_push(params->cmd.get.keys_ary, keys);
502
+ cb_params_get_init_item(params, 0, keys, params->cmd.get.ttl);
503
+ }
504
+ } else {
505
+ /* just list of arguments */
506
+ cb_params_get_alloc(params, argc);
507
+ for (ii = 0; ii < params->cmd.get.num; ++ii) {
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
+ }
511
+ }
512
+ }
513
+
514
+
515
+ /* ARITH */
516
+ static void
517
+ cb_params_arith_alloc(struct cb_params_st *params, lcb_size_t size)
518
+ {
519
+ _alloc_data_for(arith, lcb_arithmetic_cmd_t);
520
+ }
521
+
522
+ static void
523
+ cb_params_arith_init_item(struct cb_params_st *params, lcb_size_t idx,
524
+ VALUE key_obj, lcb_int64_t delta)
525
+ {
526
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
527
+ rb_ary_push(params->ensurance, key_obj);
528
+ params->cmd.arith.items[idx].v.v0.key = RSTRING_PTR(key_obj);
529
+ params->cmd.arith.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
530
+ params->cmd.arith.items[idx].v.v0.delta = delta * params->cmd.arith.sign;
531
+ params->cmd.arith.items[idx].v.v0.exptime = params->cmd.arith.ttl;
532
+ params->cmd.arith.items[idx].v.v0.create = params->cmd.arith.create;
533
+ params->cmd.arith.items[idx].v.v0.initial = params->cmd.arith.initial;
534
+ params->npayload += RSTRING_LEN(key_obj);
535
+ }
536
+
537
+ static int
538
+ cb_params_arith_extract_keys_i(VALUE key, VALUE value, VALUE arg)
539
+ {
540
+ struct cb_params_st *params = (struct cb_params_st *)arg;
541
+ cb_params_arith_init_item(params, params->idx++, key, NUM2ULONG(value) & INT64_MAX);
542
+ return ST_CONTINUE;
543
+ }
544
+
545
+ static void
546
+ cb_params_arith_parse_options(struct cb_params_st *params, VALUE options)
547
+ {
548
+ VALUE tmp;
549
+
550
+ if (NIL_P(options)) {
551
+ return;
552
+ }
553
+ tmp = rb_hash_aref(options, cb_sym_create);
554
+ if (tmp != Qnil) {
555
+ params->cmd.arith.create = RTEST(tmp);
556
+ }
557
+ params->cmd.arith.extended = RTEST(rb_hash_aref(options, cb_sym_extended));
558
+ tmp = rb_hash_aref(options, cb_sym_ttl);
559
+ if (tmp != Qnil) {
560
+ params->cmd.arith.ttl = NUM2ULONG(tmp);
561
+ }
562
+ tmp = rb_hash_aref(options, cb_sym_initial);
563
+ if (tmp != Qnil) {
564
+ params->cmd.arith.initial = NUM2ULL(tmp);
565
+ params->cmd.arith.create = 1;
566
+ }
567
+ tmp = rb_hash_aref(options, cb_sym_delta);
568
+ if (tmp != Qnil) {
569
+ params->cmd.arith.delta = NUM2ULL(tmp) & INT64_MAX;
570
+ }
571
+ tmp = rb_hash_aref(options, cb_sym_format);
572
+ if (tmp != Qnil) {
573
+ params->cmd.arith.transcoder = get_transcoder(params->bucket,
574
+ tmp, 1, params->cmd.arith.transcoder_opts);
575
+ }
576
+ tmp = rb_hash_lookup2(options, cb_sym_transcoder, Qundef);
577
+ if (tmp != Qundef) {
578
+ params->cmd.arith.transcoder = get_transcoder(params->bucket,
579
+ tmp, 0, params->cmd.arith.transcoder_opts);
580
+ }
581
+ }
582
+
583
+ static void
584
+ cb_params_arith_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
585
+ {
586
+ lcb_size_t ii;
587
+
588
+ if (argc < 1) {
589
+ rb_raise(rb_eArgError, "must be at least one key");
590
+ }
591
+ if (argc == 1) {
592
+ VALUE keys = rb_ary_entry(argv, 0);
593
+ switch(TYPE(keys)) {
594
+ case T_ARRAY:
595
+ /* array of keys as a first argument */
596
+ params->cmd.arith.array = 1;
597
+ cb_params_arith_alloc(params, RARRAY_LEN(keys));
598
+ for (ii = 0; ii < params->cmd.arith.num; ++ii) {
599
+ cb_params_arith_init_item(params, ii, rb_ary_entry(keys, ii), params->cmd.arith.delta);
600
+ }
601
+ break;
602
+ case T_HASH:
603
+ /* key-delta pairs */
604
+ cb_params_arith_alloc(params, RHASH_SIZE(keys));
605
+ rb_hash_foreach(keys, cb_params_arith_extract_keys_i, (VALUE)params);
606
+ break;
607
+ default:
608
+ /* single key */
609
+ cb_params_arith_alloc(params, 1);
610
+ cb_params_arith_init_item(params, 0, keys, params->cmd.arith.delta);
611
+ }
612
+ } else {
613
+ /* just list of arguments */
614
+ cb_params_arith_alloc(params, argc);
615
+ for (ii = 0; ii < params->cmd.arith.num; ++ii) {
616
+ cb_params_arith_init_item(params, ii, rb_ary_entry(argv, ii), params->cmd.arith.delta);
617
+ }
618
+ }
619
+ }
620
+
621
+
622
+ /* STATS */
623
+ static void
624
+ cb_params_stats_alloc(struct cb_params_st *params, lcb_size_t size)
625
+ {
626
+ _alloc_data_for(stats, lcb_server_stats_cmd_t);
627
+ }
628
+
629
+ static void
630
+ cb_params_stats_init_item(struct cb_params_st *params, lcb_size_t idx,
631
+ VALUE key_obj)
632
+ {
633
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
634
+ rb_ary_push(params->ensurance, key_obj);
635
+ params->cmd.stats.items[idx].v.v0.name = RSTRING_PTR(key_obj);
636
+ params->cmd.stats.items[idx].v.v0.nname = RSTRING_LEN(key_obj);
637
+ params->npayload += RSTRING_LEN(key_obj);
638
+ }
639
+
640
+ static void
641
+ cb_params_stats_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
642
+ {
643
+ lcb_size_t ii;
644
+
645
+ if (argc == 1) {
646
+ VALUE keys = rb_ary_entry(argv, 0);
647
+ switch(TYPE(keys)) {
648
+ case T_ARRAY:
649
+ /* array of keys as a first argument */
650
+ params->cmd.stats.array = 1;
651
+ cb_params_stats_alloc(params, RARRAY_LEN(keys));
652
+ for (ii = 0; ii < params->cmd.stats.num; ++ii) {
653
+ cb_params_stats_init_item(params, ii, rb_ary_entry(keys, ii));
654
+ }
655
+ break;
656
+ default:
657
+ /* single key */
658
+ cb_params_stats_alloc(params, 1);
659
+ cb_params_stats_init_item(params, 0, keys);
660
+ }
661
+ } else if (argc == 0) {
662
+ /* stat without argument (single empty struct) */
663
+ cb_params_stats_alloc(params, 1);
664
+ } else {
665
+ /* just list of arguments */
666
+ cb_params_stats_alloc(params, argc);
667
+ for (ii = 0; ii < params->cmd.stats.num; ++ii) {
668
+ cb_params_stats_init_item(params, ii, rb_ary_entry(argv, ii));
669
+ }
670
+ }
671
+ }
672
+
673
+
674
+ /* REMOVE */
675
+
676
+ static void
677
+ cb_params_observe_alloc(struct cb_params_st *params, lcb_size_t size)
678
+ {
679
+ _alloc_data_for(observe, lcb_observe_cmd_t);
680
+ }
681
+
682
+ static void
683
+ cb_params_observe_init_item(struct cb_params_st *params, lcb_size_t idx, VALUE key_obj)
684
+ {
685
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
686
+ rb_ary_push(params->ensurance, key_obj);
687
+ params->cmd.observe.items[idx].v.v0.key = RSTRING_PTR(key_obj);
688
+ params->cmd.observe.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
689
+ params->npayload += RSTRING_LEN(key_obj);
690
+ }
691
+
692
+ static void
693
+ cb_params_observe_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
694
+ {
695
+ lcb_size_t ii;
696
+
697
+ if (argc < 1) {
698
+ rb_raise(rb_eArgError, "must be at least one key");
699
+ }
700
+ if (argc == 1) {
701
+ VALUE keys = rb_ary_entry(argv, 0);
702
+ switch(TYPE(keys)) {
703
+ case T_ARRAY:
704
+ /* array of keys as a first argument */
705
+ params->cmd.observe.array = 1;
706
+ cb_params_observe_alloc(params, RARRAY_LEN(keys));
707
+ for (ii = 0; ii < params->cmd.observe.num; ++ii) {
708
+ cb_params_observe_init_item(params, ii, rb_ary_entry(keys, ii));
709
+ }
710
+ break;
711
+ default:
712
+ /* single key */
713
+ cb_params_observe_alloc(params, 1);
714
+ cb_params_observe_init_item(params, 0, keys);
715
+ }
716
+ } else {
717
+ /* just list of arguments */
718
+ cb_params_observe_alloc(params, argc);
719
+ for (ii = 0; ii < params->cmd.observe.num; ++ii) {
720
+ cb_params_observe_init_item(params, ii, rb_ary_entry(argv, ii));
721
+ }
722
+ }
723
+ }
724
+
725
+
726
+ /* UNLOCK */
727
+ static void
728
+ cb_params_unlock_alloc(struct cb_params_st *params, lcb_size_t size)
729
+ {
730
+ _alloc_data_for(unlock, lcb_unlock_cmd_t);
731
+ }
732
+
733
+ static void
734
+ cb_params_unlock_init_item(struct cb_params_st *params, lcb_size_t idx, VALUE key_obj, lcb_cas_t cas)
735
+ {
736
+ key_obj = cb_unify_key(params->bucket, key_obj, 1);
737
+ rb_ary_push(params->ensurance, key_obj);
738
+ params->cmd.unlock.items[idx].v.v0.key = RSTRING_PTR(key_obj);
739
+ params->cmd.unlock.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
740
+ params->cmd.unlock.items[idx].v.v0.cas = cas;
741
+ params->npayload += RSTRING_LEN(key_obj);
742
+ }
743
+
744
+ static int
745
+ cb_params_unlock_extract_keys_i(VALUE key, VALUE value, VALUE arg)
746
+ {
747
+ struct cb_params_st *params = (struct cb_params_st *)arg;
748
+ cb_params_unlock_init_item(params, params->idx++, key, NUM2ULL(value));
749
+ return ST_CONTINUE;
750
+ }
751
+
752
+ static void
753
+ cb_params_unlock_parse_options(struct cb_params_st *params, VALUE options)
754
+ {
755
+ VALUE tmp;
756
+
757
+ if (NIL_P(options)) {
758
+ return;
759
+ }
760
+ tmp = rb_hash_aref(options, cb_sym_cas);
761
+ if (tmp != Qnil) {
762
+ params->cmd.unlock.cas = NUM2ULL(tmp);
763
+ }
764
+ tmp = rb_hash_lookup2(options, cb_sym_quiet, Qundef);
765
+ if (tmp != Qundef) {
766
+ params->cmd.unlock.quiet = RTEST(tmp);
767
+ }
768
+ }
769
+
770
+ static void
771
+ cb_params_unlock_parse_arguments(struct cb_params_st *params, int argc, VALUE argv)
772
+ {
773
+ if (argc == 1) {
774
+ VALUE keys = rb_ary_entry(argv, 0);
775
+ switch(TYPE(keys)) {
776
+ case T_HASH:
777
+ /* key-cas pairs */
778
+ cb_params_unlock_alloc(params, RHASH_SIZE(keys));
779
+ rb_hash_foreach(keys, cb_params_unlock_extract_keys_i, (VALUE)params);
780
+ break;
781
+ default:
782
+ /* single key */
783
+ cb_params_unlock_alloc(params, 1);
784
+ cb_params_unlock_init_item(params, 0, keys, params->cmd.unlock.cas);
785
+ }
786
+ } else {
787
+ rb_raise(rb_eArgError, "must be either Hash or single key with cas option");
788
+ }
789
+ }
790
+
791
+
792
+ /* VERSION */
793
+ static void
794
+ cb_params_version_alloc(struct cb_params_st *params)
795
+ {
796
+ params->cmd.version.num = 1;
797
+ _alloc_data_for_s(version, lcb_server_version_cmd_t, 1, items, ptr);
798
+ }
799
+
800
+
801
+ /* common stuff */
802
+ void
803
+ cb_params_destroy(struct cb_params_st *params)
804
+ {
805
+ rb_ary_clear(params->ensurance);
806
+ params->ensurance = Qfalse;
807
+ params->args = Qfalse;
808
+ switch (params->type) {
809
+ case cb_cmd_get:
810
+ _release_data_for(get);
811
+ _release_data_for_s(get, items_gr, ptr_gr);
812
+ break;
813
+ case cb_cmd_touch:
814
+ _release_data_for(touch);
815
+ break;
816
+ case cb_cmd_arith:
817
+ _release_data_for(arith);
818
+ break;
819
+ case cb_cmd_remove:
820
+ _release_data_for(remove);
821
+ break;
822
+ case cb_cmd_store:
823
+ _release_data_for(store);
824
+ break;
825
+ case cb_cmd_stats:
826
+ _release_data_for(stats);
827
+ break;
828
+ case cb_cmd_version:
829
+ _release_data_for(version);
830
+ break;
831
+ case cb_cmd_observe:
832
+ _release_data_for(observe);
833
+ break;
834
+ case cb_cmd_unlock:
835
+ _release_data_for(unlock);
836
+ break;
837
+ }
838
+ }
839
+
840
+ static VALUE
841
+ do_params_build(VALUE ptr)
842
+ {
843
+ VALUE opts;
844
+ /* unpack arguments */
845
+ struct cb_params_st *params = (struct cb_params_st*)ptr;
846
+ int argc = RARRAY_LEN(params->args);
847
+ VALUE argv = params->args;
848
+
849
+ /* extract options */
850
+ if (argc > 1 && TYPE(rb_ary_entry(argv, argc-1)) == T_HASH) {
851
+ opts = rb_ary_pop(argv);
852
+ --argc;
853
+ } else {
854
+ opts = Qnil;
855
+ }
856
+
857
+ params->npayload = CB_PACKET_HEADER_SIZE; /* size of packet header */
858
+ switch (params->type) {
859
+ case cb_cmd_touch:
860
+ params->cmd.touch.quiet = params->bucket->quiet;
861
+ params->cmd.touch.ttl = params->bucket->default_ttl;
862
+ cb_params_touch_parse_options(params, opts);
863
+ cb_params_touch_parse_arguments(params, argc, argv);
864
+ break;
865
+ case cb_cmd_remove:
866
+ params->cmd.remove.quiet = params->bucket->quiet;
867
+ if (argc == 2) {
868
+ int type = TYPE(rb_ary_entry(argv, 1));
869
+ if (type == T_FIXNUM || type == T_BIGNUM) {
870
+ /* allow form delete("foo", 0xdeadbeef) */
871
+ --argc;
872
+ params->cmd.remove.cas = NUM2ULL(rb_ary_pop(argv));
873
+ }
874
+ }
875
+ cb_params_remove_parse_options(params, opts);
876
+ cb_params_remove_parse_arguments(params, argc, argv);
877
+ break;
878
+ case cb_cmd_store:
879
+ if (argc == 1 && opts != Qnil) {
880
+ /* put last hash back because it is the value */
881
+ rb_ary_push(argv, opts);
882
+ opts = Qnil;
883
+ ++argc;
884
+ }
885
+ params->cmd.store.datatype = 0x00;
886
+ params->cmd.store.ttl = params->bucket->default_ttl;
887
+ params->cmd.store.flags = params->bucket->default_flags;
888
+ params->cmd.store.observe = Qnil;
889
+ params->cmd.store.transcoder = params->bucket->transcoder;
890
+ params->cmd.store.transcoder_opts = rb_hash_new();
891
+ cb_params_store_parse_options(params, opts);
892
+ cb_params_store_parse_arguments(params, argc, argv);
893
+ break;
894
+ case cb_cmd_get:
895
+ params->cmd.get.quiet = params->bucket->quiet;
896
+ params->cmd.get.transcoder = params->bucket->transcoder;
897
+ params->cmd.get.transcoder_opts = rb_hash_new();
898
+ params->cmd.get.replica = Qfalse;
899
+ cb_params_get_parse_options(params, opts);
900
+ cb_params_get_parse_arguments(params, argc, argv);
901
+ break;
902
+ case cb_cmd_arith:
903
+ params->cmd.arith.transcoder = params->bucket->transcoder;
904
+ params->cmd.arith.transcoder_opts = rb_hash_new();
905
+ params->cmd.arith.create = params->bucket->default_arith_create;
906
+ params->cmd.arith.initial = params->bucket->default_arith_init;
907
+ params->cmd.arith.delta = 1;
908
+ params->cmd.arith.ttl = params->bucket->default_ttl;
909
+ if (argc == 2 && TYPE(rb_ary_entry(argv, 1)) == T_FIXNUM) {
910
+ /* allow form incr("foo", 1) */
911
+ --argc;
912
+ params->cmd.arith.delta = NUM2ULL(rb_ary_pop(argv)) & INT64_MAX;
913
+ }
914
+ cb_params_arith_parse_options(params, opts);
915
+ cb_params_arith_parse_arguments(params, argc, argv);
916
+ break;
917
+ case cb_cmd_stats:
918
+ cb_params_stats_parse_arguments(params, argc, argv);
919
+ break;
920
+ case cb_cmd_version:
921
+ cb_params_version_alloc(params);
922
+ break;
923
+ case cb_cmd_observe:
924
+ cb_params_observe_parse_arguments(params, argc, argv);
925
+ break;
926
+ case cb_cmd_unlock:
927
+ params->cmd.unlock.quiet = params->bucket->quiet;
928
+ if (argc == 2) {
929
+ int type = TYPE(rb_ary_entry(argv, 1));
930
+ if (type == T_FIXNUM || type == T_BIGNUM) {
931
+ /* allow form unlock("foo", 0xdeadbeef) */
932
+ --argc;
933
+ params->cmd.unlock.cas = NUM2ULL(rb_ary_pop(argv));
934
+ }
935
+ }
936
+ cb_params_unlock_parse_options(params, opts);
937
+ cb_params_unlock_parse_arguments(params, argc, argv);
938
+ break;
939
+ }
940
+
941
+ return Qnil;
942
+ }
943
+
944
+ void
945
+ cb_params_build(struct cb_params_st *params)
946
+ {
947
+ int fail = 0;
948
+ params->ensurance = rb_ary_new();
949
+
950
+ rb_protect(do_params_build, (VALUE)params, &fail);
951
+ if (fail) {
952
+ cb_params_destroy(params);
953
+ /* raise exception from protected block */
954
+ rb_jump_tag(fail);
955
+ }
956
+ }