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.
@@ -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
@@ -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
@@ -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.set["foo"] = {"bar" => "baz}
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
- @data.get(names, options)
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
- @data.incr(name, amount, options)
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
- @data.decr(name, amount, options)
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
- @data.stats(*arg)
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
- @data.get(key, options)
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
- @data.send(method, key, value, options)
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
- @data.delete(key, options)
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
@@ -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
 
@@ -17,5 +17,5 @@
17
17
 
18
18
  # Couchbase ruby client
19
19
  module Couchbase
20
- VERSION = "1.2.2"
20
+ VERSION = "1.2.3"
21
21
  end
@@ -16,6 +16,6 @@
16
16
  #
17
17
 
18
18
  desc 'Start an irb session and load the library.'
19
- task :console => :compile do
19
+ task :console do
20
20
  exec "irb -I lib -rcouchbase"
21
21
  end
@@ -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.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-11 00:00:00.000000000 Z
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: 3150309656222985130
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: 3150309656222985130
268
+ hash: -322659644960790893
268
269
  requirements: []
269
270
  rubyforge_project:
270
271
  rubygems_version: 1.8.23