cache 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +40 -17
- data/lib/cache.rb +38 -17
- data/lib/cache/config.rb +14 -19
- data/lib/cache/storage.rb +36 -28
- data/lib/cache/version.rb +2 -2
- data/test/helper.rb +4 -0
- data/test/shared_tests.rb +18 -18
- data/test/test_dalli_storage.rb +8 -10
- data/test/test_dalli_store_storage.rb +8 -10
- data/test/test_memcache_storage.rb +8 -10
- data/test/test_memcached_rails_storage.rb +8 -10
- data/test/test_memcached_storage.rb +8 -10
- data/test/test_redis_storage.rb +9 -11
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -2,12 +2,40 @@
|
|
2
2
|
|
3
3
|
A unified cache handling interface, inspired (but simpler than) Perl's Cache::Cache[http://cpan.uwinnipeg.ca/module/Cache::Cache] and CHI[http://cpan.uwinnipeg.ca/module/CHI].
|
4
4
|
|
5
|
+
Takes care of exceptions like Memcached::NotFound and also forking/threading.
|
6
|
+
|
7
|
+
== Example
|
8
|
+
|
9
|
+
require 'memcached' # a really fast memcached client gem
|
10
|
+
require 'client' # this gem, which provides a standard interface
|
11
|
+
raw_client = Memcached.new '127.0.0.1:11211'
|
12
|
+
cache = Cache.new raw_client
|
13
|
+
|
14
|
+
or
|
15
|
+
|
16
|
+
require 'redis' # the redis key-value store
|
17
|
+
require 'client' # this gem, which provides a standard interface
|
18
|
+
raw_client = Redis.new
|
19
|
+
cache = Cache.new raw_client
|
20
|
+
|
21
|
+
or
|
22
|
+
|
23
|
+
require 'dalli' # the dalli memcached client used by heroku
|
24
|
+
require 'client' # this gem, which provides a standard interface
|
25
|
+
raw_client = Dalli::Client.new
|
26
|
+
cache = Cache.new raw_client
|
27
|
+
|
28
|
+
Maybe this will even work:
|
29
|
+
|
30
|
+
# Piggyback off the default rails cache
|
31
|
+
cache = Cache.new Rails.cache
|
32
|
+
|
5
33
|
== Methods
|
6
34
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
35
|
+
cache.get 'hello'
|
36
|
+
cache.set 'hello', 'world'
|
37
|
+
cache.delete 'hello'
|
38
|
+
cache.flush
|
11
39
|
|
12
40
|
== Supported clients
|
13
41
|
|
@@ -21,29 +49,24 @@ Supported Redis clients:
|
|
21
49
|
|
22
50
|
* redis[https://github.com/ezmobius/redis-rb]
|
23
51
|
|
24
|
-
==
|
25
|
-
|
26
|
-
You set your preferred cache client:
|
27
|
-
|
28
|
-
Cache.config.client = Memcached.new '127.0.0.1:11211'
|
29
|
-
|
30
|
-
or
|
31
|
-
|
32
|
-
Cache.config.client = Redis.new
|
52
|
+
== TTL
|
33
53
|
|
34
|
-
|
54
|
+
0 means don't expire.
|
35
55
|
|
36
|
-
|
56
|
+
== Forking/threading
|
37
57
|
|
38
|
-
|
58
|
+
When you use a Cache object to wrap Memcached or Redis, you don't have to worry about forking or threading.
|
39
59
|
|
40
|
-
|
60
|
+
For example, you don't have to set up unicorn or PhusionPassenger's <tt>after_fork</tt>.
|
41
61
|
|
42
62
|
== Rationale
|
43
63
|
|
64
|
+
I wanted a common interface to a bunch of great Ruby cache clients so I can develop gems (lock_method, cache_method) that accept any of them.
|
65
|
+
|
44
66
|
* I am so tired of rescuing from Memcached::NotFound
|
45
67
|
* I am so tired of forgetting whether it's :expires_in or :ttl
|
46
68
|
* I don't know why we ever started using read/write instead of get/set.
|
69
|
+
* I don't like how you have to manually handle after_fork for Redis, Memcached, etc.
|
47
70
|
|
48
71
|
== Currently unsupported
|
49
72
|
|
data/lib/cache.rb
CHANGED
@@ -1,42 +1,63 @@
|
|
1
1
|
require 'cache/version'
|
2
|
-
|
2
|
+
class Cache
|
3
3
|
autoload :Config, 'cache/config'
|
4
4
|
autoload :Storage, 'cache/storage'
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
|
6
|
+
# Create a new Cache object by passing it a client of your choice.
|
7
|
+
#
|
8
|
+
# Supported memcached clients:
|
9
|
+
# * memcached[https://github.com/fauna/memcached] (either a Memcached or a Memcached::Rails)
|
10
|
+
# * dalli[https://github.com/mperham/dalli] (either a Dalli::Client or an ActiveSupport::Cache::DalliStore)
|
11
|
+
# * memcache-client[https://github.com/mperham/memcache-client] (MemCache, the one commonly used by Rails)
|
12
|
+
#
|
13
|
+
# Supported Redis clients:
|
14
|
+
# * redis[https://github.com/ezmobius/redis-rb]
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
# raw_client = Memcached.new('127.0.0.1:11211')
|
18
|
+
# cache = Cache.new raw_client
|
19
|
+
def initialize(client)
|
20
|
+
config.client = client
|
21
|
+
end
|
22
|
+
|
23
|
+
def config #:nodoc:
|
24
|
+
@config ||= Config.new self
|
25
|
+
end
|
26
|
+
|
27
|
+
def storage #:nodoc:
|
28
|
+
@storage ||= Storage.new self
|
8
29
|
end
|
9
30
|
|
10
31
|
# Get a value.
|
11
32
|
#
|
12
33
|
# Example:
|
13
|
-
#
|
14
|
-
def
|
15
|
-
|
34
|
+
# cache.get 'hello'
|
35
|
+
def get(k)
|
36
|
+
storage.get k
|
16
37
|
end
|
17
38
|
|
18
39
|
# Store a value. Note that this will Marshal it.
|
19
40
|
#
|
20
41
|
# Example:
|
21
|
-
#
|
22
|
-
#
|
23
|
-
def
|
24
|
-
|
42
|
+
# cache.set 'hello', 'world'
|
43
|
+
# cache.set 'hello', 'world', 80 # seconds til it expires
|
44
|
+
def set(k, v, ttl = nil)
|
45
|
+
storage.set k, v, ttl
|
25
46
|
end
|
26
47
|
|
27
48
|
# Delete a value.
|
28
49
|
#
|
29
50
|
# Example:
|
30
|
-
#
|
31
|
-
def
|
32
|
-
|
51
|
+
# cache.delete 'hello'
|
52
|
+
def delete(k)
|
53
|
+
storage.delete k
|
33
54
|
end
|
34
55
|
|
35
56
|
# Flush the cache.
|
36
57
|
#
|
37
58
|
# Example:
|
38
|
-
#
|
39
|
-
def
|
40
|
-
|
59
|
+
# cache.flush
|
60
|
+
def flush
|
61
|
+
storage.flush
|
41
62
|
end
|
42
63
|
end
|
data/lib/cache/config.rb
CHANGED
@@ -1,39 +1,34 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Here's where you set config options.
|
1
|
+
class Cache
|
2
|
+
# Here's where config options are kept.
|
4
3
|
#
|
5
4
|
# Example:
|
6
|
-
#
|
7
|
-
# Cache.config.default_ttl = 120 # seconds
|
8
|
-
#
|
9
|
-
# You'd probably put this in your Rails config/initializers, for example.
|
5
|
+
# cache.config.default_ttl = 120 # seconds
|
10
6
|
class Config
|
11
|
-
|
7
|
+
|
8
|
+
attr_reader :parent
|
9
|
+
|
10
|
+
def initialize(parent) #:nodoc:
|
11
|
+
@parent = parent
|
12
|
+
end
|
12
13
|
|
13
14
|
# The cache client to use.
|
14
15
|
#
|
15
|
-
#
|
16
|
-
# * memcached[https://github.com/fauna/memcached] (either a Memcached or a Memcached::Rails)
|
17
|
-
# * dalli[https://github.com/mperham/dalli] (either a Dalli::Client or an ActiveSupport::Cache::DalliStore)
|
18
|
-
# * memcache-client[https://github.com/mperham/memcache-client] (MemCache, the one commonly used by Rails)
|
19
|
-
#
|
20
|
-
# Supported Redis clients:
|
21
|
-
# * redis[https://github.com/ezmobius/redis-rb]
|
16
|
+
# Note that you normally just set this when you initialize a Cache object.
|
22
17
|
#
|
23
18
|
# Example:
|
24
|
-
#
|
25
|
-
def client=(client)
|
19
|
+
# cache.config.client = Memcached.new '127.0.0.1:11211'
|
20
|
+
def client=(client) #:nodoc:
|
26
21
|
@client = client
|
27
22
|
end
|
28
23
|
|
29
24
|
def client #:nodoc:
|
30
|
-
@client
|
25
|
+
@client || raise("You didn't select a cache client")
|
31
26
|
end
|
32
27
|
|
33
28
|
# TTL for method caches. Defaults to 60 seconds.
|
34
29
|
#
|
35
30
|
# Example:
|
36
|
-
#
|
31
|
+
# cache.config.default_ttl = 120 # seconds
|
37
32
|
def default_ttl=(seconds)
|
38
33
|
@default_ttl = seconds
|
39
34
|
end
|
data/lib/cache/storage.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
-
|
2
|
-
module Cache
|
1
|
+
class Cache
|
3
2
|
class Storage #:nodoc: all
|
4
|
-
|
5
|
-
|
3
|
+
|
4
|
+
attr_reader :parent
|
5
|
+
|
6
|
+
def initialize(parent)
|
7
|
+
@parent = parent
|
8
|
+
@pid = ::Process.pid
|
9
|
+
@thread_object_id = ::Thread.current.object_id
|
10
|
+
end
|
11
|
+
|
6
12
|
def get(k)
|
7
13
|
if defined?(::Memcached) and bare_client.is_a?(::Memcached)
|
8
14
|
begin; bare_client.get(k); rescue ::Memcached::NotFound; nil; end
|
@@ -20,7 +26,7 @@ module Cache
|
|
20
26
|
end
|
21
27
|
|
22
28
|
def set(k, v, ttl)
|
23
|
-
ttl ||=
|
29
|
+
ttl ||= parent.config.default_ttl
|
24
30
|
if defined?(::Redis) and bare_client.is_a?(::Redis)
|
25
31
|
if ttl == 0
|
26
32
|
bare_client.set k, ::Marshal.dump(v)
|
@@ -56,35 +62,37 @@ module Cache
|
|
56
62
|
bare_client.send %w{ flush flushdb flush_all clear }.detect { |flush_cmd| bare_client.respond_to? flush_cmd }
|
57
63
|
end
|
58
64
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
fork_detected = true
|
64
|
-
::Thread.current[:cache_storage_bare_client] = nil
|
65
|
+
private
|
66
|
+
|
67
|
+
def fork_detected?
|
68
|
+
if @pid != ::Process.pid
|
65
69
|
@pid = ::Process.pid
|
66
70
|
end
|
67
|
-
::Thread.current[:cache_storage_bare_client] ||= fresh_bare_client(fork_detected)
|
68
71
|
end
|
69
72
|
|
70
|
-
def
|
71
|
-
if
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
73
|
+
def new_thread_detected?
|
74
|
+
if @thread_object_id != ::Thread.current.object_id
|
75
|
+
@thread_object_id = ::Thread.current.object_id
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def bare_client
|
80
|
+
fork_detected = fork_detected?
|
81
|
+
new_thread_detected = new_thread_detected?
|
82
|
+
if defined?(::Dalli) and parent.config.client.is_a?(::Dalli::Client)
|
83
|
+
parent.config.client.close if fork_detected
|
84
|
+
elsif defined?(::ActiveSupport::Cache::DalliStore) and parent.config.client.is_a?(::ActiveSupport::Cache::DalliStore)
|
85
|
+
parent.config.client.reset if fork_detected
|
86
|
+
elsif defined?(::Memcached) and (parent.config.client.is_a?(::Memcached) or parent.config.client.is_a?(::Memcached::Rails))
|
87
|
+
parent.config.client = parent.config.client.clone if fork_detected or new_thread_detected
|
88
|
+
elsif defined?(::Redis) and parent.config.client.is_a?(::Redis)
|
89
|
+
parent.config.client.client.connect if fork_detected
|
90
|
+
elsif defined?(::MemCache) and parent.config.client.is_a?(::MemCache)
|
91
|
+
parent.config.client.reset if fork_detected
|
85
92
|
else
|
86
|
-
raise "Don't know how to thread/fork #{
|
93
|
+
raise "Don't know how to thread/fork #{parent.config.client.inspect}"
|
87
94
|
end
|
95
|
+
parent.config.client
|
88
96
|
end
|
89
97
|
end
|
90
98
|
end
|
data/lib/cache/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.0.
|
1
|
+
class Cache
|
2
|
+
VERSION = "0.0.2"
|
3
3
|
end
|
data/test/helper.rb
CHANGED
data/test/shared_tests.rb
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
module SharedTests
|
2
2
|
def test_get
|
3
|
-
assert_equal nil,
|
4
|
-
|
5
|
-
assert_equal 'world',
|
3
|
+
assert_equal nil, @cache.get('hello')
|
4
|
+
@cache.set 'hello', 'world'
|
5
|
+
assert_equal 'world', @cache.get('hello')
|
6
6
|
end
|
7
7
|
|
8
8
|
def test_set
|
9
9
|
assert_nothing_raised do
|
10
|
-
|
10
|
+
@cache.set 'hello', 'world'
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_set_with_ttl
|
15
|
-
|
16
|
-
assert_equal 'world',
|
15
|
+
@cache.set 'hello', 'world', 1
|
16
|
+
assert_equal 'world', @cache.get('hello')
|
17
17
|
sleep 2
|
18
|
-
assert_equal nil,
|
18
|
+
assert_equal nil, @cache.get('hello')
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_set_with_zero_ttl_meaning_eternal
|
22
|
-
|
23
|
-
assert_equal 'world',
|
22
|
+
@cache.set 'hello', 'world', 0
|
23
|
+
assert_equal 'world', @cache.get('hello')
|
24
24
|
sleep 1
|
25
|
-
assert_equal 'world',
|
25
|
+
assert_equal 'world', @cache.get('hello')
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_delete
|
29
|
-
|
30
|
-
assert_equal 'world',
|
31
|
-
|
32
|
-
assert_equal nil,
|
29
|
+
@cache.set 'hello', 'world'
|
30
|
+
assert_equal 'world', @cache.get('hello')
|
31
|
+
@cache.delete 'hello'
|
32
|
+
assert_equal nil, @cache.get('hello')
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_flush
|
36
|
-
|
37
|
-
assert_equal 'world',
|
38
|
-
|
39
|
-
assert_equal nil,
|
36
|
+
@cache.set 'hello', 'world'
|
37
|
+
assert_equal 'world', @cache.get('hello')
|
38
|
+
@cache.flush
|
39
|
+
assert_equal nil, @cache.get('hello')
|
40
40
|
end
|
41
41
|
end
|
data/test/test_dalli_storage.rb
CHANGED
@@ -4,31 +4,29 @@ require 'dalli'
|
|
4
4
|
|
5
5
|
class TestDalliStorage < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
+
@client = Dalli::Client.new ['localhost:11211']
|
7
8
|
super
|
8
|
-
client = Dalli::Client.new ['localhost:11211']
|
9
|
-
client.flush
|
10
|
-
Cache.config.client = client
|
11
9
|
end
|
12
10
|
|
13
11
|
include SharedTests
|
14
12
|
|
15
13
|
def get_ring_object_id
|
16
|
-
|
14
|
+
@cache.config.client.instance_variable_get(:@ring).object_id
|
17
15
|
end
|
18
16
|
|
19
17
|
def test_treats_as_thread_safe
|
20
18
|
# make sure ring is initialized
|
21
|
-
|
19
|
+
@cache.get 'hi'
|
22
20
|
|
23
21
|
# get the main thread's ring
|
24
22
|
main_thread_ring_id = get_ring_object_id
|
25
23
|
|
26
24
|
# sanity check that it's not changing every time
|
27
|
-
|
25
|
+
@cache.get 'hi'
|
28
26
|
assert_equal main_thread_ring_id, get_ring_object_id
|
29
27
|
|
30
28
|
# create a new thread and get its ring
|
31
|
-
new_thread_ring_id = Thread.new {
|
29
|
+
new_thread_ring_id = Thread.new { @cache.get 'hi'; get_ring_object_id }.value
|
32
30
|
|
33
31
|
# make sure the ring was reinitialized
|
34
32
|
assert_equal main_thread_ring_id, new_thread_ring_id
|
@@ -36,18 +34,18 @@ class TestDalliStorage < Test::Unit::TestCase
|
|
36
34
|
|
37
35
|
def test_treats_as_not_fork_safe
|
38
36
|
# make sure ring is initialized
|
39
|
-
|
37
|
+
@cache.get 'hi'
|
40
38
|
|
41
39
|
# get the main thread's ring
|
42
40
|
parent_process_ring_id = get_ring_object_id
|
43
41
|
|
44
42
|
# sanity check that it's not changing every time
|
45
|
-
|
43
|
+
@cache.get 'hi'
|
46
44
|
assert_equal parent_process_ring_id, get_ring_object_id
|
47
45
|
|
48
46
|
# fork a new process
|
49
47
|
pid = Kernel.fork do
|
50
|
-
|
48
|
+
@cache.get 'hi'
|
51
49
|
raise "Didn't split!" if parent_process_ring_id == get_ring_object_id
|
52
50
|
end
|
53
51
|
Process.wait pid
|
@@ -6,32 +6,30 @@ require 'active_support/cache/dalli_store'
|
|
6
6
|
|
7
7
|
class TestDalliStoreStorage < Test::Unit::TestCase
|
8
8
|
def setup
|
9
|
+
@client = ActiveSupport::Cache::DalliStore.new ['localhost:11211']
|
9
10
|
super
|
10
|
-
client = ActiveSupport::Cache::DalliStore.new ['localhost:11211']
|
11
|
-
client.clear
|
12
|
-
Cache.config.client = client
|
13
11
|
end
|
14
12
|
|
15
13
|
include SharedTests
|
16
14
|
|
17
15
|
def get_ring_object_id
|
18
|
-
hidden_dalli_client =
|
16
|
+
hidden_dalli_client = @cache.config.client.instance_variable_get :@data
|
19
17
|
hidden_dalli_client.instance_variable_get(:@ring).object_id
|
20
18
|
end
|
21
19
|
|
22
20
|
def test_treats_as_thread_safe
|
23
21
|
# make sure ring is initialized
|
24
|
-
|
22
|
+
@cache.get 'hi'
|
25
23
|
|
26
24
|
# get the main thread's ring
|
27
25
|
main_thread_ring_id = get_ring_object_id
|
28
26
|
|
29
27
|
# sanity check that it's not changing every time
|
30
|
-
|
28
|
+
@cache.get 'hi'
|
31
29
|
assert_equal main_thread_ring_id, get_ring_object_id
|
32
30
|
|
33
31
|
# create a new thread and get its ring
|
34
|
-
new_thread_ring_id = Thread.new {
|
32
|
+
new_thread_ring_id = Thread.new { @cache.get 'hi'; get_ring_object_id }.value
|
35
33
|
|
36
34
|
# make sure the ring was reinitialized
|
37
35
|
assert_equal main_thread_ring_id, new_thread_ring_id
|
@@ -39,18 +37,18 @@ class TestDalliStoreStorage < Test::Unit::TestCase
|
|
39
37
|
|
40
38
|
def test_treats_as_not_fork_safe
|
41
39
|
# make sure ring is initialized
|
42
|
-
|
40
|
+
@cache.get 'hi'
|
43
41
|
|
44
42
|
# get the main thread's ring
|
45
43
|
parent_process_ring_id = get_ring_object_id
|
46
44
|
|
47
45
|
# sanity check that it's not changing every time
|
48
|
-
|
46
|
+
@cache.get 'hi'
|
49
47
|
assert_equal parent_process_ring_id, get_ring_object_id
|
50
48
|
|
51
49
|
# fork a new process
|
52
50
|
pid = Kernel.fork do
|
53
|
-
|
51
|
+
@cache.get 'hi'
|
54
52
|
raise "Didn't split!" if parent_process_ring_id == get_ring_object_id
|
55
53
|
end
|
56
54
|
Process.wait pid
|
@@ -5,31 +5,29 @@ require 'memcache'
|
|
5
5
|
|
6
6
|
class TestMemcacheStorage < Test::Unit::TestCase
|
7
7
|
def setup
|
8
|
+
@client = MemCache.new ['localhost:11211']
|
8
9
|
super
|
9
|
-
client = MemCache.new ['localhost:11211']
|
10
|
-
client.flush_all
|
11
|
-
Cache.config.client = client
|
12
10
|
end
|
13
11
|
|
14
12
|
include SharedTests
|
15
13
|
|
16
14
|
def get_server_status_ids
|
17
|
-
|
15
|
+
@cache.config.client.instance_variable_get(:@servers).map { |s| s.status.object_id }
|
18
16
|
end
|
19
17
|
|
20
18
|
def test_treats_as_thread_safe
|
21
19
|
# make sure servers are connected
|
22
|
-
|
20
|
+
@cache.get 'hi'
|
23
21
|
|
24
22
|
# get the object ids
|
25
23
|
main_thread_server_status_ids = get_server_status_ids
|
26
24
|
|
27
25
|
# sanity check that it's not changing every time
|
28
|
-
|
26
|
+
@cache.get 'hi'
|
29
27
|
assert_equal main_thread_server_status_ids, get_server_status_ids
|
30
28
|
|
31
29
|
# create a new thread and get its server ids
|
32
|
-
new_thread_server_status_ids = Thread.new {
|
30
|
+
new_thread_server_status_ids = Thread.new { @cache.get 'hi'; get_server_status_ids }.value
|
33
31
|
|
34
32
|
# make sure the server ids was reinitialized
|
35
33
|
assert_equal main_thread_server_status_ids, new_thread_server_status_ids
|
@@ -37,18 +35,18 @@ class TestMemcacheStorage < Test::Unit::TestCase
|
|
37
35
|
|
38
36
|
def test_treats_as_not_fork_safe
|
39
37
|
# make sure server ids is initialized
|
40
|
-
|
38
|
+
@cache.get 'hi'
|
41
39
|
|
42
40
|
# get the main thread's server ids
|
43
41
|
parent_process_server_status_ids = get_server_status_ids
|
44
42
|
|
45
43
|
# sanity check that it's not changing every time
|
46
|
-
|
44
|
+
@cache.get 'hi'
|
47
45
|
assert_equal parent_process_server_status_ids, get_server_status_ids
|
48
46
|
|
49
47
|
# fork a new process
|
50
48
|
pid = Kernel.fork do
|
51
|
-
|
49
|
+
@cache.get 'hi'
|
52
50
|
raise "Didn't split!" if parent_process_server_status_ids == get_server_status_ids
|
53
51
|
end
|
54
52
|
Process.wait pid
|
@@ -4,31 +4,29 @@ require 'memcached'
|
|
4
4
|
|
5
5
|
class TestMemcachedRailsStorage < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
+
@client = Memcached::Rails.new 'localhost:11211'
|
7
8
|
super
|
8
|
-
client = Memcached::Rails.new 'localhost:11211'
|
9
|
-
client.flush
|
10
|
-
Cache.config.client = client
|
11
9
|
end
|
12
10
|
|
13
11
|
include SharedTests
|
14
12
|
|
15
13
|
def get_bare_client_id
|
16
|
-
|
14
|
+
@cache.storage.send(:bare_client).object_id
|
17
15
|
end
|
18
16
|
|
19
17
|
def test_treats_as_not_thread_safe
|
20
18
|
# make sure bare client is initialized
|
21
|
-
|
19
|
+
@cache.get 'hi'
|
22
20
|
|
23
21
|
# get the main thread's bare client
|
24
22
|
main_thread_bare_client_id = get_bare_client_id
|
25
23
|
|
26
24
|
# sanity check that it's not changing every time
|
27
|
-
|
25
|
+
@cache.get 'hi'
|
28
26
|
assert_equal main_thread_bare_client_id, get_bare_client_id
|
29
27
|
|
30
28
|
# create a new thread and get its bare client
|
31
|
-
new_thread_bare_client_id = Thread.new {
|
29
|
+
new_thread_bare_client_id = Thread.new { @cache.get 'hi'; get_bare_client_id }.value
|
32
30
|
|
33
31
|
# make sure the bare client was reinitialized
|
34
32
|
assert(main_thread_bare_client_id != new_thread_bare_client_id)
|
@@ -36,18 +34,18 @@ class TestMemcachedRailsStorage < Test::Unit::TestCase
|
|
36
34
|
|
37
35
|
def test_treats_as_not_fork_safe
|
38
36
|
# make sure bare client is initialized
|
39
|
-
|
37
|
+
@cache.get 'hi'
|
40
38
|
|
41
39
|
# get the main process's bare client
|
42
40
|
parent_process_bare_client_id = get_bare_client_id
|
43
41
|
|
44
42
|
# sanity check that it's not changing every time
|
45
|
-
|
43
|
+
@cache.get 'hi'
|
46
44
|
assert_equal parent_process_bare_client_id, get_bare_client_id
|
47
45
|
|
48
46
|
# fork a new process
|
49
47
|
pid = Kernel.fork do
|
50
|
-
|
48
|
+
@cache.get 'hi'
|
51
49
|
raise "Didn't split!" if parent_process_bare_client_id == get_bare_client_id
|
52
50
|
end
|
53
51
|
Process.wait pid
|
@@ -4,31 +4,29 @@ require 'memcached'
|
|
4
4
|
|
5
5
|
class TestMemcachedStorage < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
+
@client = Memcached.new 'localhost:11211'
|
7
8
|
super
|
8
|
-
client = Memcached.new 'localhost:11211'
|
9
|
-
client.flush
|
10
|
-
Cache.config.client = client
|
11
9
|
end
|
12
10
|
|
13
11
|
include SharedTests
|
14
12
|
|
15
13
|
def get_bare_client_id
|
16
|
-
|
14
|
+
@cache.storage.send(:bare_client).object_id
|
17
15
|
end
|
18
16
|
|
19
17
|
def test_treats_as_not_thread_safe
|
20
18
|
# make sure bare client is initialized
|
21
|
-
|
19
|
+
@cache.get 'hi'
|
22
20
|
|
23
21
|
# get the main thread's bare client
|
24
22
|
main_thread_bare_client_id = get_bare_client_id
|
25
23
|
|
26
24
|
# sanity check that it's not changing every time
|
27
|
-
|
25
|
+
@cache.get 'hi'
|
28
26
|
assert_equal main_thread_bare_client_id, get_bare_client_id
|
29
27
|
|
30
28
|
# create a new thread and get its bare client
|
31
|
-
new_thread_bare_client_id = Thread.new {
|
29
|
+
new_thread_bare_client_id = Thread.new { @cache.get 'hi'; get_bare_client_id }.value
|
32
30
|
|
33
31
|
# make sure the bare client was reinitialized
|
34
32
|
assert(main_thread_bare_client_id != new_thread_bare_client_id)
|
@@ -36,18 +34,18 @@ class TestMemcachedStorage < Test::Unit::TestCase
|
|
36
34
|
|
37
35
|
def test_treats_as_not_fork_safe
|
38
36
|
# make sure bare client is initialized
|
39
|
-
|
37
|
+
@cache.get 'hi'
|
40
38
|
|
41
39
|
# get the main process's bare client
|
42
40
|
parent_process_bare_client_id = get_bare_client_id
|
43
41
|
|
44
42
|
# sanity check that it's not changing every time
|
45
|
-
|
43
|
+
@cache.get 'hi'
|
46
44
|
assert_equal parent_process_bare_client_id, get_bare_client_id
|
47
45
|
|
48
46
|
# fork a new process
|
49
47
|
pid = Kernel.fork do
|
50
|
-
|
48
|
+
@cache.get 'hi'
|
51
49
|
raise "Didn't split!" if parent_process_bare_client_id == get_bare_client_id
|
52
50
|
end
|
53
51
|
Process.wait pid
|
data/test/test_redis_storage.rb
CHANGED
@@ -6,18 +6,16 @@ if ENV['REDIS_URL']
|
|
6
6
|
|
7
7
|
class TestRedisStorage < Test::Unit::TestCase
|
8
8
|
def setup
|
9
|
-
super
|
10
9
|
uri = URI.parse(ENV["REDIS_URL"])
|
11
|
-
client = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
12
|
-
|
13
|
-
Cache.config.client = client
|
10
|
+
@client = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
11
|
+
super
|
14
12
|
end
|
15
13
|
|
16
14
|
include SharedTests
|
17
15
|
|
18
16
|
# client DOT client
|
19
17
|
def get_redis_client_connection_socket_id
|
20
|
-
connection =
|
18
|
+
connection = @cache.config.client.client.instance_variable_get :@connection
|
21
19
|
sock = connection.instance_variable_get(:@sock)
|
22
20
|
# $stderr.puts sock.inspect
|
23
21
|
sock.object_id
|
@@ -25,17 +23,17 @@ if ENV['REDIS_URL']
|
|
25
23
|
|
26
24
|
def test_treats_as_thread_safe
|
27
25
|
# make sure ring is initialized
|
28
|
-
|
26
|
+
@cache.get 'hi'
|
29
27
|
|
30
28
|
# get the main thread's ring
|
31
29
|
main_thread_redis_client_connection_socket_id = get_redis_client_connection_socket_id
|
32
30
|
|
33
31
|
# sanity check that it's not changing every time
|
34
|
-
|
32
|
+
@cache.get 'hi'
|
35
33
|
assert_equal main_thread_redis_client_connection_socket_id, get_redis_client_connection_socket_id
|
36
34
|
|
37
35
|
# create a new thread and get its ring
|
38
|
-
new_thread_redis_client_connection_socket_id = Thread.new {
|
36
|
+
new_thread_redis_client_connection_socket_id = Thread.new { @cache.get 'hi'; get_redis_client_connection_socket_id }.value
|
39
37
|
|
40
38
|
# make sure the ring was reinitialized
|
41
39
|
assert_equal main_thread_redis_client_connection_socket_id, new_thread_redis_client_connection_socket_id
|
@@ -43,18 +41,18 @@ if ENV['REDIS_URL']
|
|
43
41
|
|
44
42
|
def test_treats_as_not_fork_safe
|
45
43
|
# make sure ring is initialized
|
46
|
-
|
44
|
+
@cache.get 'hi'
|
47
45
|
|
48
46
|
# get the main thread's ring
|
49
47
|
parent_process_redis_client_connection_socket_id = get_redis_client_connection_socket_id
|
50
48
|
|
51
49
|
# sanity check that it's not changing every time
|
52
|
-
|
50
|
+
@cache.get 'hi'
|
53
51
|
assert_equal parent_process_redis_client_connection_socket_id, get_redis_client_connection_socket_id
|
54
52
|
|
55
53
|
# fork a new process
|
56
54
|
pid = Kernel.fork do
|
57
|
-
|
55
|
+
@cache.get 'hi'
|
58
56
|
raise "Didn't split!" if parent_process_redis_client_connection_socket_id == get_redis_client_connection_socket_id
|
59
57
|
end
|
60
58
|
Process.wait pid
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 2
|
10
|
+
version: 0.0.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Seamus Abshere
|