couchbase 1.1.5 → 1.2.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/.travis.yml +12 -1
- data/HISTORY.markdown +112 -1
- data/README.markdown +149 -6
- data/couchbase.gemspec +5 -1
- data/ext/couchbase_ext/.gitignore +4 -0
- data/ext/couchbase_ext/arguments.c +973 -0
- data/ext/couchbase_ext/arithmetic.c +322 -0
- data/ext/couchbase_ext/bucket.c +1092 -0
- data/ext/couchbase_ext/couchbase_ext.c +618 -3247
- data/ext/couchbase_ext/couchbase_ext.h +519 -0
- data/ext/couchbase_ext/delete.c +167 -0
- data/ext/couchbase_ext/extconf.rb +24 -5
- data/ext/couchbase_ext/get.c +301 -0
- data/ext/couchbase_ext/gethrtime.c +124 -0
- data/ext/couchbase_ext/http.c +402 -0
- data/ext/couchbase_ext/observe.c +174 -0
- data/ext/couchbase_ext/result.c +126 -0
- data/ext/couchbase_ext/stats.c +169 -0
- data/ext/couchbase_ext/store.c +522 -0
- data/ext/couchbase_ext/timer.c +192 -0
- data/ext/couchbase_ext/touch.c +190 -0
- data/ext/couchbase_ext/unlock.c +180 -0
- data/ext/couchbase_ext/utils.c +471 -0
- data/ext/couchbase_ext/version.c +147 -0
- data/lib/action_dispatch/middleware/session/couchbase_store.rb +38 -0
- data/lib/active_support/cache/couchbase_store.rb +356 -0
- data/lib/couchbase.rb +24 -3
- data/lib/couchbase/bucket.rb +372 -9
- data/lib/couchbase/result.rb +26 -0
- data/lib/couchbase/utils.rb +59 -0
- data/lib/couchbase/version.rb +1 -1
- data/lib/couchbase/view.rb +305 -0
- data/lib/couchbase/view_row.rb +230 -0
- data/lib/ext/multi_json_fix.rb +47 -0
- data/lib/rack/session/couchbase.rb +104 -0
- data/tasks/compile.rake +5 -14
- data/test/setup.rb +6 -2
- data/test/test_arithmetic.rb +32 -2
- data/test/test_async.rb +18 -4
- data/test/test_bucket.rb +11 -1
- data/test/test_cas.rb +13 -3
- data/test/test_couchbase_rails_cache_store.rb +294 -0
- data/test/test_delete.rb +60 -3
- data/test/test_format.rb +28 -17
- data/test/test_get.rb +91 -14
- data/test/test_store.rb +31 -1
- data/test/{test_flush.rb → test_timer.rb} +11 -18
- data/test/test_touch.rb +33 -5
- data/test/test_unlock.rb +120 -0
- data/test/test_utils.rb +26 -0
- metadata +101 -8
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
before_install:
|
2
|
+
- sudo rm -rf /etc/apt/sources.list.d/couchdb-ppa-source.list
|
3
|
+
- sudo rm -rf /etc/apt/sources.list.d/mongodb.list
|
4
|
+
- sudo rm -rf /etc/apt/sources.list.d/datastax-source.list
|
5
|
+
- sudo rm -rf /etc/apt/sources.list.d/rabbitmq-source.list
|
6
|
+
- sudo rm -rf /etc/apt/sources.list.d/mapopa-source.list
|
7
|
+
- sudo rm -rf /etc/apt/sources.list.d/webupd8team-java-ppa-source.list
|
8
|
+
- sudo rm -rf /etc/apt/sources.list.d/maven3-ppa-source.list
|
2
9
|
- wget -O- http://packages.couchbase.com/ubuntu/couchbase.key | sudo apt-key add -
|
3
|
-
- echo deb http://packages.couchbase.com/ubuntu
|
10
|
+
- echo deb http://packages.couchbase.com/snapshot/ubuntu oneiric oneiric/main | sudo tee /etc/apt/sources.list.d/couchbase.list
|
4
11
|
- sudo apt-get update
|
5
12
|
- sudo apt-get -y install libevent-dev libvbucket-dev libcouchbase-dev
|
6
13
|
|
@@ -9,3 +16,7 @@ rvm:
|
|
9
16
|
- 1.9.2
|
10
17
|
- 1.9.3
|
11
18
|
- ree
|
19
|
+
|
20
|
+
notifications:
|
21
|
+
email:
|
22
|
+
- sdk_dev@couchbase.com
|
data/HISTORY.markdown
CHANGED
@@ -1,6 +1,117 @@
|
|
1
|
-
## 1.
|
1
|
+
## 1.2.0.beta / 2012-09-18
|
2
2
|
|
3
|
+
* RCBC-70 return binary keys using Encoding.external value (thanks to Alex Leverington)
|
4
|
+
* Create new key object only if it is necessary
|
5
|
+
* Switch to rbenv because RVM doesn't work with tclsh
|
6
|
+
* [backport] RCBC-37 Bootstrapping using multiple nodes
|
7
|
+
* React on HTTP level errors in view request
|
8
|
+
* Fix typo: check for MultiJson.decode
|
9
|
+
* Use unified HTTP function from the latest libcouchbase
|
10
|
+
* Expose HTTP headers
|
11
|
+
* Update views to meet latest server changes
|
12
|
+
* Add support for spatial views
|
13
|
+
* Use updated libcouchbase_cancel_http_request()
|
14
|
+
* Workaround query issue on group=false&reduce=false
|
15
|
+
* Update windows build
|
16
|
+
* Bump version 1.1.4
|
17
|
+
* Refactor the C extension
|
18
|
+
* Fix CAS conversion for Bucket#delete method for 32-bit systems
|
19
|
+
* RCBC-28 Implement Bucket#unlock
|
20
|
+
* CCBC-98 Expose client temporary failure error
|
21
|
+
* Fix warnings in doc generator and specify return values
|
22
|
+
* Fix -Wreturn-type warning
|
23
|
+
* Add attribute reader for Error::Base status code
|
24
|
+
* Unset RUBYOPT to avoid issues with bundler
|
25
|
+
* Ignore shared object on macos
|
26
|
+
* RCBC-79 Use RESTful flush
|
27
|
+
* Fix build under bundler on MacOS
|
3
28
|
* RCBC-81 Protect against NoMethodError
|
29
|
+
* Fixup MAKEFILE_CONFIG which is copy of the CONFIG
|
30
|
+
* RCBC-81 Protect against NoMethodError
|
31
|
+
* Update windows build
|
32
|
+
|
33
|
+
## 1.2.0.dp6 / 2012-07-28
|
34
|
+
|
35
|
+
* Inherit StandardError instead RuntimeError for errors
|
36
|
+
* Use renamed functions for view requests
|
37
|
+
* Depend on yard-xml plugin to dump docs into single XML
|
38
|
+
* No need to check for NULL before deallocating memory
|
39
|
+
* RCBC-37 Bootstrapping using multiple nodes
|
40
|
+
* More docs and examples on views (fixes RCBC-43)
|
41
|
+
* RCBC-40 Fix Bucket#cas operation behaviour in async mode
|
42
|
+
* RCBC-39 Allow to specify delta for incr/decr in options
|
43
|
+
* Update README
|
44
|
+
* Apply timeout value before connection
|
45
|
+
* Clarify connection exceptions
|
46
|
+
* Remove seqno kludge
|
47
|
+
* rb_hash_delete() function could incorrectly detect block presence
|
48
|
+
* Add example with in-URL credentials
|
49
|
+
* RCBC-57 Expose timers API from libcouchbase
|
50
|
+
* RCBC-50 Allow to read keys from replica
|
51
|
+
* RCBC-6 Implement OBSERVE command
|
52
|
+
* Expose number of replicas to the user
|
53
|
+
* Notify about observe batch finish in async mode
|
54
|
+
* Separate memory errors for client and server
|
55
|
+
* Prefix error message from views with "SERVER: "
|
56
|
+
* Remove timeout hack
|
57
|
+
* RCBC-49 Bucket#observe_and_wait primitive
|
58
|
+
* RCBC-47 Allow to skip username for protected buckets
|
59
|
+
* Use allocators instead of singleton methods
|
60
|
+
* Check RDATA()->dfree to ensure object type
|
61
|
+
* Fix observe_and_wait in async mode
|
62
|
+
* Fill 'operation' in observe_and_wait Result object
|
63
|
+
* Fix extraction Hash with keys in observe_and_wait
|
64
|
+
* RCBC-49 :observe option for storage functions
|
65
|
+
* Fix timeout test
|
66
|
+
* Mention couchbase.com in install errors
|
67
|
+
* Make Bucket#observe_and_wait more 1.8.7 friendly
|
68
|
+
|
69
|
+
## 1.2.0.dp5 / 2012-06-15
|
70
|
+
|
71
|
+
* Allow to force assembling result Hash for multi-get
|
72
|
+
* Fix documentation for :ttl option in Bucket#cas
|
73
|
+
* Implement key prefix (simple namespacing)
|
74
|
+
* Implement cache store adapter for Rails
|
75
|
+
* Integrate with Rack and Rails session store
|
76
|
+
|
77
|
+
## 1.2.0.dp4 / 2012-06-07
|
78
|
+
|
79
|
+
* RCBC-36 Fix segfault
|
80
|
+
* Comment out unpredictable test
|
81
|
+
* Update replace documentation: it accepts :cas option
|
82
|
+
|
83
|
+
## 1.2.0.dp3 / 2012-06-06
|
84
|
+
|
85
|
+
* Fix for multi_json < 1.3.3
|
86
|
+
* Break out from event loop for non-chunked responses (fix creating
|
87
|
+
design create)
|
88
|
+
|
89
|
+
## 1.2.0.dp2 / 2012-06-05
|
90
|
+
|
91
|
+
* RCBC-31 Make Bucket#get more consistent
|
92
|
+
* Use monotonic high resolution clock
|
93
|
+
* Implement threshold for outgoing commands
|
94
|
+
* Allow to stop event loop from ruby
|
95
|
+
* RCBC-35 Fix the params escaping
|
96
|
+
* RCBC-34 Use multi_json gem
|
97
|
+
* Allow to block and wait for part of the requests
|
98
|
+
* Fix view iterator. It doesn't lock event loop anymore
|
99
|
+
* Specify HTTP method when body is set for View request
|
100
|
+
* Define views only if "views" key presented
|
101
|
+
* Use plain structs instead of typedefs
|
102
|
+
* Use debugger gem for 1.9.x rubies
|
103
|
+
* Use latest stable build of libcouchbase for travis-ci
|
104
|
+
* Require yajl as development dependency
|
105
|
+
* Implement get with lock operation
|
106
|
+
* Update docs
|
107
|
+
|
108
|
+
## 1.2.0.dp / 2012-04-06
|
109
|
+
|
110
|
+
* Properly handle hashes as Couchbase.connection_options
|
111
|
+
* Implement views
|
112
|
+
* Use verbose mode by default throwing exceptions on NOT_FOUND errors.
|
113
|
+
This means that quiet attribute is false now on new connections.
|
114
|
+
* Doc fixes
|
4
115
|
|
5
116
|
## 1.1.4 / 2012-08-30
|
6
117
|
|
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Couchbase Ruby Client [![Build Status](https://secure.travis-ci.org/
|
1
|
+
# Couchbase Ruby Client [![Build Status](https://secure.travis-ci.org/couchbase/couchbase-ruby-client.png?branch=master)](http://travis-ci.org/couchbase/couchbase-ruby-client)
|
2
2
|
|
3
3
|
This is the official client library for use with Couchbase Server.
|
4
4
|
|
@@ -18,14 +18,15 @@ libcouchbase doesn't take much effort.
|
|
18
18
|
|
19
19
|
$ brew install libcouchbase
|
20
20
|
|
21
|
-
|
21
|
+
The official homebrew repository contains only stable versions of
|
22
|
+
libvbucket and libcouchbase, if you need preview, take a look at
|
23
|
+
Couchbase's fork: https://github.com/couchbase/homebrew
|
22
24
|
|
23
|
-
$ brew install https://github.com/
|
24
|
-
$ brew install https://github.com/avsej/homebrew/raw/libcouchbase/Library/Formula/libcouchbase.rb
|
25
|
+
$ brew install https://raw.github.com/couchbase/homebrew/preview/Library/Formula/libcouchbase.rb
|
25
26
|
|
26
27
|
### Debian (Ubuntu)
|
27
28
|
|
28
|
-
Add the appropriate line to
|
29
|
+
Add the appropriate line to `/etc/apt/sources.list.d/couchbase.list` for
|
29
30
|
your OS release:
|
30
31
|
|
31
32
|
# Ubuntu 11.10 Oneiric Ocelot (Debian unstable)
|
@@ -42,6 +43,15 @@ Then install them
|
|
42
43
|
|
43
44
|
$ sudo apt-get update && sudo apt-get install libcouchbase-dev
|
44
45
|
|
46
|
+
Again, if you need preview versions, just use another repositories in
|
47
|
+
your `couchbase.list`
|
48
|
+
|
49
|
+
# Ubuntu 11.10 Oneiric Ocelot (Debian unstable)
|
50
|
+
deb http://packages.couchbase.com/preview/ubuntu oneiric oneiric/main
|
51
|
+
|
52
|
+
# Ubuntu 10.04 Lucid Lynx (Debian stable or testing)
|
53
|
+
deb http://packages.couchbase.com/preview/ubuntu lucid lucid/main
|
54
|
+
|
45
55
|
### Centos (Redhat and rpm-based systems)
|
46
56
|
|
47
57
|
Add these lines to /etc/yum.repos.d/couchbase.repo using the correct architecture
|
@@ -52,12 +62,23 @@ Add these lines to /etc/yum.repos.d/couchbase.repo using the correct architectur
|
|
52
62
|
|
53
63
|
[couchbase]
|
54
64
|
name = Couchbase package repository
|
55
|
-
baseurl = http
|
65
|
+
baseurl = http://packages.couchbase.com/rpm/5.5/x86_64
|
56
66
|
|
57
67
|
Then to install libcouchbase itself, run:
|
58
68
|
|
59
69
|
$ sudo yum update && sudo yum install libcouchbase-devel
|
60
70
|
|
71
|
+
We have preview repositories for RPMs too, use them if you need to try
|
72
|
+
fresh version of couchbase gem:
|
73
|
+
|
74
|
+
[couchbase]
|
75
|
+
name = Couchbase package repository
|
76
|
+
baseurl = http://packages.couchbase.com/preview/rpm/5.5/i386
|
77
|
+
|
78
|
+
[couchbase]
|
79
|
+
name = Couchbase package repository
|
80
|
+
baseurl = http://packages.couchbase.com/preview/rpm/5.5/x86_64
|
81
|
+
|
61
82
|
### Windows
|
62
83
|
|
63
84
|
There no additional dependencies for Windows systems. The gem carry
|
@@ -94,6 +115,14 @@ This is equivalent to following forms:
|
|
94
115
|
|
95
116
|
The hash parameters take precedence on string URL.
|
96
117
|
|
118
|
+
If you worry about state of your nodes or not sure what node is alive,
|
119
|
+
you can pass the list of nodes and the library will iterate over it
|
120
|
+
until finds the working one. From that moment it won't use **your**
|
121
|
+
list, because node list from cluster config is more actual.
|
122
|
+
|
123
|
+
c = Couchbase.connect(:bucket => "mybucket",
|
124
|
+
:node_list => ['example.com:8091', example.net'])
|
125
|
+
|
97
126
|
There is also handy method `Couchbase.bucket` which uses thread local
|
98
127
|
storage to keep the reference to default connection. You can set the
|
99
128
|
connection options via `Couchbase.connection_options`:
|
@@ -371,6 +400,120 @@ the key and stats as key-value pairs.
|
|
371
400
|
# ...
|
372
401
|
}
|
373
402
|
|
403
|
+
### Timers
|
404
|
+
|
405
|
+
It is possible to create timers to implement general purpose timeouts.
|
406
|
+
Note that timers are using microseconds for time intervals. For example,
|
407
|
+
following examples increment the keys value five times with 0.5 second
|
408
|
+
interval:
|
409
|
+
|
410
|
+
c.set("foo", 100)
|
411
|
+
n = 1
|
412
|
+
c.run do
|
413
|
+
c.create_periodic_timer(500000) do |tm|
|
414
|
+
c.incr("foo") do
|
415
|
+
if n == 5
|
416
|
+
tm.cancel
|
417
|
+
else
|
418
|
+
n += 1
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
### Views (Map/Reduce queries)
|
425
|
+
|
426
|
+
If you store structured data, they will be treated as documents and you
|
427
|
+
can handle them in map/reduce function from Couchbase Views. For example,
|
428
|
+
store a couple of posts using memcached API:
|
429
|
+
|
430
|
+
c['biking'] = {:title => 'Biking',
|
431
|
+
:body => 'My biggest hobby is mountainbiking. The other day...',
|
432
|
+
:date => '2009/01/30 18:04:11'}
|
433
|
+
c['bought-a-cat'] = {:title => 'Bought a Cat',
|
434
|
+
:body => 'I went to the the pet store earlier and brought home a little kitty...',
|
435
|
+
:date => '2009/01/30 20:04:11'}
|
436
|
+
c['hello-world'] = {:title => 'Hello World',
|
437
|
+
:body => 'Well hello and welcome to my new blog...',
|
438
|
+
:date => '2009/01/15 15:52:20'}
|
439
|
+
c.all_docs.count #=> 3
|
440
|
+
|
441
|
+
Now let's create design doc with sample view and save it in file
|
442
|
+
'blog.json':
|
443
|
+
|
444
|
+
{
|
445
|
+
"_id": "_design/blog",
|
446
|
+
"language": "javascript",
|
447
|
+
"views": {
|
448
|
+
"recent_posts": {
|
449
|
+
"map": "function(doc){if(doc.date && doc.title){emit(doc.date, doc.title);}}"
|
450
|
+
}
|
451
|
+
}
|
452
|
+
}
|
453
|
+
|
454
|
+
This design document could be loaded into the database like this (also you can
|
455
|
+
pass the ruby Hash or String with JSON encoded document):
|
456
|
+
|
457
|
+
c.save_design_doc(File.open('blog.json'))
|
458
|
+
|
459
|
+
To execute view you need to fetch it from design document `_design/blog`:
|
460
|
+
|
461
|
+
blog = c.design_docs['blog']
|
462
|
+
blog.views #=> ["recent_posts"]
|
463
|
+
blog.recent_posts #=> [#<Couchbase::ViewRow:9855800 @id="hello-world" @key="2009/01/15 15:52:20" @value="Hello World" @doc=nil @meta={} @views=[]>, ...]
|
464
|
+
|
465
|
+
Gem uses streaming parser to access view results so you can iterate them
|
466
|
+
easily and if your code won't keep links to the documents GC might free
|
467
|
+
them as soon as it decide they are unreachable, because parser doesn't
|
468
|
+
store global JSON tree.
|
469
|
+
|
470
|
+
blog.recent_posts.each do |doc|
|
471
|
+
# do something
|
472
|
+
# with doc object
|
473
|
+
doc.key # gives the key argument of the emit()
|
474
|
+
doc.value # gives the value argument of the emit()
|
475
|
+
end
|
476
|
+
|
477
|
+
Load with documents
|
478
|
+
|
479
|
+
blog.recent_posts(:include_docs => true).each do |doc|
|
480
|
+
doc.doc # gives the document which emitted the item
|
481
|
+
doc['date'] # gives the argument of the underlying document
|
482
|
+
end
|
483
|
+
|
484
|
+
|
485
|
+
You can also use Enumerator to iterate view results
|
486
|
+
|
487
|
+
require 'date'
|
488
|
+
posts_by_date = Hash.new{|h,k| h[k] = []}
|
489
|
+
enum = c.all_docs(:include_docs => true).each # request hasn't issued yet
|
490
|
+
enum.inject(posts_by_date) do |acc, doc|
|
491
|
+
acc[date] = Date.strptime(doc['date'], '%Y/%m/%d')
|
492
|
+
acc
|
493
|
+
end
|
494
|
+
|
495
|
+
The Couchbase server could generate errors during view execution with
|
496
|
+
`200 OK` and partial results. By default the library raises exception as
|
497
|
+
soon as errors detected in the result stream, but you can define the
|
498
|
+
callback `on_error` to intercept these errors and do something more
|
499
|
+
useful.
|
500
|
+
|
501
|
+
view = blog.recent_posts(:include_docs => true)
|
502
|
+
logger = Logger.new(STDOUT)
|
503
|
+
|
504
|
+
view.on_error do |from, reason|
|
505
|
+
logger.warn("#{view.inspect} received the error '#{reason}' from #{from}")
|
506
|
+
end
|
507
|
+
|
508
|
+
posts = view.each do |doc|
|
509
|
+
# do something
|
510
|
+
# with doc object
|
511
|
+
end
|
512
|
+
|
513
|
+
Note that errors object in view results usually goes *after* the rows,
|
514
|
+
so you will likely receive a number of view results successfully before
|
515
|
+
the error is detected.
|
516
|
+
|
374
517
|
[1]: http://couchbase.com/issues/browse/RCBC
|
375
518
|
[2]: http://freenode.net/irc_servers.shtml
|
376
519
|
[3]: http://www.couchbase.com/develop/c/current
|
data/couchbase.gemspec
CHANGED
@@ -35,13 +35,17 @@ Gem::Specification.new do |s|
|
|
35
35
|
s.extensions = `git ls-files -- ext/**/extconf.rb`.split("\n")
|
36
36
|
s.require_paths = ['lib']
|
37
37
|
|
38
|
-
s.add_runtime_dependency '
|
38
|
+
s.add_runtime_dependency 'yaji', '~> 0.3.2'
|
39
|
+
s.add_runtime_dependency 'multi_json', '~> 1.0'
|
39
40
|
|
40
41
|
s.add_development_dependency 'rake', '~> 0.8.7'
|
41
42
|
s.add_development_dependency 'minitest'
|
42
43
|
s.add_development_dependency 'rake-compiler', '>= 0.7.5'
|
43
44
|
s.add_development_dependency 'rdiscount'
|
44
45
|
s.add_development_dependency 'yard'
|
46
|
+
s.add_development_dependency 'yard-xml'
|
45
47
|
s.add_development_dependency 'mini_portile'
|
48
|
+
s.add_development_dependency 'yajl-ruby', '~> 1.1.0'
|
46
49
|
s.add_development_dependency RUBY_VERSION =~ /^1\.9/ ? 'debugger' : 'ruby-debug'
|
50
|
+
s.add_development_dependency 'active_support'
|
47
51
|
end
|
@@ -0,0 +1,973 @@
|
|
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
|
+
|
21
|
+
/* TOUCH */
|
22
|
+
|
23
|
+
static void
|
24
|
+
cb_params_touch_alloc(struct params_st *params, lcb_size_t size)
|
25
|
+
{
|
26
|
+
lcb_size_t ii;
|
27
|
+
|
28
|
+
params->cmd.touch.num = size;
|
29
|
+
params->cmd.touch.items = xcalloc(size, sizeof(lcb_touch_cmd_t));
|
30
|
+
if (params->cmd.touch.items == NULL) {
|
31
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
32
|
+
}
|
33
|
+
params->cmd.touch.ptr = xcalloc(size, sizeof(lcb_touch_cmd_t *));
|
34
|
+
if (params->cmd.touch.ptr == NULL) {
|
35
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
36
|
+
}
|
37
|
+
for (ii = 0; ii < size; ++ii) {
|
38
|
+
params->cmd.touch.ptr[ii] = params->cmd.touch.items + ii;
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
static void
|
43
|
+
cb_params_touch_init_item(struct params_st *params, lcb_size_t idx, VALUE key_obj, lcb_time_t exptime)
|
44
|
+
{
|
45
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
46
|
+
params->cmd.touch.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
47
|
+
params->cmd.touch.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
48
|
+
params->cmd.touch.items[idx].v.v0.exptime = exptime;
|
49
|
+
params->npayload += RSTRING_LEN(key_obj) + sizeof(exptime);
|
50
|
+
}
|
51
|
+
|
52
|
+
static int
|
53
|
+
cb_params_touch_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
54
|
+
{
|
55
|
+
struct params_st *params = (struct params_st *)arg;
|
56
|
+
cb_params_touch_init_item(params, params->idx++, key, NUM2ULONG(value));
|
57
|
+
return ST_CONTINUE;
|
58
|
+
}
|
59
|
+
|
60
|
+
static void
|
61
|
+
cb_params_touch_parse_options(struct params_st *params, VALUE options)
|
62
|
+
{
|
63
|
+
VALUE tmp;
|
64
|
+
|
65
|
+
if (NIL_P(options)) {
|
66
|
+
return;
|
67
|
+
}
|
68
|
+
tmp = rb_hash_aref(options, sym_ttl);
|
69
|
+
if (tmp != Qnil) {
|
70
|
+
params->cmd.touch.ttl = NUM2ULONG(tmp);
|
71
|
+
}
|
72
|
+
if (RTEST(rb_funcall(options, id_has_key_p, 1, sym_quiet))) {
|
73
|
+
params->cmd.touch.quiet = RTEST(rb_hash_aref(options, sym_quiet));
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
static void
|
78
|
+
cb_params_touch_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
79
|
+
{
|
80
|
+
lcb_size_t ii;
|
81
|
+
|
82
|
+
if (argc < 1) {
|
83
|
+
rb_raise(rb_eArgError, "must be at least one key");
|
84
|
+
}
|
85
|
+
if (argc == 1) {
|
86
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
87
|
+
switch(TYPE(keys)) {
|
88
|
+
case T_ARRAY:
|
89
|
+
/* array of keys as a first argument */
|
90
|
+
params->cmd.touch.array = 1;
|
91
|
+
cb_params_touch_alloc(params, RARRAY_LEN(keys));
|
92
|
+
for (ii = 0; ii < params->cmd.touch.num; ++ii) {
|
93
|
+
cb_params_touch_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.touch.ttl);
|
94
|
+
}
|
95
|
+
break;
|
96
|
+
case T_HASH:
|
97
|
+
/* key-ttl pairs */
|
98
|
+
cb_params_touch_alloc(params, RHASH_SIZE(keys));
|
99
|
+
rb_hash_foreach(keys, cb_params_touch_extract_keys_i,
|
100
|
+
(VALUE)params);
|
101
|
+
break;
|
102
|
+
default:
|
103
|
+
/* single key */
|
104
|
+
cb_params_touch_alloc(params, 1);
|
105
|
+
cb_params_touch_init_item(params, 0, keys, params->cmd.touch.ttl);
|
106
|
+
}
|
107
|
+
} else {
|
108
|
+
/* just list of arguments */
|
109
|
+
cb_params_touch_alloc(params, argc);
|
110
|
+
for (ii = 0; ii < params->cmd.touch.num; ++ii) {
|
111
|
+
cb_params_touch_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.touch.ttl);
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
|
117
|
+
/* REMOVE */
|
118
|
+
|
119
|
+
static void
|
120
|
+
cb_params_remove_alloc(struct params_st *params, lcb_size_t size)
|
121
|
+
{
|
122
|
+
lcb_size_t ii;
|
123
|
+
|
124
|
+
params->cmd.remove.num = size;
|
125
|
+
params->cmd.remove.items = xcalloc(size, sizeof(lcb_remove_cmd_t));
|
126
|
+
if (params->cmd.remove.items == NULL) {
|
127
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
128
|
+
}
|
129
|
+
params->cmd.remove.ptr = xcalloc(size, sizeof(lcb_remove_cmd_t *));
|
130
|
+
if (params->cmd.remove.ptr == NULL) {
|
131
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
132
|
+
}
|
133
|
+
for (ii = 0; ii < size; ++ii) {
|
134
|
+
params->cmd.remove.ptr[ii] = params->cmd.remove.items + ii;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
static void
|
139
|
+
cb_params_remove_init_item(struct params_st *params, lcb_size_t idx, VALUE key_obj, lcb_cas_t cas)
|
140
|
+
{
|
141
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
142
|
+
params->cmd.remove.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
143
|
+
params->cmd.remove.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
144
|
+
params->cmd.remove.items[idx].v.v0.cas = cas;
|
145
|
+
params->npayload += RSTRING_LEN(key_obj);
|
146
|
+
}
|
147
|
+
|
148
|
+
static int
|
149
|
+
cb_params_remove_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
150
|
+
{
|
151
|
+
struct params_st *params = (struct params_st *)arg;
|
152
|
+
cb_params_remove_init_item(params, params->idx++, key, NUM2ULL(value));
|
153
|
+
return ST_CONTINUE;
|
154
|
+
}
|
155
|
+
|
156
|
+
static void
|
157
|
+
cb_params_remove_parse_options(struct params_st *params, VALUE options)
|
158
|
+
{
|
159
|
+
VALUE tmp;
|
160
|
+
|
161
|
+
if (NIL_P(options)) {
|
162
|
+
return;
|
163
|
+
}
|
164
|
+
if (RTEST(rb_funcall(options, id_has_key_p, 1, sym_quiet))) {
|
165
|
+
params->cmd.remove.quiet = RTEST(rb_hash_aref(options, sym_quiet));
|
166
|
+
}
|
167
|
+
tmp = rb_hash_aref(options, sym_cas);
|
168
|
+
if (tmp != Qnil) {
|
169
|
+
params->cmd.remove.cas = NUM2ULL(tmp);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
|
173
|
+
static void
|
174
|
+
cb_params_remove_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
175
|
+
{
|
176
|
+
lcb_size_t ii;
|
177
|
+
|
178
|
+
if (argc < 1) {
|
179
|
+
rb_raise(rb_eArgError, "must be at least one key");
|
180
|
+
}
|
181
|
+
if (argc == 1) {
|
182
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
183
|
+
switch(TYPE(keys)) {
|
184
|
+
case T_ARRAY:
|
185
|
+
/* array of keys as a first argument */
|
186
|
+
params->cmd.remove.array = 1;
|
187
|
+
cb_params_remove_alloc(params, RARRAY_LEN(keys));
|
188
|
+
for (ii = 0; ii < params->cmd.remove.num; ++ii) {
|
189
|
+
cb_params_remove_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.remove.cas);
|
190
|
+
}
|
191
|
+
break;
|
192
|
+
case T_HASH:
|
193
|
+
/* key-cas pairs */
|
194
|
+
cb_params_remove_alloc(params, RHASH_SIZE(keys));
|
195
|
+
rb_hash_foreach(keys, cb_params_remove_extract_keys_i,
|
196
|
+
(VALUE)params);
|
197
|
+
break;
|
198
|
+
default:
|
199
|
+
/* single key */
|
200
|
+
cb_params_remove_alloc(params, 1);
|
201
|
+
cb_params_remove_init_item(params, 0, keys, params->cmd.remove.cas);
|
202
|
+
}
|
203
|
+
} else {
|
204
|
+
/* just list of arguments */
|
205
|
+
cb_params_remove_alloc(params, argc);
|
206
|
+
for (ii = 0; ii < params->cmd.remove.num; ++ii) {
|
207
|
+
cb_params_remove_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.remove.cas);
|
208
|
+
}
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
212
|
+
|
213
|
+
/* STORE */
|
214
|
+
static void
|
215
|
+
cb_params_store_alloc(struct params_st *params, lcb_size_t size)
|
216
|
+
{
|
217
|
+
lcb_size_t ii;
|
218
|
+
|
219
|
+
params->cmd.store.num = size;
|
220
|
+
params->cmd.store.items = xcalloc(size, sizeof(lcb_store_cmd_t));
|
221
|
+
if (params->cmd.store.items == NULL) {
|
222
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
223
|
+
}
|
224
|
+
params->cmd.store.ptr = xcalloc(size, sizeof(lcb_store_cmd_t *));
|
225
|
+
if (params->cmd.store.ptr == NULL) {
|
226
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
227
|
+
}
|
228
|
+
for (ii = 0; ii < size; ++ii) {
|
229
|
+
params->cmd.store.ptr[ii] = params->cmd.store.items + ii;
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
static void
|
234
|
+
cb_params_store_init_item(struct params_st *params, lcb_size_t idx,
|
235
|
+
VALUE key_obj, VALUE value_obj, lcb_uint32_t flags, lcb_cas_t cas,
|
236
|
+
lcb_time_t exptime)
|
237
|
+
{
|
238
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
239
|
+
value_obj = encode_value(value_obj, params->cmd.store.flags);
|
240
|
+
if (value_obj == Qundef) {
|
241
|
+
rb_raise(eValueFormatError, "unable to convert value for key '%s'", RSTRING_PTR(key_obj));
|
242
|
+
}
|
243
|
+
params->cmd.store.items[idx].v.v0.datatype = params->cmd.store.datatype;
|
244
|
+
params->cmd.store.items[idx].v.v0.operation = params->cmd.store.operation;
|
245
|
+
params->cmd.store.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
246
|
+
params->cmd.store.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
247
|
+
params->cmd.store.items[idx].v.v0.bytes = RSTRING_PTR(value_obj);
|
248
|
+
params->cmd.store.items[idx].v.v0.nbytes = RSTRING_LEN(value_obj);
|
249
|
+
params->cmd.store.items[idx].v.v0.flags = flags;
|
250
|
+
params->cmd.store.items[idx].v.v0.cas = cas;
|
251
|
+
params->cmd.store.items[idx].v.v0.exptime = exptime;
|
252
|
+
params->npayload += RSTRING_LEN(key_obj) + RSTRING_LEN(value_obj) + sizeof(flags) + sizeof(exptime);
|
253
|
+
}
|
254
|
+
|
255
|
+
static int
|
256
|
+
cb_params_store_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
257
|
+
{
|
258
|
+
struct params_st *params = (struct params_st *)arg;
|
259
|
+
cb_params_store_init_item(params, params->idx++, key, value,
|
260
|
+
params->cmd.store.flags, 0, params->cmd.store.ttl);
|
261
|
+
return ST_CONTINUE;
|
262
|
+
}
|
263
|
+
|
264
|
+
static void
|
265
|
+
cb_params_store_parse_options(struct params_st *params, VALUE options)
|
266
|
+
{
|
267
|
+
VALUE tmp;
|
268
|
+
|
269
|
+
if (NIL_P(options)) {
|
270
|
+
return;
|
271
|
+
}
|
272
|
+
tmp = rb_hash_aref(options, sym_flags);
|
273
|
+
if (tmp != Qnil) {
|
274
|
+
params->cmd.store.flags = (lcb_uint32_t)NUM2ULONG(tmp);
|
275
|
+
}
|
276
|
+
tmp = rb_hash_aref(options, sym_format);
|
277
|
+
if (tmp != Qnil) { /* rewrite format bits */
|
278
|
+
params->cmd.store.flags = flags_set_format(params->cmd.store.flags, tmp);
|
279
|
+
}
|
280
|
+
tmp = rb_hash_aref(options, sym_ttl);
|
281
|
+
if (tmp != Qnil) {
|
282
|
+
params->cmd.store.ttl = NUM2ULONG(tmp);
|
283
|
+
}
|
284
|
+
tmp = rb_hash_aref(options, sym_cas);
|
285
|
+
if (tmp != Qnil) {
|
286
|
+
params->cmd.store.cas = NUM2ULL(tmp);
|
287
|
+
}
|
288
|
+
tmp = rb_hash_aref(options, sym_observe);
|
289
|
+
if (tmp != Qnil) {
|
290
|
+
Check_Type(tmp, T_HASH);
|
291
|
+
rb_funcall(params->bucket->self, id_verify_observe_options, 1, tmp);
|
292
|
+
params->cmd.store.observe = tmp;
|
293
|
+
}
|
294
|
+
if (flags_get_format(params->cmd.store.flags) == sym_document) {
|
295
|
+
/* just amend datatype for now */
|
296
|
+
params->cmd.store.datatype = 0x01;
|
297
|
+
}
|
298
|
+
}
|
299
|
+
|
300
|
+
static void
|
301
|
+
cb_params_store_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
302
|
+
{
|
303
|
+
VALUE keys;
|
304
|
+
|
305
|
+
if (argc < 1) {
|
306
|
+
rb_raise(rb_eArgError, "the key and value must be specified");
|
307
|
+
}
|
308
|
+
switch (argc) {
|
309
|
+
case 1:
|
310
|
+
keys = RARRAY_PTR(argv)[0];
|
311
|
+
switch(TYPE(keys)) {
|
312
|
+
case T_HASH:
|
313
|
+
/* key-value pairs */
|
314
|
+
cb_params_store_alloc(params, RHASH_SIZE(keys));
|
315
|
+
rb_hash_foreach(keys, cb_params_store_extract_keys_i,
|
316
|
+
(VALUE)params);
|
317
|
+
break;
|
318
|
+
default:
|
319
|
+
rb_raise(rb_eArgError, "there must be either Hash with key-value pairs"
|
320
|
+
" or two separate arguments: key and value");
|
321
|
+
}
|
322
|
+
break;
|
323
|
+
case 2:
|
324
|
+
/* just key and value */
|
325
|
+
cb_params_store_alloc(params, 1);
|
326
|
+
cb_params_store_init_item(params, 0, RARRAY_PTR(argv)[0], RARRAY_PTR(argv)[1],
|
327
|
+
params->cmd.store.flags, params->cmd.store.cas, params->cmd.store.ttl);
|
328
|
+
break;
|
329
|
+
default:
|
330
|
+
rb_raise(rb_eArgError, "too many arguments");
|
331
|
+
}
|
332
|
+
}
|
333
|
+
|
334
|
+
|
335
|
+
/* GET */
|
336
|
+
static void
|
337
|
+
cb_params_get_alloc(struct params_st *params, lcb_size_t size)
|
338
|
+
{
|
339
|
+
lcb_size_t ii;
|
340
|
+
|
341
|
+
params->cmd.get.num = size;
|
342
|
+
if (params->cmd.get.replica) {
|
343
|
+
params->cmd.get.items = xcalloc(size, sizeof(lcb_get_replica_cmd_t));
|
344
|
+
if (params->cmd.get.items_gr == NULL) {
|
345
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
346
|
+
}
|
347
|
+
params->cmd.get.ptr = xcalloc(size, sizeof(lcb_get_replica_cmd_t *));
|
348
|
+
if (params->cmd.get.ptr_gr == NULL) {
|
349
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
350
|
+
}
|
351
|
+
for (ii = 0; ii < size; ++ii) {
|
352
|
+
params->cmd.get.ptr_gr[ii] = params->cmd.get.items_gr + ii;
|
353
|
+
}
|
354
|
+
} else {
|
355
|
+
params->cmd.get.items = xcalloc(size, sizeof(lcb_get_cmd_t));
|
356
|
+
if (params->cmd.get.items == NULL) {
|
357
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
358
|
+
}
|
359
|
+
params->cmd.get.ptr = xcalloc(size, sizeof(lcb_get_cmd_t *));
|
360
|
+
if (params->cmd.get.ptr == NULL) {
|
361
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
362
|
+
}
|
363
|
+
for (ii = 0; ii < size; ++ii) {
|
364
|
+
params->cmd.get.ptr[ii] = params->cmd.get.items + ii;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
369
|
+
static void
|
370
|
+
cb_params_get_init_item(struct params_st *params, lcb_size_t idx,
|
371
|
+
VALUE key_obj, lcb_time_t exptime)
|
372
|
+
{
|
373
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
374
|
+
if (params->cmd.get.replica) {
|
375
|
+
params->cmd.get.items_gr[idx].v.v0.key = RSTRING_PTR(key_obj);
|
376
|
+
params->cmd.get.items_gr[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
377
|
+
} else {
|
378
|
+
params->cmd.get.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
379
|
+
params->cmd.get.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
380
|
+
params->cmd.get.items[idx].v.v0.exptime = exptime;
|
381
|
+
params->cmd.get.items[idx].v.v0.lock = params->cmd.get.lock;
|
382
|
+
params->npayload += sizeof(exptime);
|
383
|
+
}
|
384
|
+
params->npayload += RSTRING_LEN(key_obj);
|
385
|
+
}
|
386
|
+
|
387
|
+
static int
|
388
|
+
cb_params_get_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
389
|
+
{
|
390
|
+
struct params_st *params = (struct params_st *)arg;
|
391
|
+
rb_ary_push(params->cmd.get.keys_ary, key);
|
392
|
+
cb_params_get_init_item(params, params->idx++, key, NUM2ULONG(value));
|
393
|
+
return ST_CONTINUE;
|
394
|
+
}
|
395
|
+
|
396
|
+
static void
|
397
|
+
cb_params_get_parse_options(struct params_st *params, VALUE options)
|
398
|
+
{
|
399
|
+
VALUE tmp;
|
400
|
+
|
401
|
+
if (NIL_P(options)) {
|
402
|
+
return;
|
403
|
+
}
|
404
|
+
params->cmd.get.replica = RTEST(rb_hash_aref(options, sym_replica));
|
405
|
+
params->cmd.get.extended = RTEST(rb_hash_aref(options, sym_extended));
|
406
|
+
params->cmd.get.assemble_hash = RTEST(rb_hash_aref(options, sym_assemble_hash));
|
407
|
+
if (RTEST(rb_funcall(options, id_has_key_p, 1, sym_quiet))) {
|
408
|
+
params->cmd.get.quiet = RTEST(rb_hash_aref(options, sym_quiet));
|
409
|
+
}
|
410
|
+
tmp = rb_hash_aref(options, sym_format);
|
411
|
+
if (tmp != Qnil) {
|
412
|
+
Check_Type(tmp, T_SYMBOL);
|
413
|
+
params->cmd.get.forced_format = tmp;
|
414
|
+
}
|
415
|
+
tmp = rb_hash_aref(options, sym_ttl);
|
416
|
+
if (tmp != Qnil) {
|
417
|
+
params->cmd.get.ttl = NUM2ULONG(tmp);
|
418
|
+
}
|
419
|
+
/* boolean or number of seconds to lock */
|
420
|
+
tmp = rb_hash_aref(options, sym_lock);
|
421
|
+
if (tmp != Qnil) {
|
422
|
+
params->cmd.get.lock = RTEST(tmp);
|
423
|
+
if (TYPE(tmp) == T_FIXNUM) {
|
424
|
+
params->cmd.get.ttl = NUM2ULONG(tmp);
|
425
|
+
}
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
static void
|
430
|
+
cb_params_get_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
431
|
+
{
|
432
|
+
lcb_size_t ii;
|
433
|
+
|
434
|
+
if (argc < 1) {
|
435
|
+
rb_raise(rb_eArgError, "must be at least one key");
|
436
|
+
}
|
437
|
+
if (argc == 1) {
|
438
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
439
|
+
switch(TYPE(keys)) {
|
440
|
+
case T_ARRAY:
|
441
|
+
/* array of keys as a first argument */
|
442
|
+
params->cmd.get.array = 1;
|
443
|
+
cb_params_get_alloc(params, RARRAY_LEN(keys));
|
444
|
+
for (ii = 0; ii < params->cmd.get.num; ++ii) {
|
445
|
+
rb_ary_push(params->cmd.get.keys_ary, RARRAY_PTR(keys)[ii]);
|
446
|
+
cb_params_get_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.get.ttl);
|
447
|
+
}
|
448
|
+
break;
|
449
|
+
case T_HASH:
|
450
|
+
/* key-ttl pairs */
|
451
|
+
if (params->cmd.get.replica) {
|
452
|
+
rb_raise(rb_eArgError, "must be either list of key or single key");
|
453
|
+
}
|
454
|
+
params->cmd.get.gat = 1;
|
455
|
+
cb_params_get_alloc(params, RHASH_SIZE(keys));
|
456
|
+
rb_hash_foreach(keys, cb_params_get_extract_keys_i, (VALUE)params);
|
457
|
+
break;
|
458
|
+
default:
|
459
|
+
/* single key */
|
460
|
+
cb_params_get_alloc(params, 1);
|
461
|
+
rb_ary_push(params->cmd.get.keys_ary, keys);
|
462
|
+
cb_params_get_init_item(params, 0, keys, params->cmd.get.ttl);
|
463
|
+
}
|
464
|
+
} else {
|
465
|
+
/* just list of arguments */
|
466
|
+
cb_params_get_alloc(params, argc);
|
467
|
+
for (ii = 0; ii < params->cmd.get.num; ++ii) {
|
468
|
+
rb_ary_push(params->cmd.get.keys_ary, RARRAY_PTR(argv)[ii]);
|
469
|
+
cb_params_get_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.get.ttl);
|
470
|
+
}
|
471
|
+
}
|
472
|
+
}
|
473
|
+
|
474
|
+
|
475
|
+
/* ARITH */
|
476
|
+
static void
|
477
|
+
cb_params_arith_alloc(struct params_st *params, lcb_size_t size)
|
478
|
+
{
|
479
|
+
lcb_size_t ii;
|
480
|
+
|
481
|
+
params->cmd.arith.num = size;
|
482
|
+
params->cmd.arith.items = xcalloc(size, sizeof(lcb_arithmetic_cmd_t));
|
483
|
+
if (params->cmd.arith.items == NULL) {
|
484
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
485
|
+
}
|
486
|
+
params->cmd.arith.ptr = xcalloc(size, sizeof(lcb_arithmetic_cmd_t *));
|
487
|
+
if (params->cmd.arith.ptr == NULL) {
|
488
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
489
|
+
}
|
490
|
+
for (ii = 0; ii < size; ++ii) {
|
491
|
+
params->cmd.arith.ptr[ii] = params->cmd.arith.items + ii;
|
492
|
+
}
|
493
|
+
}
|
494
|
+
|
495
|
+
static void
|
496
|
+
cb_params_arith_init_item(struct params_st *params, lcb_size_t idx,
|
497
|
+
VALUE key_obj, lcb_int64_t delta)
|
498
|
+
{
|
499
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
500
|
+
params->cmd.arith.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
501
|
+
params->cmd.arith.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
502
|
+
params->cmd.arith.items[idx].v.v0.delta = delta * params->cmd.arith.sign;
|
503
|
+
params->cmd.arith.items[idx].v.v0.exptime = params->cmd.arith.ttl;
|
504
|
+
params->cmd.arith.items[idx].v.v0.create = params->cmd.arith.create;
|
505
|
+
params->cmd.arith.items[idx].v.v0.initial = params->cmd.arith.initial;
|
506
|
+
params->npayload += RSTRING_LEN(key_obj);
|
507
|
+
}
|
508
|
+
|
509
|
+
static int
|
510
|
+
cb_params_arith_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
511
|
+
{
|
512
|
+
struct params_st *params = (struct params_st *)arg;
|
513
|
+
cb_params_arith_init_item(params, params->idx++, key, NUM2ULONG(value) & INT64_MAX);
|
514
|
+
return ST_CONTINUE;
|
515
|
+
}
|
516
|
+
|
517
|
+
static void
|
518
|
+
cb_params_arith_parse_options(struct params_st *params, VALUE options)
|
519
|
+
{
|
520
|
+
VALUE tmp;
|
521
|
+
|
522
|
+
if (NIL_P(options)) {
|
523
|
+
return;
|
524
|
+
}
|
525
|
+
params->cmd.arith.create = RTEST(rb_hash_aref(options, sym_create));
|
526
|
+
params->cmd.arith.extended = RTEST(rb_hash_aref(options, sym_extended));
|
527
|
+
tmp = rb_hash_aref(options, sym_ttl);
|
528
|
+
if (tmp != Qnil) {
|
529
|
+
params->cmd.arith.ttl = NUM2ULONG(tmp);
|
530
|
+
}
|
531
|
+
tmp = rb_hash_aref(options, sym_initial);
|
532
|
+
if (tmp != Qnil) {
|
533
|
+
params->cmd.arith.initial = NUM2ULL(tmp);
|
534
|
+
params->cmd.arith.create = 1;
|
535
|
+
}
|
536
|
+
tmp = rb_hash_aref(options, sym_delta);
|
537
|
+
if (tmp != Qnil) {
|
538
|
+
params->cmd.arith.delta = NUM2ULL(tmp) & INT64_MAX;
|
539
|
+
}
|
540
|
+
tmp = rb_hash_aref(options, sym_format);
|
541
|
+
if (tmp != Qnil) { /* rewrite format bits */
|
542
|
+
params->cmd.arith.format = tmp;
|
543
|
+
}
|
544
|
+
if (params->cmd.arith.format == sym_document) {
|
545
|
+
/* just amend datatype for now */
|
546
|
+
params->cmd.arith.datatype = 0x01;
|
547
|
+
}
|
548
|
+
}
|
549
|
+
|
550
|
+
static void
|
551
|
+
cb_params_arith_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
552
|
+
{
|
553
|
+
lcb_size_t ii;
|
554
|
+
|
555
|
+
if (argc < 1) {
|
556
|
+
rb_raise(rb_eArgError, "must be at least one key");
|
557
|
+
}
|
558
|
+
if (argc == 1) {
|
559
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
560
|
+
switch(TYPE(keys)) {
|
561
|
+
case T_ARRAY:
|
562
|
+
/* array of keys as a first argument */
|
563
|
+
params->cmd.arith.array = 1;
|
564
|
+
cb_params_arith_alloc(params, RARRAY_LEN(keys));
|
565
|
+
for (ii = 0; ii < params->cmd.arith.num; ++ii) {
|
566
|
+
cb_params_arith_init_item(params, ii, RARRAY_PTR(keys)[ii], params->cmd.arith.delta);
|
567
|
+
}
|
568
|
+
break;
|
569
|
+
case T_HASH:
|
570
|
+
/* key-delta pairs */
|
571
|
+
cb_params_arith_alloc(params, RHASH_SIZE(keys));
|
572
|
+
rb_hash_foreach(keys, cb_params_arith_extract_keys_i, (VALUE)params);
|
573
|
+
break;
|
574
|
+
default:
|
575
|
+
/* single key */
|
576
|
+
cb_params_arith_alloc(params, 1);
|
577
|
+
cb_params_arith_init_item(params, 0, keys, params->cmd.arith.delta);
|
578
|
+
}
|
579
|
+
} else {
|
580
|
+
/* just list of arguments */
|
581
|
+
cb_params_arith_alloc(params, argc);
|
582
|
+
for (ii = 0; ii < params->cmd.arith.num; ++ii) {
|
583
|
+
cb_params_arith_init_item(params, ii, RARRAY_PTR(argv)[ii], params->cmd.arith.delta);
|
584
|
+
}
|
585
|
+
}
|
586
|
+
}
|
587
|
+
|
588
|
+
|
589
|
+
/* STATS */
|
590
|
+
static void
|
591
|
+
cb_params_stats_alloc(struct params_st *params, lcb_size_t size)
|
592
|
+
{
|
593
|
+
lcb_size_t ii;
|
594
|
+
|
595
|
+
params->cmd.stats.num = size;
|
596
|
+
params->cmd.stats.items = xcalloc(size, sizeof(lcb_server_stats_cmd_t));
|
597
|
+
if (params->cmd.stats.items == NULL) {
|
598
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
599
|
+
}
|
600
|
+
params->cmd.stats.ptr = xcalloc(size, sizeof(lcb_server_stats_cmd_t *));
|
601
|
+
if (params->cmd.stats.ptr == NULL) {
|
602
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
603
|
+
}
|
604
|
+
for (ii = 0; ii < size; ++ii) {
|
605
|
+
params->cmd.stats.ptr[ii] = params->cmd.stats.items + ii;
|
606
|
+
}
|
607
|
+
}
|
608
|
+
|
609
|
+
static void
|
610
|
+
cb_params_stats_init_item(struct params_st *params, lcb_size_t idx,
|
611
|
+
VALUE key_obj)
|
612
|
+
{
|
613
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
614
|
+
params->cmd.stats.items[idx].v.v0.name = RSTRING_PTR(key_obj);
|
615
|
+
params->cmd.stats.items[idx].v.v0.nname = RSTRING_LEN(key_obj);
|
616
|
+
params->npayload += RSTRING_LEN(key_obj);
|
617
|
+
}
|
618
|
+
|
619
|
+
static void
|
620
|
+
cb_params_stats_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
621
|
+
{
|
622
|
+
lcb_size_t ii;
|
623
|
+
|
624
|
+
if (argc == 1) {
|
625
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
626
|
+
switch(TYPE(keys)) {
|
627
|
+
case T_ARRAY:
|
628
|
+
/* array of keys as a first argument */
|
629
|
+
params->cmd.stats.array = 1;
|
630
|
+
cb_params_stats_alloc(params, RARRAY_LEN(keys));
|
631
|
+
for (ii = 0; ii < params->cmd.stats.num; ++ii) {
|
632
|
+
cb_params_stats_init_item(params, ii, RARRAY_PTR(keys)[ii]);
|
633
|
+
}
|
634
|
+
break;
|
635
|
+
default:
|
636
|
+
/* single key */
|
637
|
+
cb_params_stats_alloc(params, 1);
|
638
|
+
cb_params_stats_init_item(params, 0, keys);
|
639
|
+
}
|
640
|
+
} else if (argc == 0) {
|
641
|
+
/* stat without argument (single empty struct) */
|
642
|
+
cb_params_stats_alloc(params, 1);
|
643
|
+
} else {
|
644
|
+
/* just list of arguments */
|
645
|
+
cb_params_stats_alloc(params, argc);
|
646
|
+
for (ii = 0; ii < params->cmd.stats.num; ++ii) {
|
647
|
+
cb_params_stats_init_item(params, ii, RARRAY_PTR(argv)[ii]);
|
648
|
+
}
|
649
|
+
}
|
650
|
+
}
|
651
|
+
|
652
|
+
|
653
|
+
/* REMOVE */
|
654
|
+
|
655
|
+
static void
|
656
|
+
cb_params_observe_alloc(struct params_st *params, lcb_size_t size)
|
657
|
+
{
|
658
|
+
lcb_size_t ii;
|
659
|
+
|
660
|
+
params->cmd.observe.num = size;
|
661
|
+
params->cmd.observe.items = xcalloc(size, sizeof(lcb_observe_cmd_t));
|
662
|
+
if (params->cmd.observe.items == NULL) {
|
663
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
664
|
+
}
|
665
|
+
params->cmd.observe.ptr = xcalloc(size, sizeof(lcb_observe_cmd_t *));
|
666
|
+
if (params->cmd.observe.ptr == NULL) {
|
667
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
668
|
+
}
|
669
|
+
for (ii = 0; ii < size; ++ii) {
|
670
|
+
params->cmd.observe.ptr[ii] = params->cmd.observe.items + ii;
|
671
|
+
}
|
672
|
+
}
|
673
|
+
|
674
|
+
static void
|
675
|
+
cb_params_observe_init_item(struct params_st *params, lcb_size_t idx, VALUE key_obj)
|
676
|
+
{
|
677
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
678
|
+
params->cmd.observe.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
679
|
+
params->cmd.observe.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
680
|
+
params->npayload += RSTRING_LEN(key_obj);
|
681
|
+
}
|
682
|
+
|
683
|
+
static void
|
684
|
+
cb_params_observe_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
685
|
+
{
|
686
|
+
lcb_size_t ii;
|
687
|
+
|
688
|
+
if (argc < 1) {
|
689
|
+
rb_raise(rb_eArgError, "must be at least one key");
|
690
|
+
}
|
691
|
+
if (argc == 1) {
|
692
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
693
|
+
switch(TYPE(keys)) {
|
694
|
+
case T_ARRAY:
|
695
|
+
/* array of keys as a first argument */
|
696
|
+
params->cmd.observe.array = 1;
|
697
|
+
cb_params_observe_alloc(params, RARRAY_LEN(keys));
|
698
|
+
for (ii = 0; ii < params->cmd.observe.num; ++ii) {
|
699
|
+
cb_params_observe_init_item(params, ii, RARRAY_PTR(keys)[ii]);
|
700
|
+
}
|
701
|
+
break;
|
702
|
+
default:
|
703
|
+
/* single key */
|
704
|
+
cb_params_observe_alloc(params, 1);
|
705
|
+
cb_params_observe_init_item(params, 0, keys);
|
706
|
+
}
|
707
|
+
} else {
|
708
|
+
/* just list of arguments */
|
709
|
+
cb_params_observe_alloc(params, argc);
|
710
|
+
for (ii = 0; ii < params->cmd.observe.num; ++ii) {
|
711
|
+
cb_params_observe_init_item(params, ii, RARRAY_PTR(argv)[ii]);
|
712
|
+
}
|
713
|
+
}
|
714
|
+
}
|
715
|
+
|
716
|
+
|
717
|
+
/* UNLOCK */
|
718
|
+
static void
|
719
|
+
cb_params_unlock_alloc(struct params_st *params, lcb_size_t size)
|
720
|
+
{
|
721
|
+
lcb_size_t ii;
|
722
|
+
|
723
|
+
params->cmd.unlock.num = size;
|
724
|
+
params->cmd.unlock.items = xcalloc(size, sizeof(lcb_unlock_cmd_t));
|
725
|
+
if (params->cmd.unlock.items == NULL) {
|
726
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
727
|
+
}
|
728
|
+
params->cmd.unlock.ptr = xcalloc(size, sizeof(lcb_unlock_cmd_t *));
|
729
|
+
if (params->cmd.unlock.ptr == NULL) {
|
730
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
731
|
+
}
|
732
|
+
for (ii = 0; ii < size; ++ii) {
|
733
|
+
params->cmd.unlock.ptr[ii] = params->cmd.unlock.items + ii;
|
734
|
+
}
|
735
|
+
}
|
736
|
+
|
737
|
+
static void
|
738
|
+
cb_params_unlock_init_item(struct params_st *params, lcb_size_t idx, VALUE key_obj, lcb_cas_t cas)
|
739
|
+
{
|
740
|
+
key_obj = unify_key(params->bucket, key_obj, 1);
|
741
|
+
params->cmd.unlock.items[idx].v.v0.key = RSTRING_PTR(key_obj);
|
742
|
+
params->cmd.unlock.items[idx].v.v0.nkey = RSTRING_LEN(key_obj);
|
743
|
+
params->cmd.unlock.items[idx].v.v0.cas = cas;
|
744
|
+
params->npayload += RSTRING_LEN(key_obj);
|
745
|
+
}
|
746
|
+
|
747
|
+
static int
|
748
|
+
cb_params_unlock_extract_keys_i(VALUE key, VALUE value, VALUE arg)
|
749
|
+
{
|
750
|
+
struct params_st *params = (struct params_st *)arg;
|
751
|
+
cb_params_unlock_init_item(params, params->idx++, key, NUM2ULL(value));
|
752
|
+
return ST_CONTINUE;
|
753
|
+
}
|
754
|
+
|
755
|
+
static void
|
756
|
+
cb_params_unlock_parse_options(struct params_st *params, VALUE options)
|
757
|
+
{
|
758
|
+
VALUE tmp;
|
759
|
+
|
760
|
+
if (NIL_P(options)) {
|
761
|
+
return;
|
762
|
+
}
|
763
|
+
tmp = rb_hash_aref(options, sym_cas);
|
764
|
+
if (tmp != Qnil) {
|
765
|
+
params->cmd.unlock.cas = NUM2ULL(tmp);
|
766
|
+
}
|
767
|
+
if (RTEST(rb_funcall(options, id_has_key_p, 1, sym_quiet))) {
|
768
|
+
params->cmd.unlock.quiet = RTEST(rb_hash_aref(options, sym_quiet));
|
769
|
+
}
|
770
|
+
}
|
771
|
+
|
772
|
+
static void
|
773
|
+
cb_params_unlock_parse_arguments(struct params_st *params, int argc, VALUE argv)
|
774
|
+
{
|
775
|
+
if (argc == 1) {
|
776
|
+
VALUE keys = RARRAY_PTR(argv)[0];
|
777
|
+
switch(TYPE(keys)) {
|
778
|
+
case T_HASH:
|
779
|
+
/* key-cas pairs */
|
780
|
+
cb_params_unlock_alloc(params, RHASH_SIZE(keys));
|
781
|
+
rb_hash_foreach(keys, cb_params_unlock_extract_keys_i, (VALUE)params);
|
782
|
+
break;
|
783
|
+
default:
|
784
|
+
/* single key */
|
785
|
+
cb_params_unlock_alloc(params, 1);
|
786
|
+
cb_params_unlock_init_item(params, 0, keys, params->cmd.unlock.cas);
|
787
|
+
}
|
788
|
+
} else {
|
789
|
+
rb_raise(rb_eArgError, "must be either Hash or single key with cas option");
|
790
|
+
}
|
791
|
+
}
|
792
|
+
|
793
|
+
|
794
|
+
/* VERSION */
|
795
|
+
static void
|
796
|
+
cb_params_version_alloc(struct params_st *params)
|
797
|
+
{
|
798
|
+
params->cmd.version.num = 1;
|
799
|
+
params->cmd.version.items = xcalloc(1, sizeof(lcb_server_version_cmd_t));
|
800
|
+
if (params->cmd.version.items == NULL) {
|
801
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
802
|
+
}
|
803
|
+
params->cmd.version.ptr = xcalloc(1, sizeof(lcb_server_version_cmd_t *));
|
804
|
+
if (params->cmd.version.ptr == NULL) {
|
805
|
+
rb_raise(eClientNoMemoryError, "failed to allocate memory for arguments");
|
806
|
+
}
|
807
|
+
params->cmd.version.ptr[0] = params->cmd.version.items;
|
808
|
+
}
|
809
|
+
|
810
|
+
|
811
|
+
/* common stuff */
|
812
|
+
void
|
813
|
+
cb_params_destroy(struct params_st *params)
|
814
|
+
{
|
815
|
+
#define _release_data_for(type) \
|
816
|
+
xfree(params->cmd.type.items); \
|
817
|
+
xfree(params->cmd.type.ptr);
|
818
|
+
|
819
|
+
switch (params->type) {
|
820
|
+
case cmd_get:
|
821
|
+
_release_data_for(get);
|
822
|
+
xfree(params->cmd.get.items_gr);
|
823
|
+
xfree(params->cmd.get.ptr_gr);
|
824
|
+
break;
|
825
|
+
case cmd_touch:
|
826
|
+
_release_data_for(touch);
|
827
|
+
break;
|
828
|
+
case cmd_arith:
|
829
|
+
_release_data_for(arith);
|
830
|
+
break;
|
831
|
+
case cmd_remove:
|
832
|
+
_release_data_for(remove);
|
833
|
+
break;
|
834
|
+
case cmd_store:
|
835
|
+
_release_data_for(store);
|
836
|
+
break;
|
837
|
+
case cmd_stats:
|
838
|
+
_release_data_for(stats);
|
839
|
+
break;
|
840
|
+
case cmd_version:
|
841
|
+
_release_data_for(version);
|
842
|
+
break;
|
843
|
+
case cmd_observe:
|
844
|
+
_release_data_for(observe);
|
845
|
+
break;
|
846
|
+
case cmd_unlock:
|
847
|
+
_release_data_for(unlock);
|
848
|
+
break;
|
849
|
+
}
|
850
|
+
#undef _release_data_for
|
851
|
+
}
|
852
|
+
|
853
|
+
struct build_params_st
|
854
|
+
{
|
855
|
+
struct params_st *params;
|
856
|
+
int argc;
|
857
|
+
VALUE argv;
|
858
|
+
};
|
859
|
+
|
860
|
+
static VALUE
|
861
|
+
do_params_build(VALUE ptr)
|
862
|
+
{
|
863
|
+
VALUE opts;
|
864
|
+
/* unpack arguments */
|
865
|
+
struct build_params_st *p = (struct build_params_st *)ptr;
|
866
|
+
struct params_st *params = p->params;
|
867
|
+
int argc = p->argc;
|
868
|
+
VALUE argv = p->argv;
|
869
|
+
|
870
|
+
/* extract options */
|
871
|
+
if (argc > 1 && TYPE(RARRAY_PTR(argv)[argc-1]) == T_HASH) {
|
872
|
+
opts = rb_ary_pop(argv);
|
873
|
+
--argc;
|
874
|
+
} else {
|
875
|
+
opts = Qnil;
|
876
|
+
}
|
877
|
+
|
878
|
+
params->npayload = PACKET_HEADER_SIZE; /* size of packet header */
|
879
|
+
switch (params->type) {
|
880
|
+
case cmd_touch:
|
881
|
+
params->cmd.touch.quiet = params->bucket->quiet;
|
882
|
+
params->cmd.touch.ttl = params->bucket->default_ttl;
|
883
|
+
cb_params_touch_parse_options(params, opts);
|
884
|
+
cb_params_touch_parse_arguments(params, argc, argv);
|
885
|
+
break;
|
886
|
+
case cmd_remove:
|
887
|
+
params->cmd.remove.quiet = params->bucket->quiet;
|
888
|
+
if (argc == 2) {
|
889
|
+
int type = TYPE(RARRAY_PTR(argv)[1]);
|
890
|
+
if (type == T_FIXNUM || type == T_BIGNUM) {
|
891
|
+
/* allow form delete("foo", 0xdeadbeef) */
|
892
|
+
--argc;
|
893
|
+
params->cmd.remove.cas = NUM2ULL(rb_ary_pop(argv));
|
894
|
+
}
|
895
|
+
}
|
896
|
+
cb_params_remove_parse_options(params, opts);
|
897
|
+
cb_params_remove_parse_arguments(params, argc, argv);
|
898
|
+
break;
|
899
|
+
case cmd_store:
|
900
|
+
if (argc == 1 && opts != Qnil) {
|
901
|
+
/* put last hash back because it is the value */
|
902
|
+
rb_ary_push(argv, opts);
|
903
|
+
opts = Qnil;
|
904
|
+
++argc;
|
905
|
+
}
|
906
|
+
params->cmd.store.datatype = 0x00;
|
907
|
+
params->cmd.store.ttl = params->bucket->default_ttl;
|
908
|
+
params->cmd.store.flags = flags_set_format(params->bucket->default_flags,
|
909
|
+
params->bucket->default_format);
|
910
|
+
params->cmd.store.observe = Qnil;
|
911
|
+
cb_params_store_parse_options(params, opts);
|
912
|
+
cb_params_store_parse_arguments(params, argc, argv);
|
913
|
+
break;
|
914
|
+
case cmd_get:
|
915
|
+
params->cmd.get.quiet = params->bucket->quiet;
|
916
|
+
cb_params_get_parse_options(params, opts);
|
917
|
+
cb_params_get_parse_arguments(params, argc, argv);
|
918
|
+
break;
|
919
|
+
case cmd_arith:
|
920
|
+
params->cmd.arith.delta = 1;
|
921
|
+
params->cmd.arith.format = params->bucket->default_format;
|
922
|
+
params->cmd.arith.ttl = params->bucket->default_ttl;
|
923
|
+
if (argc == 2 && TYPE(RARRAY_PTR(argv)[1]) == T_FIXNUM) {
|
924
|
+
/* allow form incr("foo", 1) */
|
925
|
+
--argc;
|
926
|
+
params->cmd.arith.delta = NUM2ULL(rb_ary_pop(argv)) & INT64_MAX;
|
927
|
+
}
|
928
|
+
cb_params_arith_parse_options(params, opts);
|
929
|
+
cb_params_arith_parse_arguments(params, argc, argv);
|
930
|
+
break;
|
931
|
+
case cmd_stats:
|
932
|
+
cb_params_stats_parse_arguments(params, argc, argv);
|
933
|
+
break;
|
934
|
+
case cmd_version:
|
935
|
+
cb_params_version_alloc(params);
|
936
|
+
break;
|
937
|
+
case cmd_observe:
|
938
|
+
cb_params_observe_parse_arguments(params, argc, argv);
|
939
|
+
break;
|
940
|
+
case cmd_unlock:
|
941
|
+
params->cmd.unlock.quiet = params->bucket->quiet;
|
942
|
+
if (argc == 2) {
|
943
|
+
int type = TYPE(RARRAY_PTR(argv)[1]);
|
944
|
+
if (type == T_FIXNUM || type == T_BIGNUM) {
|
945
|
+
/* allow form unlock("foo", 0xdeadbeef) */
|
946
|
+
--argc;
|
947
|
+
params->cmd.unlock.cas = NUM2ULL(rb_ary_pop(argv));
|
948
|
+
}
|
949
|
+
}
|
950
|
+
cb_params_unlock_parse_options(params, opts);
|
951
|
+
cb_params_unlock_parse_arguments(params, argc, argv);
|
952
|
+
break;
|
953
|
+
}
|
954
|
+
|
955
|
+
return Qnil;
|
956
|
+
}
|
957
|
+
|
958
|
+
void
|
959
|
+
cb_params_build(struct params_st *params, int argc, VALUE argv)
|
960
|
+
{
|
961
|
+
int fail = 0;
|
962
|
+
struct build_params_st args;
|
963
|
+
|
964
|
+
args.params = params;
|
965
|
+
args.argc = argc;
|
966
|
+
args.argv = argv;
|
967
|
+
rb_protect(do_params_build, (VALUE)&args, &fail);
|
968
|
+
if (fail) {
|
969
|
+
cb_params_destroy(params);
|
970
|
+
/* raise exception from protected block */
|
971
|
+
rb_jump_tag(fail);
|
972
|
+
}
|
973
|
+
}
|