couchbase 1.2.2-x86-mingw32 → 1.2.3-x86-mingw32

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.
@@ -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