rails2_libmemcached_store 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjU2YzlkOGNhMjlmNjc4MzIxMWEzYmE3MDExY2MwNzc3ZWU5OTQ0ZQ==
5
+ data.tar.gz: !binary |-
6
+ ZjI0NzE1YzY0YWE1NDI5YTE5M2U4MjJmM2IyMjUxYmFhZDkwZWQ1OA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MzUzZDdiYmMwMDA2OGY2NzMwZjI2MzEzM2NmN2JlODhhYTJhZmM5MmM4ZmQ3
10
+ ZjVlMDQzMDM3ZGYzODk4MWRhMTQ5ODI4MzA4NDEzNWY1ZDZhOTFhNmJlNWQ0
11
+ MjVjOTg0NDcyZmQwNTQ4ZmNkYjMwZDYyZTYzZDRiNDkwYmFkYzg=
12
+ data.tar.gz: !binary |-
13
+ Mjc2YTQ0NzA3NmNjZjQ4YmU2NjZlNWFmYTFhMDkyMzdlZmNmNDM1NGViNDMy
14
+ ZGYwOWRhZjljN2U0OWIxMzAwOWZmMjE2NzM2NjAxOWZiMjAzNGI1NzIwMTM0
15
+ ZmM1ZDQ5ZDdhN2E1ZDBkNDYxZDI3NTlkYTE2ZDM0YTUyNGYwMGM=
@@ -15,14 +15,30 @@ end
15
15
  module ActiveSupport
16
16
  module Cache
17
17
  class LibmemcachedStore < Store
18
+ class FetchWithRaceConditionTTLEntry
19
+ attr_accessor :value, :extended
20
+
21
+ def initialize(value, expires_in)
22
+ @value, @extended = value, false
23
+ @expires_at = Time.now.to_i + expires_in
24
+ end
25
+
26
+ def expires_in
27
+ [@expires_at - Time.now.to_i, 1].max # never set to 0 -> never expires
28
+ end
29
+
30
+ def expired?
31
+ @expires_at <= Time.now.to_i
32
+ end
33
+ end
34
+
18
35
  attr_reader :addresses
19
36
 
20
37
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
21
38
 
22
39
  DEFAULT_OPTIONS = {
23
40
  :distribution => :consistent,
24
- :no_block => true,
25
- :failover => true
41
+ :no_block => true
26
42
  }
27
43
 
28
44
  def initialize(*addresses)
@@ -42,10 +58,44 @@ module ActiveSupport
42
58
  extend ActiveSupport::Cache::Strategy::LocalCache
43
59
  end
44
60
 
61
+ def fetch(key, options={}, &block)
62
+ if options && options[:race_condition_ttl]
63
+ fetch_with_race_condition_ttl(key, options, &block)
64
+ else
65
+ super
66
+ end
67
+ end
68
+
69
+ def fetch_with_race_condition_ttl(key, options={}, &block)
70
+ options = options.dup
71
+
72
+ race_ttl = options.delete(:race_condition_ttl) || raise("Use :race_condition_ttl option or normal fetch")
73
+ expires_in = options.fetch(:expires_in)
74
+ options[:expires_in] = expires_in + race_ttl
75
+ options[:preserve_race_condition_entry] = true
76
+
77
+ value = fetch(key, options) { FetchWithRaceConditionTTLEntry.new(yield, expires_in) }
78
+
79
+ return value unless value.is_a?(FetchWithRaceConditionTTLEntry)
80
+
81
+ if value.expired? && !value.extended
82
+ # we take care of refreshing the cache, all others should keep reading
83
+ value.extended = true
84
+ write(key, value, options.merge(:expires_in => value.expires_in + race_ttl))
85
+
86
+ # calculate new value and store it
87
+ value = FetchWithRaceConditionTTLEntry.new(yield, expires_in)
88
+ write(key, value, options)
89
+ end
90
+
91
+ value.value
92
+ end
93
+
45
94
  def read(key, options = nil)
46
95
  key = expanded_key(key)
47
96
  super
48
- @cache.get(escape_and_normalize(key), marshal?(options))
97
+ value = @cache.get(escape_and_normalize(key), marshal?(options))
98
+ convert_race_condition_entry(value, options)
49
99
  rescue Memcached::NotFound
50
100
  nil
51
101
  rescue Memcached::Error => e
