couchbase 0.9.8 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +8 -0
- data/.yardopts +5 -0
- data/HISTORY.markdown +14 -10
- data/README.markdown +293 -98
- data/Rakefile +19 -24
- data/couchbase.gemspec +25 -7
- data/ext/couchbase_ext/couchbase_ext.c +2332 -0
- data/ext/couchbase_ext/extconf.rb +102 -0
- data/lib/couchbase.rb +20 -30
- data/lib/couchbase/bucket.rb +43 -112
- data/lib/couchbase/version.rb +3 -2
- data/tasks/benchmark.rake +6 -0
- data/tasks/compile.rake +52 -0
- data/tasks/doc.rake +27 -0
- data/tasks/test.rake +94 -0
- data/tasks/util.rake +21 -0
- data/test/profile/.gitignore +1 -0
- data/test/profile/Gemfile +6 -0
- data/test/profile/benchmark.rb +195 -0
- data/test/setup.rb +107 -18
- data/test/test_arithmetic.rb +98 -0
- data/test/test_async.rb +211 -0
- data/test/test_bucket.rb +126 -23
- data/test/test_cas.rb +59 -0
- data/test/test_couchbase.rb +22 -3
- data/test/test_delete.rb +63 -0
- data/test/test_errors.rb +82 -0
- data/test/test_flush.rb +49 -0
- data/test/test_format.rb +98 -0
- data/test/test_get.rb +236 -0
- data/test/test_stats.rb +53 -0
- data/test/test_store.rb +186 -0
- data/test/test_touch.rb +57 -0
- data/test/test_version.rb +17 -0
- metadata +72 -58
- data/lib/couchbase/couchdb.rb +0 -107
- data/lib/couchbase/document.rb +0 -71
- data/lib/couchbase/http_status.rb +0 -118
- data/lib/couchbase/latch.rb +0 -71
- data/lib/couchbase/memcached.rb +0 -372
- data/lib/couchbase/node.rb +0 -49
- data/lib/couchbase/rest_client.rb +0 -124
- data/lib/couchbase/view.rb +0 -182
- data/test/support/buckets-config.json +0 -843
- data/test/support/sample_design_doc.json +0 -9
- data/test/test_couchdb.rb +0 -98
- data/test/test_document.rb +0 -11
- data/test/test_latch.rb +0 -88
- data/test/test_memcached.rb +0 -59
- data/test/test_rest_client.rb +0 -14
- data/test/test_view.rb +0 -98
data/.gitignore
CHANGED
data/.yardopts
ADDED
data/HISTORY.markdown
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
-
|
1
|
+
## 1.0.0 / 2011-12-23
|
2
|
+
|
3
|
+
* Implement all operations using libcouchbase as backend
|
4
|
+
* Remove views code. It will be re-added in 1.1 version
|
5
|
+
|
6
|
+
## 0.9.8 / 2011-12-16
|
2
7
|
|
3
8
|
* Fix RCBC-10: It was impossible to store data in non-default buckets
|
4
9
|
|
5
|
-
|
10
|
+
## 0.9.7 / 2011-10-04
|
6
11
|
|
7
12
|
* Fix design doc removing
|
8
13
|
* Fix 'set' method signature: add missing options argument
|
9
14
|
* Rename gem to 'couchbase' for easy of use. The github project still
|
10
15
|
is 'couchbase-ruby-client'
|
11
16
|
|
12
|
-
|
17
|
+
## 0.9.6 / 2011-10-04
|
13
18
|
|
14
19
|
* Fix bug with decoding multiget result
|
15
20
|
* Allow create design documents from IO and String
|
@@ -18,11 +23,11 @@
|
|
18
23
|
* Remove dependency on libyajl library: it bundled with yaji now
|
19
24
|
* Update rake tasks: create zip- and tar-balls
|
20
25
|
|
21
|
-
|
26
|
+
## 0.9.5 / 2011-08-24
|
22
27
|
|
23
28
|
* Update installation notes in README
|
24
29
|
|
25
|
-
|
30
|
+
## 0.9.4 / 2011-08-24
|
26
31
|
|
27
32
|
* Use streaming json parser to iterate over view results
|
28
33
|
* Update memcached gem dependency to v1.3
|
@@ -32,23 +37,22 @@
|
|
32
37
|
* Fix bug with unicode parsing in config listener
|
33
38
|
* Add more unit tests
|
34
39
|
|
35
|
-
|
40
|
+
## 0.9.3 / 2011-07-29
|
36
41
|
|
37
42
|
* Use Latch (via Mutex and ConditionVariable) to wait until initial
|
38
43
|
setup will be finished.
|
39
44
|
* Update prefix for development views (from '$dev_' to 'dev_')
|
40
45
|
|
41
|
-
|
46
|
+
## 0.9.2 / 2011-07-29
|
42
47
|
|
43
48
|
* Use zero TTL by default to store records forever
|
44
49
|
* Update documentation
|
45
50
|
* Sleep if setup isn't done
|
46
51
|
|
47
|
-
|
48
|
-
=== 0.9.1 / 2011-07-25
|
52
|
+
## 0.9.1 / 2011-07-25
|
49
53
|
|
50
54
|
* Minor bugfix for RestClient initialization
|
51
55
|
|
52
|
-
|
56
|
+
## 0.9.0 / 2011-07-25
|
53
57
|
|
54
58
|
* Initial public release
|
data/README.markdown
CHANGED
@@ -1,135 +1,330 @@
|
|
1
|
-
Couchbase Ruby Client
|
2
|
-
=====================
|
1
|
+
# Couchbase Ruby Client
|
3
2
|
|
4
3
|
This is the official client library for use with Couchbase Server.
|
5
4
|
|
6
|
-
INSTALL
|
7
|
-
=======
|
5
|
+
## INSTALL
|
8
6
|
|
9
7
|
This gem depends on a couple of external libraries to work with JSON and
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
Couchbase Server. For JSON it uses [yajl-ruby][1] which is built atop
|
9
|
+
[yajl][2]. For Couchbase iteraction it uses [libcouchbase][3]. The first
|
10
|
+
dependency shouldn't cause any issues because it will bundle yajl in the c
|
11
|
+
extensions. To install yajl-ruby use following command:
|
14
12
|
|
15
|
-
$
|
13
|
+
$ gem install yajl-ruby
|
16
14
|
|
17
|
-
|
15
|
+
In most cases installing libcouchbase is just as simple.
|
16
|
+
|
17
|
+
### MacOS (Homebrew)
|
18
|
+
|
19
|
+
$ brew install libcouchbase
|
20
|
+
|
21
|
+
Or if our pull request isn't yet merged:
|
22
|
+
|
23
|
+
$ brew install http://packages.couchbase.com/clients/c/homebrew/libvbucket.rb
|
24
|
+
$ brew install http://packages.couchbase.com/clients/c/homebrew/libcouchbase.rb
|
25
|
+
|
26
|
+
### Debian (Ubuntu)
|
27
|
+
|
28
|
+
Download packages depending on your architecture:
|
29
|
+
|
30
|
+
$ wget http://packages.couchbase.com/clients/c/libvbucket{1,1-dbg,-dev}_1.8.0.1-1_amd64.deb
|
31
|
+
$ wget http://packages.couchbase.com/clients/c/libcouchbase{1,1-dbg,-dev}_1.0.0-1_amd64.deb
|
32
|
+
|
33
|
+
or
|
34
|
+
|
35
|
+
$ wget http://packages.couchbase.com/clients/c/libvbucket{1,1-dbg,-dev}_1.8.0.1-1_i386.deb
|
36
|
+
$ wget http://packages.couchbase.com/clients/c/libcouchbase{1,1-dbg,-dev}_1.0.0-1_i386.deb
|
37
|
+
|
38
|
+
Then install them using dpkg tool
|
39
|
+
|
40
|
+
$ sudo dpkg -i lib{vbucket,couchbase}*.deb
|
41
|
+
|
42
|
+
### Centos (Redhat and rpm-based systems)
|
43
|
+
|
44
|
+
Download packages depending on your architecture:
|
45
|
+
|
46
|
+
$ wget http://packages.couchbase.com/clients/c/libvbucket{1,-debuginfo,-devel}-1.8.0.1-1.x86_64.rpm
|
47
|
+
$ wget http://packages.couchbase.com/clients/c/libcouchbase{1,-debuginfo,-devel}-1.0.0-1.x86_64.rpm
|
48
|
+
|
49
|
+
or
|
50
|
+
|
51
|
+
$ wget http://packages.couchbase.com/clients/c/libvbucket{1,-debuginfo,-devel}-1.8.0.1-1.i386.rpm
|
52
|
+
$ wget http://packages.couchbase.com/clients/c/libcouchbase{1,-debuginfo,-devel}-1.0.0-1.i386.rpm
|
53
|
+
|
54
|
+
Then install them using rpm tool
|
55
|
+
|
56
|
+
$ sudo rpm -ivh lib{vbucket,couchbase}*.rpm
|
57
|
+
|
58
|
+
### Couchbase gem
|
59
|
+
|
60
|
+
Now install the couchbase gem itself
|
18
61
|
|
19
62
|
$ gem install couchbase
|
20
63
|
|
21
|
-
|
22
|
-
|
64
|
+
|
65
|
+
## USAGE
|
23
66
|
|
24
67
|
First of all you need to load library:
|
25
68
|
|
26
69
|
require 'couchbase'
|
27
70
|
|
28
|
-
|
29
|
-
|
30
|
-
|
71
|
+
There are several ways to establish new connection to Couchbase Server.
|
72
|
+
By default it uses the `http://localhost:8091/pools/default/buckets/default`
|
73
|
+
as the endpoint. The client will automatically adjust configuration when
|
74
|
+
the cluster will rebalance its nodes when nodes are added or deleted
|
75
|
+
therefore this client is "smart".
|
76
|
+
|
77
|
+
c = Couchbase.new
|
31
78
|
|
79
|
+
This is equivalent to following forms:
|
80
|
+
|
81
|
+
c = Couchbase.new("http://localhost:8091/pools/default/buckets/default")
|
32
82
|
c = Couchbase.new("http://localhost:8091/pools/default")
|
33
|
-
c = Couchbase.new("http://localhost:8091
|
34
|
-
c = Couchbase.new("
|
35
|
-
|
36
|
-
|
37
|
-
This gem supports memcached API accessible for [memcached][5] client
|
38
|
-
with a bit syntax sugar:
|
39
|
-
|
40
|
-
c.set('password', 'secret')
|
41
|
-
c.get('password') #=> "secret"
|
42
|
-
c['password'] = 'secret'
|
43
|
-
c['password'] #=> "secret"
|
44
|
-
c['counter'] = 1 #=> 1
|
45
|
-
c['counter'] += 1 #=> 2
|
46
|
-
c['counter'] #=> 2
|
47
|
-
c.increment('counter', 10)
|
48
|
-
c.flush
|
83
|
+
c = Couchbase.new("http://localhost:8091")
|
84
|
+
c = Couchbase.new(:host => "localhost")
|
85
|
+
c = Couchbase.new(:host => "localhost", :port => 8091)
|
86
|
+
c = Couchbase.new(:pool => "default", :bucket => "default")
|
49
87
|
|
50
|
-
|
51
|
-
you can handle them in map/reduce function from CouchDB views. For
|
52
|
-
example, store a couple of posts using memcached API:
|
88
|
+
The hash parameters take precedence on string URL.
|
53
89
|
|
54
|
-
|
55
|
-
|
56
|
-
:date => '2009/01/30 18:04:11'}
|
57
|
-
c['bought-a-cat'] = {:title => 'Biking',
|
58
|
-
:body => 'My biggest hobby is mountainbiking. The other day...',
|
59
|
-
:date => '2009/01/30 18:04:11'}
|
60
|
-
c['hello-world'] = {:title => 'Hello World',
|
61
|
-
:body => 'Well hello and welcome to my new blog...',
|
62
|
-
:date => '2009/01/15 15:52:20'}
|
63
|
-
c.all_docs.count #=> 3
|
90
|
+
The library supports both synchronous and asynchronous mode. You can
|
91
|
+
choose either using the `:async` option or attribute.
|
64
92
|
|
65
|
-
|
66
|
-
|
93
|
+
c = Couchbase.new(:async => true)
|
94
|
+
# ... asynchronous mode
|
95
|
+
c.async = false
|
96
|
+
# ... synchronous mode
|
67
97
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
"recent_posts": {
|
73
|
-
"map": "function(doc){if(doc.date && doc.title){emit(doc.date, doc.title);}}"
|
74
|
-
}
|
75
|
-
}
|
76
|
-
}
|
98
|
+
In asynchronous mode all operations will return control to caller
|
99
|
+
without blocking current thread. You can pass the block to method and it
|
100
|
+
will be called with result when the operation will be completed. You
|
101
|
+
need to run event loop when you scheduled your operations:
|
77
102
|
|
78
|
-
|
79
|
-
|
103
|
+
c = Couchbase.new(:async => true)
|
104
|
+
c.run do |conn|
|
105
|
+
conn.get("foo") {|ret| puts ret.value}
|
106
|
+
conn.set("bar", "baz")
|
107
|
+
end
|
80
108
|
|
81
|
-
|
109
|
+
The handlers could be nested
|
82
110
|
|
83
|
-
|
111
|
+
c.run do |conn|
|
112
|
+
conn.get("foo") do |ret|
|
113
|
+
conn.incr(ret.value, :initial => 0)
|
114
|
+
end
|
115
|
+
end
|
84
116
|
|
85
|
-
|
86
|
-
|
87
|
-
blog.recent_posts #=> [#<Couchbase::Document:14244860 {"id"=>"hello-world", "key"=>"2009/01/15 15:52:20", "value"=>"Hello World"}>,...]
|
117
|
+
The asynchronous callback receives instance of `Couchbase::Result` which
|
118
|
+
responds to several methods to figure out what was happened:
|
88
119
|
|
89
|
-
|
90
|
-
easily and if your code won't keep links to the documents GC might free
|
91
|
-
them as soon as it decide they are unreachable, because parser doesn't
|
92
|
-
store global JSON tree.
|
120
|
+
* `success?`. Returns `true` if operation succed.
|
93
121
|
|
94
|
-
|
95
|
-
|
96
|
-
# with doc object
|
97
|
-
end
|
122
|
+
* `error`. Returns `nil` or exception object (subclass of
|
123
|
+
`Couchbase::Error::Base`) if something went wrong.
|
98
124
|
|
99
|
-
|
125
|
+
* `key`
|
100
126
|
|
101
|
-
|
102
|
-
posts_by_date = Hash.new{|h,k| h[k] = []}
|
103
|
-
enum = c.all_docs.each # request hasn't issued yet
|
104
|
-
enum.inject(posts_by_date) do |acc, doc|
|
105
|
-
acc[date] = Date.strptime(doc['date'], '%Y/%m/%d')
|
106
|
-
acc
|
107
|
-
end
|
127
|
+
* `value`
|
108
128
|
|
109
|
-
|
110
|
-
`200 OK` and partial results. By default the library raises exception as
|
111
|
-
soon as errors detected in the result stream, but you can define the
|
112
|
-
callback `on_error` to intercept these errors and do something more
|
113
|
-
useful.
|
129
|
+
* `flags`
|
114
130
|
|
115
|
-
|
116
|
-
|
131
|
+
* `cas`. The CAS version tag.
|
132
|
+
|
133
|
+
* `node`. Node address. It is used in flush and stats commands.
|
134
|
+
|
135
|
+
* `operation`. The symbol, representing an operation.
|
117
136
|
|
118
|
-
view.on_error do |from, reason|
|
119
|
-
logger.warn("#{view.inspect} received the error '#{reason}' from #{from}")
|
120
|
-
end
|
121
137
|
|
122
|
-
|
123
|
-
|
124
|
-
|
138
|
+
To handle global errors in async mode `#on_error` callback should be
|
139
|
+
used. It can be set in following fashions:
|
140
|
+
|
141
|
+
c.on_error do |opcode, key, exc|
|
142
|
+
...
|
125
143
|
end
|
126
144
|
|
127
|
-
|
128
|
-
|
129
|
-
|
145
|
+
handler = lambda {|opcode, key, exc| ...}
|
146
|
+
c.on_error = handler
|
147
|
+
|
148
|
+
By default connection uses `:quiet` mode. This mean it won't raise
|
149
|
+
exceptions when the given key is not exists:
|
150
|
+
|
151
|
+
c.get("missing-key") #=> nil
|
152
|
+
|
153
|
+
It could be useful when you are trying to make you code a bit efficient
|
154
|
+
by avoiding exception handling. (See `#add` and `#replace` operations).
|
155
|
+
You can turn on these exception by passing `:quiet => false` when you
|
156
|
+
are instantiating the connection or change corresponding attribute:
|
157
|
+
|
158
|
+
c.quiet = false
|
159
|
+
c.get("missing-key") #=> raise Couchbase::Error::NotFound
|
160
|
+
c.get("missing-key", :quiet => true) #=> nil
|
161
|
+
|
162
|
+
The library supports three different formats for representing values:
|
163
|
+
|
164
|
+
* `:document` (default) format supports most of ruby types which could
|
165
|
+
be mapped to JSON data (hashes, arrays, string, numbers). A future
|
166
|
+
version will be able to run map/reduce queries on the values in the
|
167
|
+
document form (hashes)
|
168
|
+
|
169
|
+
* `:marshal` This format avoids any conversions to be applied to your
|
170
|
+
data, but your data should be passed as String. This is useful for
|
171
|
+
building custom algorithms or formats. For example to implement a set:
|
172
|
+
http://dustin.github.com/2011/02/17/memcached-set.html
|
173
|
+
|
174
|
+
* `:plain` Use this format if you'd like to transparently serialize your
|
175
|
+
ruby object with standard `Marshal.dump` and `Marshal.load` methods
|
176
|
+
|
177
|
+
The couchbase API is the superset of [Memcached binary protocol][4], so
|
178
|
+
you can use its operations.
|
179
|
+
|
180
|
+
### Get
|
181
|
+
|
182
|
+
val = c.get("foo")
|
183
|
+
val, flags, cas = c.get("foo", :extended => true)
|
184
|
+
|
185
|
+
Get and touch
|
186
|
+
|
187
|
+
val = c.get("foo", :ttl => 10)
|
188
|
+
|
189
|
+
Get multiple values. In quiet mode will put `nil` values on missing
|
190
|
+
positions:
|
191
|
+
|
192
|
+
vals = c.get("foo", "bar", "baz")
|
193
|
+
c.get("foo"){|val, key| ... }
|
194
|
+
c.get("foo", :extended => true){|val, key, flags, cas| ... }
|
195
|
+
|
196
|
+
Get multiple values with extended information. The result will
|
197
|
+
represented by hash with tuples `[value, flags, cas]` as a value.
|
198
|
+
|
199
|
+
vals = c.get("foo", "bar", "baz", :extended => true)
|
200
|
+
vals.inspect #=> {"baz"=>["3", 0, 4784582192793125888],
|
201
|
+
"foo"=>["1", 0, 8835713818674332672],
|
202
|
+
"bar"=>["2", 0, 10805929834096100352]}
|
203
|
+
|
204
|
+
Hash-like syntax
|
205
|
+
|
206
|
+
c["foo"]
|
207
|
+
c["foo", "bar", "baz"]
|
208
|
+
c["foo", {:extended => true}]
|
209
|
+
c["foo", :extended => true] # for ruby 1.9.x only
|
210
|
+
|
211
|
+
### Touch
|
212
|
+
|
213
|
+
c.touch("foo") # use :default_ttl
|
214
|
+
c.touch("foo", 10)
|
215
|
+
c.touch("foo", :ttl => 10)
|
216
|
+
c.touch("foo" => 10, "bar" => 20)
|
217
|
+
c.touch("foo" => 10, "bar" => 20){|key, success| ... }
|
218
|
+
|
219
|
+
### Set
|
220
|
+
|
221
|
+
c.set("foo", "bar")
|
222
|
+
c.set("foo", "bar", :flags => 0x1000, :ttl => 30, :format => :plain)
|
223
|
+
c["foo"] = "bar"
|
224
|
+
c["foo", {:flags => 0x1000, :format => :plain}] = "bar"
|
225
|
+
c["foo", :flags => 0x1000] = "bar" # for ruby 1.9.x only
|
226
|
+
c.set("foo", "bar", :cas => 8835713818674332672)
|
227
|
+
c.set("foo", "bar"){|cas, key, operation| ... }
|
228
|
+
|
229
|
+
### Add
|
230
|
+
|
231
|
+
Add command will fail if the key already exists. It accepts the same
|
232
|
+
options as set command above.
|
233
|
+
|
234
|
+
c.add("foo", "bar")
|
235
|
+
c.add("foo", "bar", :flags => 0x1000, :ttl => 30, :format => :plain)
|
236
|
+
|
237
|
+
### Replace
|
238
|
+
|
239
|
+
The replace command will fail if the key already exists. It accepts the same
|
240
|
+
options as set command above.
|
241
|
+
|
242
|
+
c.replace("foo", "bar")
|
243
|
+
|
244
|
+
### Prepend/Append
|
245
|
+
|
246
|
+
These commands are meaningful when you are using the `:plain` value format,
|
247
|
+
because the concatenation is performed by server which has no idea how
|
248
|
+
to merge to JSON values or values in ruby Marshal format. You may receive
|
249
|
+
an `Couchbase::Error::ValueFormat` error.
|
250
|
+
|
251
|
+
c.set("foo", "world")
|
252
|
+
c.append("foo", "!")
|
253
|
+
c.prepend("foo", "Hello, ")
|
254
|
+
c.get("foo") #=> "Hello, world!"
|
255
|
+
|
256
|
+
### Increment/Decrement
|
257
|
+
|
258
|
+
These commands increment the value assigned to the key. It will raise
|
259
|
+
Couchbase::Error::DeltaBadval if the delta or value is not a number.
|
260
|
+
|
261
|
+
c.set("foo", 1)
|
262
|
+
c.incr("foo") #=> 2
|
263
|
+
c.incr("foo", :delta => 2) #=> 4
|
264
|
+
c.incr("foo", 4) #=> 8
|
265
|
+
c.incr("foo", -1) #=> 7
|
266
|
+
c.incr("foo", -100) #=> 0
|
267
|
+
c.incr("foo"){|val, cas| ... }
|
268
|
+
|
269
|
+
c.set("foo", 10)
|
270
|
+
c.decr("foo", 1) #=> 9
|
271
|
+
c.decr("foo", 100) #=> 0
|
272
|
+
c.decr("foo"){|val, cas| ... }
|
273
|
+
|
274
|
+
c.incr("missing1", :initial => 10) #=> 10
|
275
|
+
c.incr("missing1", :initial => 10) #=> 11
|
276
|
+
c.incr("missing2", :create => true) #=> 0
|
277
|
+
c.incr("missing2", :create => true) #=> 1
|
278
|
+
|
279
|
+
Note that it isn't the same as increment/decrement in ruby, which is
|
280
|
+
performed on client side with following `set` operation:
|
281
|
+
|
282
|
+
c["foo"] = 10
|
283
|
+
c["foo"] -= 20 #=> -10
|
284
|
+
|
285
|
+
### Delete
|
286
|
+
|
287
|
+
c.delete("foo")
|
288
|
+
c.delete("foo", :cas => 8835713818674332672)
|
289
|
+
c.delete("foo", 8835713818674332672)
|
290
|
+
c.delete{|key, success| ... }
|
291
|
+
|
292
|
+
### Flush
|
293
|
+
|
294
|
+
Flush the items in the cluster.
|
295
|
+
|
296
|
+
c.flush
|
297
|
+
c.flush{|node, success| ... }
|
298
|
+
|
299
|
+
### Stats
|
300
|
+
|
301
|
+
Return statistics from each node in the cluster
|
302
|
+
|
303
|
+
c.stats
|
304
|
+
c.stats{|node, key, value| ... }
|
305
|
+
|
306
|
+
The result is represented as a hash with the server node address as
|
307
|
+
the key and stats as key-value pairs.
|
308
|
+
|
309
|
+
{
|
310
|
+
"172.16.16.76:12008"=>
|
311
|
+
{
|
312
|
+
"threads"=>"4",
|
313
|
+
"connection_structures"=>"22",
|
314
|
+
"ep_max_txn_size"=>"10000",
|
315
|
+
...
|
316
|
+
},
|
317
|
+
"172.16.16.76:12000"=>
|
318
|
+
{
|
319
|
+
"threads"=>"4",
|
320
|
+
"connection_structures"=>"447",
|
321
|
+
"ep_max_txn_size"=>"10000",
|
322
|
+
...
|
323
|
+
},
|
324
|
+
...
|
325
|
+
}
|
130
326
|
|
131
327
|
[1]: https://github.com/brianmario/yajl-ruby/
|
132
|
-
[2]:
|
133
|
-
[3]: http://
|
134
|
-
[4]:
|
135
|
-
[5]: https://github.com/fauna/memcached/
|
328
|
+
[2]: http://lloyd.github.com/yajl/
|
329
|
+
[3]: http://www.couchbase.com/develop/c/current
|
330
|
+
[4]: http://code.google.com/p/memcached/wiki/BinaryProtocolRevamped
|