Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Reset Couchbase#thread_storage when a Kernel#fork is detected

Adding to avoid file descriptor sharing between a process and its sub
process. See [section 13.3][1] at for a description of why this is bad.

[1]: http://www.modrails.com/documentation/Users%20guide%20Apache.html#_smart_spawning_gotcha_1_unintentional_file_descriptor_sharing

Change-Id: I6019aaf3635c3f9f31076f6ac5d5d978978c718f
Reviewed-on: http://review.couchbase.org/25266
Reviewed-by: Sergey Avseyev <sergey.avseyev@gmail.com>
Tested-by: Sergey Avseyev <sergey.avseyev@gmail.com>
  • Loading branch information...
commit db4e26d66eb0f63304011cd0d7d5ba75eb9d0cd9 1 parent 3395aec
@mje113 mje113 authored avsej committed
Showing with 63 additions and 1 deletion.
  1. +14 −1 lib/couchbase.rb
  2. +49 −0 test/test_couchbase.rb
View
15 lib/couchbase.rb
@@ -73,7 +73,18 @@ def connect(*options)
# @private the thread local storage
def thread_storage
- Thread.current[:couchbase] ||= {}
+ Thread.current[:couchbase] ||= { :pid => Process.pid }
+ end
+
+ # @private resets thread local storage if process ids don't match
+ # see 13.3.1: http://www.modrails.com/documentation/Users%20guide%20Apache.html
+ def verify_connection!
+ reset_thread_storage! if thread_storage[:pid] != Process.pid
+ end
+
+ # @private resets thread local storage
+ def reset_thread_storage!
+ Thread.current[:couchbase] = nil
end
# The connection instance for current thread
@@ -87,6 +98,7 @@ def thread_storage
#
# @return [Bucket]
def bucket
+ verify_connection!
thread_storage[:bucket] ||= connect(connection_options)
end
@@ -96,6 +108,7 @@ def bucket
#
# @return [Bucket]
def bucket=(connection)
+ verify_connection!
thread_storage[:bucket] = connection
end
View
49 test/test_couchbase.rb
@@ -16,13 +16,62 @@
#
require File.join(File.dirname(__FILE__), 'setup')
+require 'minitest/mock'
class TestCouchbase < MiniTest::Unit::TestCase
+ def teardown
+ Couchbase.reset_thread_storage!
+ end
+
def test_that_it_create_instance_of_bucket
with_mock do |mock|
assert_instance_of Couchbase::Bucket, Couchbase.new("http://#{mock.host}:#{mock.port}/pools/default")
end
end
+ def test_verify_connection
+ pid = Process.pid
+ assert_equal pid, Couchbase.thread_storage[:pid]
+ Couchbase.verify_connection!
+ assert_equal pid, Couchbase.thread_storage[:pid]
+ end
+
+ def test_verify_connection_when_process_forks
+ pid = Process.pid
+ assert_equal pid, Couchbase.thread_storage[:pid]
+
+ # stub a simulated Kernel#fork
+ Process.stub(:pid, Process.pid + 1) do
+ Couchbase.verify_connection!
+ refute_equal pid, Couchbase.thread_storage[:pid]
+ end
+ end
+
+ def test_new_connection_when_process_forks
+ with_mock do |mock|
+ connection_options = "http://#{mock.host}:#{mock.port}/pools/default"
+ Couchbase.connection_options = connection_options
+ old_bucket_id = Couchbase.bucket.object_id
+
+ Process.stub(:pid, Process.pid + 1) do
+ refute_equal old_bucket_id, Couchbase.bucket.object_id
+ end
+ end
+ end
+
+ def test_new_connection_has_same_configuration_options
+ with_mock do |mock|
+ connection_options = "http://#{mock.host}:#{mock.port}/pools/default"
+ Couchbase.connection_options = connection_options
+ old_bucket = Couchbase.bucket
+
+ Process.stub(:pid, Process.pid + 1) do
+ new_bucket = Couchbase.bucket
+ assert_equal old_bucket.name, new_bucket.name
+ assert_equal old_bucket.hostname, new_bucket.hostname
+ end
+ end
+ end
+
end
Please sign in to comment.
Something went wrong with that request. Please try again.