cache 0.0.1
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.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/README.rdoc +56 -0
- data/Rakefile +22 -0
- data/cache.gemspec +29 -0
- data/lib/cache.rb +42 -0
- data/lib/cache/config.rb +45 -0
- data/lib/cache/storage.rb +90 -0
- data/lib/cache/version.rb +3 -0
- data/test/helper.rb +13 -0
- data/test/shared_tests.rb +41 -0
- data/test/test_dalli_storage.rb +58 -0
- data/test/test_dalli_store_storage.rb +61 -0
- data/test/test_memcache_storage.rb +59 -0
- data/test/test_memcached_rails_storage.rb +58 -0
- data/test/test_memcached_storage.rb +58 -0
- data/test/test_redis_storage.rb +66 -0
- metadata +190 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
= cache
|
2
|
+
|
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
|
+
|
5
|
+
== Methods
|
6
|
+
|
7
|
+
* get
|
8
|
+
* set
|
9
|
+
* delete
|
10
|
+
* flush
|
11
|
+
|
12
|
+
== Supported clients
|
13
|
+
|
14
|
+
Supported memcached clients:
|
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
|
+
|
22
|
+
* redis[https://github.com/ezmobius/redis-rb]
|
23
|
+
|
24
|
+
== Configuration
|
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
|
33
|
+
|
34
|
+
or this might even work...
|
35
|
+
|
36
|
+
Cache.config.client = Rails.cache
|
37
|
+
|
38
|
+
== TTL
|
39
|
+
|
40
|
+
0 means don't expire.
|
41
|
+
|
42
|
+
== Rationale
|
43
|
+
|
44
|
+
* I am so tired of rescuing from Memcached::NotFound
|
45
|
+
* I am so tired of forgetting whether it's :expires_in or :ttl
|
46
|
+
* I don't know why we ever started using read/write instead of get/set.
|
47
|
+
|
48
|
+
== Currently unsupported
|
49
|
+
|
50
|
+
* cas
|
51
|
+
* fetch
|
52
|
+
* incr
|
53
|
+
|
54
|
+
== Copyright
|
55
|
+
|
56
|
+
Copyright 2011 Seamus Abshere
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/testtask'
|
6
|
+
Rake::TestTask.new(:test) do |test|
|
7
|
+
test.libs << 'lib' << 'test'
|
8
|
+
test.pattern = 'test/**/test_*.rb'
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => :test
|
13
|
+
|
14
|
+
require 'rake/rdoctask'
|
15
|
+
Rake::RDocTask.new do |rdoc|
|
16
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
17
|
+
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = "cache #{version}"
|
20
|
+
rdoc.rdoc_files.include('README*')
|
21
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
|
+
end
|
data/cache.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cache/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cache"
|
7
|
+
s.version = Cache::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Seamus Abshere"]
|
10
|
+
s.email = ["seamus@abshere.net"]
|
11
|
+
s.homepage = "https://github.com/seamusabshere/cache"
|
12
|
+
s.summary = %q{Wraps memcached, redis, memcache-client, dalli and handles their weirdnesses, including forking}
|
13
|
+
s.description = %q{A unified cache handling interface for Ruby, inspired by (but simpler than) Perl's Cache::Cache}
|
14
|
+
|
15
|
+
s.rubyforge_project = "cache"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency 'test-unit'
|
23
|
+
s.add_development_dependency 'redis'
|
24
|
+
s.add_development_dependency 'dalli'
|
25
|
+
s.add_development_dependency 'activesupport', '>=2.3.4' # for DalliStore
|
26
|
+
s.add_development_dependency 'i18n' # activesupport
|
27
|
+
s.add_development_dependency 'memcached'
|
28
|
+
s.add_development_dependency 'memcache-client'
|
29
|
+
end
|
data/lib/cache.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'cache/version'
|
2
|
+
module Cache
|
3
|
+
autoload :Config, 'cache/config'
|
4
|
+
autoload :Storage, 'cache/storage'
|
5
|
+
|
6
|
+
def self.config #:nodoc:
|
7
|
+
Config.instance
|
8
|
+
end
|
9
|
+
|
10
|
+
# Get a value.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# Cache.get 'hello'
|
14
|
+
def self.get(k)
|
15
|
+
Storage.instance.get k
|
16
|
+
end
|
17
|
+
|
18
|
+
# Store a value. Note that this will Marshal it.
|
19
|
+
#
|
20
|
+
# Example:
|
21
|
+
# Cache.set 'hello', 'world'
|
22
|
+
# Cache.set 'hello', 'world', 80 # seconds til it expires
|
23
|
+
def self.set(k, v, ttl = nil)
|
24
|
+
Storage.instance.set k, v, ttl
|
25
|
+
end
|
26
|
+
|
27
|
+
# Delete a value.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# Cache.delete 'hello'
|
31
|
+
def self.delete(k)
|
32
|
+
Storage.instance.delete k
|
33
|
+
end
|
34
|
+
|
35
|
+
# Flush the cache.
|
36
|
+
#
|
37
|
+
# Example:
|
38
|
+
# Cache.flush
|
39
|
+
def self.flush
|
40
|
+
Storage.instance.flush
|
41
|
+
end
|
42
|
+
end
|
data/lib/cache/config.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
module Cache
|
3
|
+
# Here's where you set config options.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
# Cache.config.client = Memcached.new '127.0.0.1:11211'
|
7
|
+
# Cache.config.default_ttl = 120 # seconds
|
8
|
+
#
|
9
|
+
# You'd probably put this in your Rails config/initializers, for example.
|
10
|
+
class Config
|
11
|
+
include ::Singleton
|
12
|
+
|
13
|
+
# The cache client to use.
|
14
|
+
#
|
15
|
+
# Supported memcached clients:
|
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]
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
# Cache.config.storage = Memcached.new '127.0.0.1:11211'
|
25
|
+
def client=(client)
|
26
|
+
@client = client
|
27
|
+
end
|
28
|
+
|
29
|
+
def client #:nodoc:
|
30
|
+
@client
|
31
|
+
end
|
32
|
+
|
33
|
+
# TTL for method caches. Defaults to 60 seconds.
|
34
|
+
#
|
35
|
+
# Example:
|
36
|
+
# Cache.config.default_ttl = 120 # seconds
|
37
|
+
def default_ttl=(seconds)
|
38
|
+
@default_ttl = seconds
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_ttl #:nodoc:
|
42
|
+
@default_ttl || 60
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
module Cache
|
3
|
+
class Storage #:nodoc: all
|
4
|
+
include ::Singleton
|
5
|
+
|
6
|
+
def get(k)
|
7
|
+
if defined?(::Memcached) and bare_client.is_a?(::Memcached)
|
8
|
+
begin; bare_client.get(k); rescue ::Memcached::NotFound; nil; end
|
9
|
+
elsif defined?(::Redis) and bare_client.is_a?(::Redis)
|
10
|
+
if cached_v = bare_client.get(k) and cached_v.is_a?(::String)
|
11
|
+
::Marshal.load cached_v
|
12
|
+
end
|
13
|
+
elsif bare_client.respond_to?(:get)
|
14
|
+
bare_client.get k
|
15
|
+
elsif bare_client.respond_to?(:read)
|
16
|
+
bare_client.read k
|
17
|
+
else
|
18
|
+
raise "Don't know how to work with #{bare_client.inspect} because it doesn't define get"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def set(k, v, ttl)
|
23
|
+
ttl ||= Config.instance.default_ttl
|
24
|
+
if defined?(::Redis) and bare_client.is_a?(::Redis)
|
25
|
+
if ttl == 0
|
26
|
+
bare_client.set k, ::Marshal.dump(v)
|
27
|
+
else
|
28
|
+
bare_client.setex k, ttl, ::Marshal.dump(v)
|
29
|
+
end
|
30
|
+
elsif bare_client.respond_to?(:set)
|
31
|
+
bare_client.set k, v, ttl
|
32
|
+
elsif bare_client.respond_to?(:write)
|
33
|
+
if ttl == 0
|
34
|
+
bare_client.write k, v # never expire
|
35
|
+
else
|
36
|
+
bare_client.write k, v, :expires_in => ttl
|
37
|
+
end
|
38
|
+
else
|
39
|
+
raise "Don't know how to work with #{bare_client.inspect} because it doesn't define set"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(k)
|
44
|
+
if defined?(::Memcached) and bare_client.is_a?(::Memcached)
|
45
|
+
begin; bare_client.delete(k); rescue ::Memcached::NotFound; nil; end
|
46
|
+
elsif defined?(::Redis) and bare_client.is_a?(::Redis)
|
47
|
+
bare_client.del k
|
48
|
+
elsif bare_client.respond_to?(:delete)
|
49
|
+
bare_client.delete k
|
50
|
+
else
|
51
|
+
raise "Don't know how to work with #{bare_client.inspect} because it doesn't define delete"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def flush
|
56
|
+
bare_client.send %w{ flush flushdb flush_all clear }.detect { |flush_cmd| bare_client.respond_to? flush_cmd }
|
57
|
+
end
|
58
|
+
|
59
|
+
def bare_client
|
60
|
+
if @pid == ::Process.pid
|
61
|
+
fork_detected = false
|
62
|
+
else
|
63
|
+
fork_detected = true
|
64
|
+
::Thread.current[:cache_storage_bare_client] = nil
|
65
|
+
@pid = ::Process.pid
|
66
|
+
end
|
67
|
+
::Thread.current[:cache_storage_bare_client] ||= fresh_bare_client(fork_detected)
|
68
|
+
end
|
69
|
+
|
70
|
+
def fresh_bare_client(fork_detected)
|
71
|
+
if defined?(::Dalli) and Config.instance.client.is_a?(::Dalli::Client)
|
72
|
+
Config.instance.client.close if fork_detected
|
73
|
+
Config.instance.client
|
74
|
+
elsif defined?(::ActiveSupport::Cache::DalliStore) and Config.instance.client.is_a?(::ActiveSupport::Cache::DalliStore)
|
75
|
+
Config.instance.client.reset if fork_detected
|
76
|
+
Config.instance.client
|
77
|
+
elsif defined?(::Memcached) and (Config.instance.client.is_a?(::Memcached) or Config.instance.client.is_a?(::Memcached::Rails))
|
78
|
+
Config.instance.client.clone
|
79
|
+
elsif defined?(::Redis) and Config.instance.client.is_a?(::Redis)
|
80
|
+
Config.instance.client.client.connect if fork_detected
|
81
|
+
Config.instance.client
|
82
|
+
elsif defined?(::MemCache) and Config.instance.client.is_a?(::MemCache)
|
83
|
+
Config.instance.client.reset if fork_detected
|
84
|
+
Config.instance.client
|
85
|
+
else
|
86
|
+
raise "Don't know how to thread/fork #{Config.instance.client.inspect}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
Bundler.setup
|
4
|
+
require 'test/unit'
|
5
|
+
# require 'ruby-debug'
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
8
|
+
require 'cache'
|
9
|
+
|
10
|
+
require 'shared_tests'
|
11
|
+
|
12
|
+
class Test::Unit::TestCase
|
13
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module SharedTests
|
2
|
+
def test_get
|
3
|
+
assert_equal nil, Cache.get('hello')
|
4
|
+
Cache.set 'hello', 'world'
|
5
|
+
assert_equal 'world', Cache.get('hello')
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_set
|
9
|
+
assert_nothing_raised do
|
10
|
+
Cache.set 'hello', 'world'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_set_with_ttl
|
15
|
+
Cache.set 'hello', 'world', 1
|
16
|
+
assert_equal 'world', Cache.get('hello')
|
17
|
+
sleep 2
|
18
|
+
assert_equal nil, Cache.get('hello')
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_set_with_zero_ttl_meaning_eternal
|
22
|
+
Cache.set 'hello', 'world', 0
|
23
|
+
assert_equal 'world', Cache.get('hello')
|
24
|
+
sleep 1
|
25
|
+
assert_equal 'world', Cache.get('hello')
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_delete
|
29
|
+
Cache.set 'hello', 'world'
|
30
|
+
assert_equal 'world', Cache.get('hello')
|
31
|
+
Cache.delete 'hello'
|
32
|
+
assert_equal nil, Cache.get('hello')
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_flush
|
36
|
+
Cache.set 'hello', 'world'
|
37
|
+
assert_equal 'world', Cache.get('hello')
|
38
|
+
Cache.flush
|
39
|
+
assert_equal nil, Cache.get('hello')
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'dalli'
|
4
|
+
|
5
|
+
class TestDalliStorage < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
client = Dalli::Client.new ['localhost:11211']
|
9
|
+
client.flush
|
10
|
+
Cache.config.client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
include SharedTests
|
14
|
+
|
15
|
+
def get_ring_object_id
|
16
|
+
Cache.config.client.instance_variable_get(:@ring).object_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_treats_as_thread_safe
|
20
|
+
# make sure ring is initialized
|
21
|
+
Cache.get 'hi'
|
22
|
+
|
23
|
+
# get the main thread's ring
|
24
|
+
main_thread_ring_id = get_ring_object_id
|
25
|
+
|
26
|
+
# sanity check that it's not changing every time
|
27
|
+
Cache.get 'hi'
|
28
|
+
assert_equal main_thread_ring_id, get_ring_object_id
|
29
|
+
|
30
|
+
# create a new thread and get its ring
|
31
|
+
new_thread_ring_id = Thread.new { Cache.get 'hi'; get_ring_object_id }.value
|
32
|
+
|
33
|
+
# make sure the ring was reinitialized
|
34
|
+
assert_equal main_thread_ring_id, new_thread_ring_id
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_treats_as_not_fork_safe
|
38
|
+
# make sure ring is initialized
|
39
|
+
Cache.get 'hi'
|
40
|
+
|
41
|
+
# get the main thread's ring
|
42
|
+
parent_process_ring_id = get_ring_object_id
|
43
|
+
|
44
|
+
# sanity check that it's not changing every time
|
45
|
+
Cache.get 'hi'
|
46
|
+
assert_equal parent_process_ring_id, get_ring_object_id
|
47
|
+
|
48
|
+
# fork a new process
|
49
|
+
pid = Kernel.fork do
|
50
|
+
Cache.get 'hi'
|
51
|
+
raise "Didn't split!" if parent_process_ring_id == get_ring_object_id
|
52
|
+
end
|
53
|
+
Process.wait pid
|
54
|
+
|
55
|
+
# make sure it didn't raise
|
56
|
+
assert $?.success?
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'dalli'
|
4
|
+
require 'active_support/all'
|
5
|
+
require 'active_support/cache/dalli_store'
|
6
|
+
|
7
|
+
class TestDalliStoreStorage < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
client = ActiveSupport::Cache::DalliStore.new ['localhost:11211']
|
11
|
+
client.clear
|
12
|
+
Cache.config.client = client
|
13
|
+
end
|
14
|
+
|
15
|
+
include SharedTests
|
16
|
+
|
17
|
+
def get_ring_object_id
|
18
|
+
hidden_dalli_client = Cache.config.client.instance_variable_get :@data
|
19
|
+
hidden_dalli_client.instance_variable_get(:@ring).object_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_treats_as_thread_safe
|
23
|
+
# make sure ring is initialized
|
24
|
+
Cache.get 'hi'
|
25
|
+
|
26
|
+
# get the main thread's ring
|
27
|
+
main_thread_ring_id = get_ring_object_id
|
28
|
+
|
29
|
+
# sanity check that it's not changing every time
|
30
|
+
Cache.get 'hi'
|
31
|
+
assert_equal main_thread_ring_id, get_ring_object_id
|
32
|
+
|
33
|
+
# create a new thread and get its ring
|
34
|
+
new_thread_ring_id = Thread.new { Cache.get 'hi'; get_ring_object_id }.value
|
35
|
+
|
36
|
+
# make sure the ring was reinitialized
|
37
|
+
assert_equal main_thread_ring_id, new_thread_ring_id
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_treats_as_not_fork_safe
|
41
|
+
# make sure ring is initialized
|
42
|
+
Cache.get 'hi'
|
43
|
+
|
44
|
+
# get the main thread's ring
|
45
|
+
parent_process_ring_id = get_ring_object_id
|
46
|
+
|
47
|
+
# sanity check that it's not changing every time
|
48
|
+
Cache.get 'hi'
|
49
|
+
assert_equal parent_process_ring_id, get_ring_object_id
|
50
|
+
|
51
|
+
# fork a new process
|
52
|
+
pid = Kernel.fork do
|
53
|
+
Cache.get 'hi'
|
54
|
+
raise "Didn't split!" if parent_process_ring_id == get_ring_object_id
|
55
|
+
end
|
56
|
+
Process.wait pid
|
57
|
+
|
58
|
+
# make sure it didn't raise
|
59
|
+
assert $?.success?
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
# the famous memcache-client
|
4
|
+
require 'memcache'
|
5
|
+
|
6
|
+
class TestMemcacheStorage < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
super
|
9
|
+
client = MemCache.new ['localhost:11211']
|
10
|
+
client.flush_all
|
11
|
+
Cache.config.client = client
|
12
|
+
end
|
13
|
+
|
14
|
+
include SharedTests
|
15
|
+
|
16
|
+
def get_server_status_ids
|
17
|
+
Cache.config.client.instance_variable_get(:@servers).map { |s| s.status.object_id }
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_treats_as_thread_safe
|
21
|
+
# make sure servers are connected
|
22
|
+
Cache.get 'hi'
|
23
|
+
|
24
|
+
# get the object ids
|
25
|
+
main_thread_server_status_ids = get_server_status_ids
|
26
|
+
|
27
|
+
# sanity check that it's not changing every time
|
28
|
+
Cache.get 'hi'
|
29
|
+
assert_equal main_thread_server_status_ids, get_server_status_ids
|
30
|
+
|
31
|
+
# create a new thread and get its server ids
|
32
|
+
new_thread_server_status_ids = Thread.new { Cache.get 'hi'; get_server_status_ids }.value
|
33
|
+
|
34
|
+
# make sure the server ids was reinitialized
|
35
|
+
assert_equal main_thread_server_status_ids, new_thread_server_status_ids
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_treats_as_not_fork_safe
|
39
|
+
# make sure server ids is initialized
|
40
|
+
Cache.get 'hi'
|
41
|
+
|
42
|
+
# get the main thread's server ids
|
43
|
+
parent_process_server_status_ids = get_server_status_ids
|
44
|
+
|
45
|
+
# sanity check that it's not changing every time
|
46
|
+
Cache.get 'hi'
|
47
|
+
assert_equal parent_process_server_status_ids, get_server_status_ids
|
48
|
+
|
49
|
+
# fork a new process
|
50
|
+
pid = Kernel.fork do
|
51
|
+
Cache.get 'hi'
|
52
|
+
raise "Didn't split!" if parent_process_server_status_ids == get_server_status_ids
|
53
|
+
end
|
54
|
+
Process.wait pid
|
55
|
+
|
56
|
+
# make sure it didn't raise
|
57
|
+
assert $?.success?
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'memcached'
|
4
|
+
|
5
|
+
class TestMemcachedRailsStorage < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
client = Memcached::Rails.new 'localhost:11211'
|
9
|
+
client.flush
|
10
|
+
Cache.config.client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
include SharedTests
|
14
|
+
|
15
|
+
def get_bare_client_id
|
16
|
+
Cache::Storage.instance.bare_client.object_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_treats_as_not_thread_safe
|
20
|
+
# make sure bare client is initialized
|
21
|
+
Cache.get 'hi'
|
22
|
+
|
23
|
+
# get the main thread's bare client
|
24
|
+
main_thread_bare_client_id = get_bare_client_id
|
25
|
+
|
26
|
+
# sanity check that it's not changing every time
|
27
|
+
Cache.get 'hi'
|
28
|
+
assert_equal main_thread_bare_client_id, get_bare_client_id
|
29
|
+
|
30
|
+
# create a new thread and get its bare client
|
31
|
+
new_thread_bare_client_id = Thread.new { Cache.get 'hi'; get_bare_client_id }.value
|
32
|
+
|
33
|
+
# make sure the bare client was reinitialized
|
34
|
+
assert(main_thread_bare_client_id != new_thread_bare_client_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_treats_as_not_fork_safe
|
38
|
+
# make sure bare client is initialized
|
39
|
+
Cache.get 'hi'
|
40
|
+
|
41
|
+
# get the main process's bare client
|
42
|
+
parent_process_bare_client_id = get_bare_client_id
|
43
|
+
|
44
|
+
# sanity check that it's not changing every time
|
45
|
+
Cache.get 'hi'
|
46
|
+
assert_equal parent_process_bare_client_id, get_bare_client_id
|
47
|
+
|
48
|
+
# fork a new process
|
49
|
+
pid = Kernel.fork do
|
50
|
+
Cache.get 'hi'
|
51
|
+
raise "Didn't split!" if parent_process_bare_client_id == get_bare_client_id
|
52
|
+
end
|
53
|
+
Process.wait pid
|
54
|
+
|
55
|
+
# make sure it didn't raise
|
56
|
+
assert $?.success?
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'memcached'
|
4
|
+
|
5
|
+
class TestMemcachedStorage < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
super
|
8
|
+
client = Memcached.new 'localhost:11211'
|
9
|
+
client.flush
|
10
|
+
Cache.config.client = client
|
11
|
+
end
|
12
|
+
|
13
|
+
include SharedTests
|
14
|
+
|
15
|
+
def get_bare_client_id
|
16
|
+
Cache::Storage.instance.bare_client.object_id
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_treats_as_not_thread_safe
|
20
|
+
# make sure bare client is initialized
|
21
|
+
Cache.get 'hi'
|
22
|
+
|
23
|
+
# get the main thread's bare client
|
24
|
+
main_thread_bare_client_id = get_bare_client_id
|
25
|
+
|
26
|
+
# sanity check that it's not changing every time
|
27
|
+
Cache.get 'hi'
|
28
|
+
assert_equal main_thread_bare_client_id, get_bare_client_id
|
29
|
+
|
30
|
+
# create a new thread and get its bare client
|
31
|
+
new_thread_bare_client_id = Thread.new { Cache.get 'hi'; get_bare_client_id }.value
|
32
|
+
|
33
|
+
# make sure the bare client was reinitialized
|
34
|
+
assert(main_thread_bare_client_id != new_thread_bare_client_id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_treats_as_not_fork_safe
|
38
|
+
# make sure bare client is initialized
|
39
|
+
Cache.get 'hi'
|
40
|
+
|
41
|
+
# get the main process's bare client
|
42
|
+
parent_process_bare_client_id = get_bare_client_id
|
43
|
+
|
44
|
+
# sanity check that it's not changing every time
|
45
|
+
Cache.get 'hi'
|
46
|
+
assert_equal parent_process_bare_client_id, get_bare_client_id
|
47
|
+
|
48
|
+
# fork a new process
|
49
|
+
pid = Kernel.fork do
|
50
|
+
Cache.get 'hi'
|
51
|
+
raise "Didn't split!" if parent_process_bare_client_id == get_bare_client_id
|
52
|
+
end
|
53
|
+
Process.wait pid
|
54
|
+
|
55
|
+
# make sure it didn't raise
|
56
|
+
assert $?.success?
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
if ENV['REDIS_URL']
|
4
|
+
require 'redis'
|
5
|
+
require 'uri'
|
6
|
+
|
7
|
+
class TestRedisStorage < Test::Unit::TestCase
|
8
|
+
def setup
|
9
|
+
super
|
10
|
+
uri = URI.parse(ENV["REDIS_URL"])
|
11
|
+
client = Redis.new(:host => uri.host, :port => uri.port, :password => uri.password)
|
12
|
+
client.flushdb
|
13
|
+
Cache.config.client = client
|
14
|
+
end
|
15
|
+
|
16
|
+
include SharedTests
|
17
|
+
|
18
|
+
# client DOT client
|
19
|
+
def get_redis_client_connection_socket_id
|
20
|
+
connection = Cache.config.client.client.instance_variable_get :@connection
|
21
|
+
sock = connection.instance_variable_get(:@sock)
|
22
|
+
# $stderr.puts sock.inspect
|
23
|
+
sock.object_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_treats_as_thread_safe
|
27
|
+
# make sure ring is initialized
|
28
|
+
Cache.get 'hi'
|
29
|
+
|
30
|
+
# get the main thread's ring
|
31
|
+
main_thread_redis_client_connection_socket_id = get_redis_client_connection_socket_id
|
32
|
+
|
33
|
+
# sanity check that it's not changing every time
|
34
|
+
Cache.get 'hi'
|
35
|
+
assert_equal main_thread_redis_client_connection_socket_id, get_redis_client_connection_socket_id
|
36
|
+
|
37
|
+
# create a new thread and get its ring
|
38
|
+
new_thread_redis_client_connection_socket_id = Thread.new { Cache.get 'hi'; get_redis_client_connection_socket_id }.value
|
39
|
+
|
40
|
+
# make sure the ring was reinitialized
|
41
|
+
assert_equal main_thread_redis_client_connection_socket_id, new_thread_redis_client_connection_socket_id
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_treats_as_not_fork_safe
|
45
|
+
# make sure ring is initialized
|
46
|
+
Cache.get 'hi'
|
47
|
+
|
48
|
+
# get the main thread's ring
|
49
|
+
parent_process_redis_client_connection_socket_id = get_redis_client_connection_socket_id
|
50
|
+
|
51
|
+
# sanity check that it's not changing every time
|
52
|
+
Cache.get 'hi'
|
53
|
+
assert_equal parent_process_redis_client_connection_socket_id, get_redis_client_connection_socket_id
|
54
|
+
|
55
|
+
# fork a new process
|
56
|
+
pid = Kernel.fork do
|
57
|
+
Cache.get 'hi'
|
58
|
+
raise "Didn't split!" if parent_process_redis_client_connection_socket_id == get_redis_client_connection_socket_id
|
59
|
+
end
|
60
|
+
Process.wait pid
|
61
|
+
|
62
|
+
# make sure it didn't raise
|
63
|
+
assert $?.success?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
metadata
ADDED
@@ -0,0 +1,190 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Seamus Abshere
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-17 00:00:00 -06:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: test-unit
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: redis
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
type: :development
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: dalli
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: activesupport
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 11
|
72
|
+
segments:
|
73
|
+
- 2
|
74
|
+
- 3
|
75
|
+
- 4
|
76
|
+
version: 2.3.4
|
77
|
+
type: :development
|
78
|
+
version_requirements: *id004
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: i18n
|
81
|
+
prerelease: false
|
82
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
hash: 3
|
88
|
+
segments:
|
89
|
+
- 0
|
90
|
+
version: "0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id005
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: memcached
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
hash: 3
|
102
|
+
segments:
|
103
|
+
- 0
|
104
|
+
version: "0"
|
105
|
+
type: :development
|
106
|
+
version_requirements: *id006
|
107
|
+
- !ruby/object:Gem::Dependency
|
108
|
+
name: memcache-client
|
109
|
+
prerelease: false
|
110
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
hash: 3
|
116
|
+
segments:
|
117
|
+
- 0
|
118
|
+
version: "0"
|
119
|
+
type: :development
|
120
|
+
version_requirements: *id007
|
121
|
+
description: A unified cache handling interface for Ruby, inspired by (but simpler than) Perl's Cache::Cache
|
122
|
+
email:
|
123
|
+
- seamus@abshere.net
|
124
|
+
executables: []
|
125
|
+
|
126
|
+
extensions: []
|
127
|
+
|
128
|
+
extra_rdoc_files: []
|
129
|
+
|
130
|
+
files:
|
131
|
+
- .gitignore
|
132
|
+
- Gemfile
|
133
|
+
- README.rdoc
|
134
|
+
- Rakefile
|
135
|
+
- cache.gemspec
|
136
|
+
- lib/cache.rb
|
137
|
+
- lib/cache/config.rb
|
138
|
+
- lib/cache/storage.rb
|
139
|
+
- lib/cache/version.rb
|
140
|
+
- test/helper.rb
|
141
|
+
- test/shared_tests.rb
|
142
|
+
- test/test_dalli_storage.rb
|
143
|
+
- test/test_dalli_store_storage.rb
|
144
|
+
- test/test_memcache_storage.rb
|
145
|
+
- test/test_memcached_rails_storage.rb
|
146
|
+
- test/test_memcached_storage.rb
|
147
|
+
- test/test_redis_storage.rb
|
148
|
+
has_rdoc: true
|
149
|
+
homepage: https://github.com/seamusabshere/cache
|
150
|
+
licenses: []
|
151
|
+
|
152
|
+
post_install_message:
|
153
|
+
rdoc_options: []
|
154
|
+
|
155
|
+
require_paths:
|
156
|
+
- lib
|
157
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
hash: 3
|
163
|
+
segments:
|
164
|
+
- 0
|
165
|
+
version: "0"
|
166
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
168
|
+
requirements:
|
169
|
+
- - ">="
|
170
|
+
- !ruby/object:Gem::Version
|
171
|
+
hash: 3
|
172
|
+
segments:
|
173
|
+
- 0
|
174
|
+
version: "0"
|
175
|
+
requirements: []
|
176
|
+
|
177
|
+
rubyforge_project: cache
|
178
|
+
rubygems_version: 1.3.7
|
179
|
+
signing_key:
|
180
|
+
specification_version: 3
|
181
|
+
summary: Wraps memcached, redis, memcache-client, dalli and handles their weirdnesses, including forking
|
182
|
+
test_files:
|
183
|
+
- test/helper.rb
|
184
|
+
- test/shared_tests.rb
|
185
|
+
- test/test_dalli_storage.rb
|
186
|
+
- test/test_dalli_store_storage.rb
|
187
|
+
- test/test_memcache_storage.rb
|
188
|
+
- test/test_memcached_rails_storage.rb
|
189
|
+
- test/test_memcached_storage.rb
|
190
|
+
- test/test_redis_storage.rb
|