couchbase 1.2.2-x86-mingw32 → 1.2.3-x86-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- data/CONTRIBUTING.markdown +75 -0
- data/RELEASE_NOTES.markdown +8 -0
- data/ext/couchbase_ext/extconf.rb +1 -0
- data/ext/couchbase_ext/gethrtime.c +5 -0
- data/ext/couchbase_ext/store.c +17 -1
- data/lib/active_support/cache/couchbase_store.rb +23 -7
- data/lib/couchbase.rb +14 -1
- data/lib/couchbase/version.rb +1 -1
- data/tasks/util.rake +1 -1
- data/test/test_couchbase.rb +49 -0
- data/test/test_couchbase_rails_cache_store.rb +23 -0
- metadata +5 -4
@@ -0,0 +1,75 @@
|
|
1
|
+
We've decided to use "gerrit" for our code review system, making it
|
2
|
+
easier for all of us to contribute with code and comments.
|
3
|
+
|
4
|
+
1. Visit http://review.couchbase.org and "Register" for an account
|
5
|
+
2. Review http://review.couchbase.org/static/individual_agreement.html
|
6
|
+
3. Agree to agreement by visiting http://review.couchbase.org/#/settings/agreements
|
7
|
+
4. If you do not receive an email, please contact us
|
8
|
+
5. Check out the `couchbase-ruby-client` area http://review.couchbase.org/#/q/status:open+project:couchbase-ruby-client,n,z
|
9
|
+
6. Join us on IRC at #libcouchbase on Freenode :-)
|
10
|
+
|
11
|
+
We normally don't go looking for stuff in gerrit, so you should add at
|
12
|
+
least me `"Sergey Avseyev" <sergey.avseyev@gmail.com>` as a reviewer
|
13
|
+
for your patch (and I'll know who else to add and add them for you).
|
14
|
+
|
15
|
+
## Contributing Using Repo Tool
|
16
|
+
|
17
|
+
Follow ["Uploading Changes" guide][1] on the site if you have some code to contribute.
|
18
|
+
|
19
|
+
All you should need to set up your development environment should be:
|
20
|
+
|
21
|
+
~ % mkdir couchbase-ruby
|
22
|
+
~ % cd couchbase-ruby
|
23
|
+
~/couchbase-ruby % repo init -u git://github.com/trondn/manifests.git -m ruby.xml
|
24
|
+
~/couchbase-ruby % repo sync
|
25
|
+
~/couchbase-ruby % repo start my-branch-name --all
|
26
|
+
~/couchbase-ruby % make
|
27
|
+
|
28
|
+
This will build the latest version of `libcouchbase`,
|
29
|
+
`couchbase-ruby-client` and `couchbase-ruby-client` libraries. You must
|
30
|
+
have a C and C++ compiler installed, automake, autoconf.
|
31
|
+
|
32
|
+
If you have to make any changes just commit them before you upload
|
33
|
+
them to gerrit with the following command:
|
34
|
+
|
35
|
+
~/couchbase-ruby/client % repo upload
|
36
|
+
|
37
|
+
You might experience a problem trying to upload the patches if you've
|
38
|
+
selected a different login name at http://review.couchbase.org than
|
39
|
+
your login name. Don't worry, all you need to do is to add the
|
40
|
+
following to your ~/.gitconfig file:
|
41
|
+
|
42
|
+
[review "review.couchbase.org"]
|
43
|
+
username = YOURNAME
|
44
|
+
|
45
|
+
## Contributing Using Plain Git
|
46
|
+
|
47
|
+
If you not so familiar with repo tool and its workflow there is
|
48
|
+
alternative way to do the same job. Lets assume you have installed
|
49
|
+
couchbase gem and libcouchbase from official packages and would you to
|
50
|
+
contribute to couchbase-client gem only. Then you just need to complete
|
51
|
+
gerrit registration steps above and clone the source repository
|
52
|
+
(remember the repository on github.com is just a mirror):
|
53
|
+
|
54
|
+
~ % git clone ssh://YOURNAME@review.couchbase.org:29418/couchbase-ruby-client.git
|
55
|
+
|
56
|
+
Install [`commit-msg` hook][2]:
|
57
|
+
|
58
|
+
~/couchbase-ruby-client % scp -p -P 29418 YOURNAME@review.couchbase.org:hooks/commit-msg .git/hooks/
|
59
|
+
|
60
|
+
Make your changes and upload them for review:
|
61
|
+
|
62
|
+
~/couchbase-ruby-client % git commit
|
63
|
+
~/couchbase-ruby-client % git push origin HEAD:refs/for/master
|
64
|
+
|
65
|
+
If you need to fix or add something to your patch, do it and re-upload
|
66
|
+
the changes (all you need is to keep `Change-Id:` line the same to
|
67
|
+
allow gerrit to track the patch.
|
68
|
+
|
69
|
+
~/couchbase-ruby-client % git commit --amend
|
70
|
+
~/couchbase-ruby-client % git push origin HEAD:refs/for/master
|
71
|
+
|
72
|
+
Happy hacking!
|
73
|
+
|
74
|
+
[1]: http://review.couchbase.org/Documentation/user-upload.html
|
75
|
+
[2]: http://review.couchbase.org/Documentation/user-changeid.html
|
data/RELEASE_NOTES.markdown
CHANGED
@@ -3,6 +3,14 @@
|
|
3
3
|
This document is a list of user visible feature changes and important
|
4
4
|
bugfixes. Do not forget to update this doc in every important patch.
|
5
5
|
|
6
|
+
## 1.2.3 (2013-04-02)
|
7
|
+
|
8
|
+
* [major] Make ActiveSupport::Cache::CouchbaseStore threadsafe
|
9
|
+
|
10
|
+
* [minor] Check for gethrtime. Needed for solaris/smartos
|
11
|
+
|
12
|
+
* [minor] Update documentation bits regarding SET operations
|
13
|
+
|
6
14
|
## 1.2.2 (2013-02-11)
|
7
15
|
|
8
16
|
* [minor] Bucket#design_docs will return a Hash with DesignDoc
|
@@ -135,6 +135,7 @@ have_type("st_index_t")
|
|
135
135
|
have_func("clock_gettime")
|
136
136
|
have_func("gettimeofday")
|
137
137
|
have_func("QueryPerformanceCounter")
|
138
|
+
have_func("gethrtime")
|
138
139
|
have_func("rb_hash_lookup2")
|
139
140
|
have_func("rb_thread_fd_select")
|
140
141
|
have_func("rb_thread_blocking_region")
|
@@ -16,6 +16,9 @@
|
|
16
16
|
*/
|
17
17
|
|
18
18
|
#include "couchbase_ext.h"
|
19
|
+
|
20
|
+
#ifndef HAVE_GETHRTIME
|
21
|
+
|
19
22
|
#include <stdlib.h>
|
20
23
|
#include <time.h>
|
21
24
|
#include <assert.h>
|
@@ -122,3 +125,5 @@ hrtime_t gethrtime(void)
|
|
122
125
|
#error "I don't know how to build a highres clock..."
|
123
126
|
#endif
|
124
127
|
}
|
128
|
+
|
129
|
+
#endif
|
data/ext/couchbase_ext/store.c
CHANGED
@@ -228,6 +228,22 @@ cb_bucket_store(lcb_storage_t cmd, int argc, VALUE *argv, VALUE self)
|
|
228
228
|
* @example Store the key which will be expired in 2 seconds using relative TTL.
|
229
229
|
* c.set("foo", "bar", :ttl => 2)
|
230
230
|
*
|
231
|
+
* @example Perform multi-set operation. It takes a Hash store its keys/values into the bucket
|
232
|
+
* c.set("foo1" => "bar1", "foo2" => "bar2")
|
233
|
+
* #=> {"foo1" => cas1, "foo2" => cas2}
|
234
|
+
*
|
235
|
+
* @example More advanced multi-set using asynchronous mode
|
236
|
+
* c.run do
|
237
|
+
* # fire and forget
|
238
|
+
* c.set("foo1", "bar1", :ttl => 10)
|
239
|
+
* # receive result into the callback
|
240
|
+
* c.set("foo2", "bar2", :ttl => 10) do |ret|
|
241
|
+
* if ret.success?
|
242
|
+
* puts ret.cas
|
243
|
+
* end
|
244
|
+
* end
|
245
|
+
* end
|
246
|
+
*
|
231
247
|
* @example Store the key which will be expired in 2 seconds using absolute TTL.
|
232
248
|
* c.set("foo", "bar", :ttl => Time.now.to_i + 2)
|
233
249
|
*
|
@@ -235,7 +251,7 @@ cb_bucket_store(lcb_storage_t cmd, int argc, VALUE *argv, VALUE self)
|
|
235
251
|
* c.set("foo", {"bar" => "baz}, :format => :document)
|
236
252
|
*
|
237
253
|
* @example Use hash-like syntax to store the value
|
238
|
-
* c
|
254
|
+
* c["foo"] = {"bar" => "baz}
|
239
255
|
*
|
240
256
|
* @example Use extended hash-like syntax
|
241
257
|
* c["foo", {:flags => 0x1000, :format => :plain}] = "bar"
|
@@ -19,6 +19,7 @@ require 'couchbase'
|
|
19
19
|
require 'securerandom'
|
20
20
|
require 'active_support/core_ext/array/extract_options'
|
21
21
|
require 'active_support/cache'
|
22
|
+
require 'monitor'
|
22
23
|
|
23
24
|
module ActiveSupport
|
24
25
|
module Cache
|
@@ -56,6 +57,7 @@ module ActiveSupport
|
|
56
57
|
options[:key_prefix] ||= options.delete(:namespace)
|
57
58
|
args.push(options)
|
58
59
|
@data = ::Couchbase::Bucket.new(*args)
|
60
|
+
@lock = Monitor.new
|
59
61
|
end
|
60
62
|
|
61
63
|
# Fetches data from the cache, using the given key.
|
@@ -182,7 +184,9 @@ module ActiveSupport
|
|
182
184
|
options[:format] = :plain
|
183
185
|
end
|
184
186
|
instrument(:read_multi, names, options) do
|
185
|
-
@
|
187
|
+
@lock.synchronize do
|
188
|
+
@data.get(names, options)
|
189
|
+
end
|
186
190
|
end
|
187
191
|
rescue ::Couchbase::Error::Base => e
|
188
192
|
logger.error("#{e.class}: #{e.message}") if logger
|
@@ -243,7 +247,9 @@ module ActiveSupport
|
|
243
247
|
options[:create] = true
|
244
248
|
instrument(:increment, name, options) do |payload|
|
245
249
|
payload[:amount] = amount if payload
|
246
|
-
@
|
250
|
+
@lock.synchronize do
|
251
|
+
@data.incr(name, amount, options)
|
252
|
+
end
|
247
253
|
end
|
248
254
|
rescue ::Couchbase::Error::Base => e
|
249
255
|
logger.error("#{e.class}: #{e.message}") if logger
|
@@ -275,7 +281,9 @@ module ActiveSupport
|
|
275
281
|
options[:create] = true
|
276
282
|
instrument(:decrement, name, options) do |payload|
|
277
283
|
payload[:amount] = amount if payload
|
278
|
-
@
|
284
|
+
@lock.synchronize do
|
285
|
+
@data.decr(name, amount, options)
|
286
|
+
end
|
279
287
|
end
|
280
288
|
rescue ::Couchbase::Error::Base => e
|
281
289
|
logger.error("#{e.class}: #{e.message}") if logger
|
@@ -289,14 +297,18 @@ module ActiveSupport
|
|
289
297
|
#
|
290
298
|
# @return [Hash]
|
291
299
|
def stats(*arg)
|
292
|
-
@
|
300
|
+
@lock.synchronize do
|
301
|
+
@data.stats(*arg)
|
302
|
+
end
|
293
303
|
end
|
294
304
|
|
295
305
|
protected
|
296
306
|
|
297
307
|
# Read an entry from the cache.
|
298
308
|
def read_entry(key, options) # :nodoc:
|
299
|
-
@
|
309
|
+
@lock.synchronize do
|
310
|
+
@data.get(key, options)
|
311
|
+
end
|
300
312
|
rescue ::Couchbase::Error::Base => e
|
301
313
|
logger.error("#{e.class}: #{e.message}") if logger
|
302
314
|
raise if @raise_errors
|
@@ -313,7 +325,9 @@ module ActiveSupport
|
|
313
325
|
if ttl = options.delete(:expires_in)
|
314
326
|
options[:ttl] ||= ttl
|
315
327
|
end
|
316
|
-
@
|
328
|
+
@lock.synchronize do
|
329
|
+
@data.send(method, key, value, options)
|
330
|
+
end
|
317
331
|
rescue ::Couchbase::Error::Base => e
|
318
332
|
logger.error("#{e.class}: #{e.message}") if logger
|
319
333
|
raise if @raise_errors
|
@@ -322,7 +336,9 @@ module ActiveSupport
|
|
322
336
|
|
323
337
|
# Delete an entry from the cache.
|
324
338
|
def delete_entry(key, options) # :nodoc:
|
325
|
-
@
|
339
|
+
@lock.synchronize do
|
340
|
+
@data.delete(key, options)
|
341
|
+
end
|
326
342
|
rescue ::Couchbase::Error::Base => e
|
327
343
|
logger.error("#{e.class}: #{e.message}") if logger
|
328
344
|
raise if @raise_errors
|
data/lib/couchbase.rb
CHANGED
@@ -73,7 +73,18 @@ module Couchbase
|
|
73
73
|
|
74
74
|
# @private the thread local storage
|
75
75
|
def thread_storage
|
76
|
-
Thread.current[:couchbase] ||= {}
|
76
|
+
Thread.current[:couchbase] ||= { :pid => Process.pid }
|
77
|
+
end
|
78
|
+
|
79
|
+
# @private resets thread local storage if process ids don't match
|
80
|
+
# see 13.3.1: http://www.modrails.com/documentation/Users%20guide%20Apache.html
|
81
|
+
def verify_connection!
|
82
|
+
reset_thread_storage! if thread_storage[:pid] != Process.pid
|
83
|
+
end
|
84
|
+
|
85
|
+
# @private resets thread local storage
|
86
|
+
def reset_thread_storage!
|
87
|
+
Thread.current[:couchbase] = nil
|
77
88
|
end
|
78
89
|
|
79
90
|
# The connection instance for current thread
|
@@ -87,6 +98,7 @@ module Couchbase
|
|
87
98
|
#
|
88
99
|
# @return [Bucket]
|
89
100
|
def bucket
|
101
|
+
verify_connection!
|
90
102
|
thread_storage[:bucket] ||= connect(connection_options)
|
91
103
|
end
|
92
104
|
|
@@ -96,6 +108,7 @@ module Couchbase
|
|
96
108
|
#
|
97
109
|
# @return [Bucket]
|
98
110
|
def bucket=(connection)
|
111
|
+
verify_connection!
|
99
112
|
thread_storage[:bucket] = connection
|
100
113
|
end
|
101
114
|
|
data/lib/couchbase/version.rb
CHANGED
data/tasks/util.rake
CHANGED
data/test/test_couchbase.rb
CHANGED
@@ -16,13 +16,62 @@
|
|
16
16
|
#
|
17
17
|
|
18
18
|
require File.join(File.dirname(__FILE__), 'setup')
|
19
|
+
require 'minitest/mock'
|
19
20
|
|
20
21
|
class TestCouchbase < MiniTest::Unit::TestCase
|
21
22
|
|
23
|
+
def teardown
|
24
|
+
Couchbase.reset_thread_storage!
|
25
|
+
end
|
26
|
+
|
22
27
|
def test_that_it_create_instance_of_bucket
|
23
28
|
with_mock do |mock|
|
24
29
|
assert_instance_of Couchbase::Bucket, Couchbase.new("http://#{mock.host}:#{mock.port}/pools/default")
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
33
|
+
def test_verify_connection
|
34
|
+
pid = Process.pid
|
35
|
+
assert_equal pid, Couchbase.thread_storage[:pid]
|
36
|
+
Couchbase.verify_connection!
|
37
|
+
assert_equal pid, Couchbase.thread_storage[:pid]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_verify_connection_when_process_forks
|
41
|
+
pid = Process.pid
|
42
|
+
assert_equal pid, Couchbase.thread_storage[:pid]
|
43
|
+
|
44
|
+
# stub a simulated Kernel#fork
|
45
|
+
Process.stub(:pid, Process.pid + 1) do
|
46
|
+
Couchbase.verify_connection!
|
47
|
+
refute_equal pid, Couchbase.thread_storage[:pid]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_new_connection_when_process_forks
|
52
|
+
with_mock do |mock|
|
53
|
+
connection_options = "http://#{mock.host}:#{mock.port}/pools/default"
|
54
|
+
Couchbase.connection_options = connection_options
|
55
|
+
old_bucket_id = Couchbase.bucket.object_id
|
56
|
+
|
57
|
+
Process.stub(:pid, Process.pid + 1) do
|
58
|
+
refute_equal old_bucket_id, Couchbase.bucket.object_id
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_new_connection_has_same_configuration_options
|
64
|
+
with_mock do |mock|
|
65
|
+
connection_options = "http://#{mock.host}:#{mock.port}/pools/default"
|
66
|
+
Couchbase.connection_options = connection_options
|
67
|
+
old_bucket = Couchbase.bucket
|
68
|
+
|
69
|
+
Process.stub(:pid, Process.pid + 1) do
|
70
|
+
new_bucket = Couchbase.bucket
|
71
|
+
assert_equal old_bucket.name, new_bucket.name
|
72
|
+
assert_equal old_bucket.hostname, new_bucket.hostname
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
28
77
|
end
|
@@ -280,6 +280,29 @@ class TestCouchbaseRailsCacheStore < MiniTest::Unit::TestCase
|
|
280
280
|
assert_equal({:key => uniq_id, :amount => 1, :create => true}, decrement.payload)
|
281
281
|
end
|
282
282
|
|
283
|
+
# Inspiration: https://github.com/mperham/dalli/blob/master/test/test_dalli.rb#L416
|
284
|
+
def test_it_is_threadsafe
|
285
|
+
workers = []
|
286
|
+
|
287
|
+
# Have a bunch of threads perform a bunch of operations at the same time.
|
288
|
+
# Verify the result of each operation to ensure the request and response
|
289
|
+
# are not intermingled between threads.
|
290
|
+
10.times do
|
291
|
+
workers << Thread.new do
|
292
|
+
100.times do
|
293
|
+
store.write('a', 9)
|
294
|
+
store.write('b', 11)
|
295
|
+
assert_equal 9, store.read('a')
|
296
|
+
assert_equal({ 'a' => 9, 'b' => 11 }, store.read_multi('a', 'b'))
|
297
|
+
assert_equal 11, store.read('b')
|
298
|
+
assert_equal %w(a b), store.read_multi('a', 'b', 'c').keys.sort
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
workers.each { |w| w.join }
|
304
|
+
end
|
305
|
+
|
283
306
|
private
|
284
307
|
|
285
308
|
def collect_notifications
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: couchbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: x86-mingw32
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02
|
12
|
+
date: 2013-04-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: yaji
|
@@ -164,6 +164,7 @@ files:
|
|
164
164
|
- .gitignore
|
165
165
|
- .travis.yml
|
166
166
|
- .yardopts
|
167
|
+
- CONTRIBUTING.markdown
|
167
168
|
- Gemfile
|
168
169
|
- LICENSE
|
169
170
|
- Makefile
|
@@ -255,7 +256,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
256
|
version: '0'
|
256
257
|
segments:
|
257
258
|
- 0
|
258
|
-
hash:
|
259
|
+
hash: -322659644960790893
|
259
260
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
260
261
|
none: false
|
261
262
|
requirements:
|
@@ -264,7 +265,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
265
|
version: '0'
|
265
266
|
segments:
|
266
267
|
- 0
|
267
|
-
hash:
|
268
|
+
hash: -322659644960790893
|
268
269
|
requirements: []
|
269
270
|
rubyforge_project:
|
270
271
|
rubygems_version: 1.8.23
|