rails2_libmemcached_store 0.3.2 → 0.4.0

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