@@ -67,8 +117,6 @@ module ActiveSupport
67
117
  values[mapping[key]] = value
68
118
  end
69
119
  values
70
- rescue Memcached::NotFound
71
- {}
72
120
  rescue Memcached::Error => e
73
121
  log_error(e)
74
122
  {}
@@ -144,6 +192,14 @@ module ActiveSupport
144
192
 
145
193
  private
146
194
 
195
+ def convert_race_condition_entry(value, options)
196
+ if (!options || !options[:preserve_race_condition_entry]) && value.is_a?(FetchWithRaceConditionTTLEntry)
197
+ value.value
198
+ else
199
+ value
200
+ end
201
+ end
202
+
147
203
  def escape_and_normalize(key)
148
204
  key = key.to_s.dup.force_encoding("BINARY").gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
149
205
  key_length = key.length
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails2_libmemcached_store
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
5
- prerelease:
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Jeffrey Hardy
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-05-10 00:00:00.000000000 Z
11
+ date: 2013-10-31 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ! '>='
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,48 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '4.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '4.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: timecop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: iconv
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
26
65
  requirements:
27
66
  - - ! '>='
28
67
  - !ruby/object:Gem::Version
@@ -30,7 +69,6 @@ dependencies:
30
69
  - !ruby/object:Gem::Dependency
31
70
  name: memcached
32
71
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
72
  requirements:
35
73
  - - ! '>='
36
74
  - !ruby/object:Gem::Version
@@ -38,7 +76,6 @@ dependencies:
38
76
  type: :runtime
39
77
  prerelease: false
40
78
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
79
  requirements:
43
80
  - - ! '>='
44
81
  - !ruby/object:Gem::Version
@@ -46,7 +83,6 @@ dependencies:
46
83
  - !ruby/object:Gem::Dependency
47
84
  name: activesupport
48
85
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
86
  requirements:
51
87
  - - <
52
88
  - !ruby/object:Gem::Version
@@ -54,7 +90,6 @@ dependencies:
54
90
  type: :runtime
55
91
  prerelease: false
56
92
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
93
  requirements:
59
94
  - - <
60
95
  - !ruby/object:Gem::Version
@@ -73,37 +108,27 @@ files:
73
108
  - lib/active_support/cache/libmemcached_store.rb
74
109
  - lib/libmemcached_store.rb
75
110
  - lib/rails2_libmemcached_store.rb
76
- - README
77
- - test/libmemcached_store_test.rb
78
- homepage: http://github.com/37signals/libmemcached_store
111
+ homepage: https://github.com/staugaard/libmemcached_store
79
112
  licenses: []
113
+ metadata: {}
80
114
  post_install_message:
81
115
  rdoc_options: []
82
116
  require_paths:
83
117
  - lib
84
118
  required_ruby_version: !ruby/object:Gem::Requirement
85
- none: false
86
119
  requirements:
87
120
  - - ! '>='
88
121
  - !ruby/object:Gem::Version
89
122
  version: '0'
90
- segments:
91
- - 0
92
- hash: 4269371507181365870
93
123
  required_rubygems_version: !ruby/object:Gem::Requirement
94
- none: false
95
124
  requirements:
96
125
  - - ! '>='
97
126
  - !ruby/object:Gem::Version
98
127
  version: '0'
99
- segments:
100
- - 0
101
- hash: 4269371507181365870
102
128
  requirements: []
103
129
  rubyforge_project:
104
- rubygems_version: 1.8.25
130
+ rubygems_version: 2.0.7
105
131
  signing_key:
106
- specification_version: 3
132
+ specification_version: 4
107
133
  summary: ActiveSupport::Cache wrapper for libmemcached
108
- test_files:
109
- - test/libmemcached_store_test.rb
134
+ test_files: []
data/README DELETED
@@ -1,47 +0,0 @@
1
- = LibmemcachedStore
2
-
3
- An ActiveSupport cache store that uses the C-based libmemcached client through
4
- Evan Weaver's Ruby/SWIG wrapper, memcached. libmemcached is fast, lightweight,
5
- and supports consistent hashing, non-blocking IO, and graceful server failover.
6
-
7
- == Prerequisites
8
-
9
- You'll need both the libmemcached client and the memcached gem:
10
-
11
- * http://tangent.org/552/libmemcached.html
12
- * http://blog.evanweaver.com/files/doc/fauna/memcached
13
-
14
- Make sure you install libmemcached first, before you try installing the gem. If
15
- you're using OS X, the easiest way to install libmemcached is through MacPorts:
16
-
17
- sudo port install libmemcached
18
-
19
- For other platforms, download and extract the libmemcached tarball and install
20
- manually:
21
-
22
- ./configure
23
- make && sudo make install
24
-
25
- Once libmemcached is installed, install the memcached gem:
26
-
27
- gem install memcached --no-rdoc --no-ri
28
-
29
- == Usage
30
-
31
- This is a drop-in replacement for the memcache store that ships with Rails. To
32
- enable, set the <tt>config.cache_store</tt> option to <tt>:libmemcached_store</tt>
33
- in the config for your environment
34
-
35
- config.cache_store = :libmemcached_store
36
-
37
- If no servers are specified, localhost is assumed. You can specify a list of
38
- server addresses, either as hostnames or IP addresses, with or without a port
39
- designation. If no port is given, 11211 is assumed:
40
-
41
- config.cache_store = :libmemcached_store, %w(cache-01 cache-02 127.0.0.1:11212)
42
-
43
- == Props
44
-
45
- Thanks to Brian Aker (http://tangent.org) for creating libmemcached, and Evan
46
- Weaver (http://blog.evanweaver.com) for the Ruby wrapper.
47
-
@@ -1,84 +0,0 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
- require 'active_support'
4
- require 'memcached'
5
-
6
- require File.dirname(__FILE__) + '/../lib/libmemcached_store'
7
-
8
- # Make it easier to get at the underlying cache options during testing.
9
- class ActiveSupport::Cache::LibmemcachedStore
10
- delegate :options, :to => '@cache'
11
- end
12
-
13
- class LibmemcachedStoreTest < Test::Unit::TestCase
14
- def setup
15
- @store = ActiveSupport::Cache.lookup_store :libmemcached_store
16
- @store.clear
17
- end
18
-
19
- def test_should_identify_cache_store
20
- assert_kind_of ActiveSupport::Cache::LibmemcachedStore, @store
21
- end
22
-
23
- def test_should_set_server_addresses_to_localhost_if_none_are_given
24
- assert_equal %w(localhost), @store.addresses
25
- end
26
-
27
- def test_should_set_custom_server_addresses
28
- store = ActiveSupport::Cache.lookup_store :libmemcached_store, 'localhost', '192.168.1.1'
29
- assert_equal %w(localhost 192.168.1.1), store.addresses
30
- end
31
-
32
- def test_should_enable_consistent_hashing_by_default
33
- assert_equal :consistent, @store.options[:distribution]
34
- end
35
-
36
- def test_should_enable_non_blocking_io_by_default
37
- assert_equal true, @store.options[:no_block]
38
- end
39
-
40
- def test_should_enable_server_failover_by_default
41
- assert_equal true, @store.options[:auto_eject_hosts]
42
- end
43
-
44
- def test_should_allow_configuration_of_custom_options
45
- options = {
46
- :prefix_key => 'test',
47
- :distribution => :modula,
48
- :no_block => false,
49
- :auto_eject_hosts => false
50
- }
51
-
52
- store = ActiveSupport::Cache.lookup_store :libmemcached_store, 'localhost', options
53
-
54
- assert_equal 'test', store.instance_variable_get(:@cache).prefix_key
55
- assert_equal :modula, store.options[:distribution]
56
- assert_equal false, store.options[:no_block]
57
- assert_equal false, store.options[:auto_eject_hosts]
58
- end
59
-
60
- def test_should_use_local_cache
61
- @store.with_local_cache do
62
- @store.write('key', 'value')
63
- assert_equal 'value', @store.send(:local_cache).read('key')
64
- end
65
-
66
- assert_equal 'value', @store.read('key')
67
- end
68
-
69
- def test_should_read_multiple_keys
70
- @store.write('a', 1)
71
- @store.write('b', 2)
72
-
73
- assert_equal({ 'a' => 1, 'b' => 2 }, @store.read_multi('a', 'b', 'c'))
74
- assert_equal({}, @store.read_multi())
75
- end
76
-
77
- def test_should_fix_long_keys
78
- key = ("0123456789" * 100).freeze
79
- assert key.size > 250
80
- @store.write(key, 1)
81
- assert_equal 1, @store.read(key)
82
- end
83
-
84
- end