rack-cache 0.5 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack-cache might be problematic. Click here for more details.

data/CHANGES CHANGED
@@ -1,3 +1,18 @@
1
+ ## 0.6.0 / Unreleased
2
+
3
+ * Added support for memcached clusters and other advanced
4
+ configuration provided by the memcache-client and memcached
5
+ libraries. The "metastore" and "entitystore" options can now be
6
+ set to a MemCache object or Memcached object:
7
+
8
+ memcache = MemCache.new(['127.1.1.1', '127.1.1.2'], :namespace => "/foo")
9
+ use Rack::Cache,
10
+ :metastore => memcache,
11
+ :entitystore => memcache
12
+
13
+ * Fix "memcached://" metastore URL handling. The "memcached" variation
14
+ blew up, the "memcache" version was fine.
15
+
1
16
  ## 0.5.0 / May 2009
2
17
 
3
18
  * Added meta and entity store implementations based on the
data/Rakefile CHANGED
@@ -110,13 +110,21 @@ file package('.tar.gz') => %w[dist/] + $spec.files do |f|
110
110
  end
111
111
 
112
112
  desc 'Upload gem and tar.gz distributables to rubyforge'
113
- task :release => [package('.gem'), package('.tar.gz')] do |t|
113
+ task 'release:rubyforge' => [package('.gem'), package('.tar.gz')] do |t|
114
114
  sh <<-SH
115
115
  rubyforge add_release wink rack-cache #{$spec.version} #{package('.gem')} &&
116
116
  rubyforge add_file wink rack-cache #{$spec.version} #{package('.tar.gz')}
117
117
  SH
118
118
  end
119
119
 
120
+ desc 'Upload gem to gemcutter.org'
121
+ task 'release:gemcutter' => [package('.gem')] do |t|
122
+ sh "gem push #{package('.gem')}"
123
+ end
124
+
125
+ desc 'Upload gem to gemcutter and rubyforge'
126
+ task 'release' => ['release:gemcutter', 'release:rubyforge']
127
+
120
128
  # GEMSPEC ===================================================================
121
129
 
122
130
  file 'rack-cache.gemspec' => FileList['{lib,test}/**','Rakefile'] do |f|
@@ -62,10 +62,9 @@ deployments so explicit configuration is advised.
62
62
  The default metastore and entitystore values can be specified when the
63
63
  __Rack::Cache__ object is added to the Rack middleware pipeline as follows:
64
64
 
65
- use Rack::Cache do
66
- set :metastore, 'file:/var/cache/rack/meta'
67
- set :entitystore, 'file:/var/cache/rack/body'
68
- end
65
+ use Rack::Cache,
66
+ :metastore => 'file:/var/cache/rack/meta',
67
+ :entitystore => 'file:/var/cache/rack/body'
69
68
 
70
69
  Alternatively, the `rack-cache.metastore` and `rack-cache.entitystore`
71
70
  variables may be set in the Rack environment by an upstream component.
@@ -82,8 +81,9 @@ use a specific storage implementation as well as pros and cons of each.
82
81
 
83
82
  Uses local process memory to store cached entries.
84
83
 
85
- set :metastore, 'heap:/'
86
- set :entitystore, 'heap:/'
84
+ use Rack::Cache,
85
+ :metastore => 'heap:/',
86
+ :entitystore => 'heap:/'
87
87
 
88
88
  The heap storage backend is simple, fast, and mostly useless. All cache
89
89
  information is stored in each backend application's local process memory (using
@@ -102,8 +102,9 @@ is small and well understood.
102
102
 
103
103
  Stores cached entries on the filesystem.
104
104
 
105
- set :metastore, 'file:/var/cache/rack/meta'
106
- set :entitystore, 'file:/var/cache/rack/body'
105
+ use Rack::Cache,
106
+ :metastore => 'file:/var/cache/rack/meta',
107
+ :entitystore => 'file:/var/cache/rack/body'
107
108
 
108
109
  The URI may specify an absolute, relative, or home-rooted path:
109
110
 
@@ -132,18 +133,19 @@ collision.
132
133
  Stores cached entries in a remote [memcached](http://www.danga.com/memcached/)
133
134
  instance.
134
135
 
135
- set :metastore, 'memcached://localhost:11211/meta'
136
- set :entitystore, 'memcached://localhost:11211/body'
136
+ use Rack::Cache,
137
+ :metastore => 'memcached://localhost:11211/meta',
138
+ :entitystore => 'memcached://localhost:11211/body'
137
139
 
138
140
  The URI must specify the host and port of a remote memcached daemon. The path
139
141
  portion is an optional (but recommended) namespace that is prepended to each
140
142
  cache key.
141
143
 
142
- The memcached storage backend requires [Evan Weaver's memcached client library][e].
143
- This is a [fast][f] client implementation built on the SWIG/[libmemcached][l] C
144
- library. The library may be installed from Gem as follows:
144
+ The memcached storage backend requires either the `memcache-client` or
145
+ `memcached` libraries. By default, the `memcache-client` library is used;
146
+ require the `memcached` library explicitly to use it instead.
145
147
 
146
- sudo gem install memcached --no-rdoc --no-ri
148
+ gem install memcache-client
147
149
 
148
150
  Memcached storage is reasonably fast and allows multiple backends to share a
149
151
  single cache. It is also the only storage implementation that allows the cache
@@ -133,8 +133,12 @@ module Rack::Cache
133
133
  # Invalidate POST, PUT, DELETE and all methods not understood by this cache
134
134
  # See RFC2616 13.10
135
135
  def invalidate
136
- record :invalidate
137
136
  metastore.invalidate(@request, entitystore)
137
+ rescue Exception => e
138
+ log_error(e)
139
+ pass
140
+ else
141
+ record :invalidate
138
142
  pass
139
143
  end
140
144
 
@@ -147,18 +151,26 @@ module Rack::Cache
147
151
  if @request.no_cache? && allow_reload?
148
152
  record :reload
149
153
  fetch
150
- elsif entry = metastore.lookup(@request, entitystore)
151
- if fresh_enough?(entry)
152
- record :fresh
153
- entry.headers['Age'] = entry.age.to_s
154
- entry
154
+ else
155
+ begin
156
+ entry = metastore.lookup(@request, entitystore)
157
+ rescue Exception => e
158
+ log_error(e)
159
+ return pass
160
+ end
161
+ if entry
162
+ if fresh_enough?(entry)
163
+ record :fresh
164
+ entry.headers['Age'] = entry.age.to_s
165
+ entry
166
+ else
167
+ record :stale
168
+ validate(entry)
169
+ end
155
170
  else
156
- record :stale
157
- validate(entry)
171
+ record :miss
172
+ fetch
158
173
  end
159
- else
160
- record :miss
161
- fetch
162
174
  end
163
175
  end
164
176
 
@@ -225,9 +237,17 @@ module Rack::Cache
225
237
 
226
238
  # Write the response to the cache.
227
239
  def store(response)
228
- record :store
229
240
  metastore.store(@request, response, entitystore)
230
241
  response.headers['Age'] = response.age.to_s
242
+ rescue Exception => e
243
+ log_error(e)
244
+ nil
245
+ else
246
+ record :store
247
+ end
248
+
249
+ def log_error(exception)
250
+ @env['rack.errors'].write("cache error: #{exception.message}\n#{exception.backtrace.join("\n")}\n")
231
251
  end
232
252
  end
233
253
  end
@@ -182,19 +182,25 @@ module Rack::Cache
182
182
  end
183
183
 
184
184
  def self.resolve(uri)
185
- server = "#{uri.host}:#{uri.port || '11211'}"
186
- options = parse_query(uri.query)
187
- options.keys.each do |key|
188
- value =
189
- case value = options.delete(key)
190
- when 'true' ; true
191
- when 'false' ; false
192
- else value.to_sym
193
- end
194
- options[k.to_sym] = value
185
+ if uri.respond_to?(:scheme)
186
+ server = "#{uri.host}:#{uri.port || '11211'}"
187
+ options = parse_query(uri.query)
188
+ options.keys.each do |key|
189
+ value =
190
+ case value = options.delete(key)
191
+ when 'true' ; true
192
+ when 'false' ; false
193
+ else value.to_sym
194
+ end
195
+ options[k.to_sym] = value
196
+ end
197
+ options[:namespace] = uri.path.sub(/^\//, '')
198
+ new server, options
199
+ else
200
+ # if the object provided is not a URI, pass it straight through
201
+ # to the underlying implementation.
202
+ new uri
195
203
  end
196
- options[:namespace] = uri.path.sub(/^\//, '')
197
- new server, options
198
204
  end
199
205
  end
200
206
 
@@ -274,19 +274,27 @@ module Rack::Cache
274
274
  # Query parameter names and values are documented with the memcached
275
275
  # library: http://tinyurl.com/4upqnd
276
276
  def self.resolve(uri)
277
- server = "#{uri.host}:#{uri.port || '11211'}"
278
- options = parse_query(uri.query)
279
- options.keys.each do |key|
280
- value =
281
- case value = options.delete(key)
282
- when 'true' ; true
283
- when 'false' ; false
284
- else value.to_sym
285
- end
286
- options[k.to_sym] = value
277
+ if uri.respond_to?(:scheme)
278
+ server = "#{uri.host}:#{uri.port || '11211'}"
279
+ options = parse_query(uri.query)
280
+ options.keys.each do |key|
281
+ value =
282
+ case value = options.delete(key)
283
+ when 'true' ; true
284
+ when 'false' ; false
285
+ else value.to_sym
286
+ end
287
+ options[k.to_sym] = value
288
+ end
289
+
290
+ options[:namespace] = uri.path.to_s.sub(/^\//, '')
291
+
292
+ new server, options
293
+ else
294
+ # if the object provided is not a URI, pass it straight through
295
+ # to the underlying implementation.
296
+ new uri
287
297
  end
288
- options[:namespace] = uri.path.sub(/^\//, '')
289
- new server, options
290
298
  end
291
299
  end
292
300
 
@@ -359,7 +367,7 @@ module Rack::Cache
359
367
  else
360
368
  MemCache
361
369
  end
362
- MEMCACHED = MemCache
370
+ MEMCACHED = MEMCACHE
363
371
 
364
372
  class GAEStore < MetaStore
365
373
  attr_reader :cache
@@ -30,12 +30,25 @@ module Rack::Cache
30
30
 
31
31
  private
32
32
  def create_store(type, uri)
33
- uri = URI.parse(uri) unless uri.respond_to?(:scheme)
34
- if type.const_defined?(uri.scheme.upcase)
35
- klass = type.const_get(uri.scheme.upcase)
36
- klass.resolve(uri)
33
+ if uri.respond_to?(:scheme) || uri.respond_to?(:to_str)
34
+ uri = URI.parse(uri) unless uri.respond_to?(:scheme)
35
+ if type.const_defined?(uri.scheme.upcase)
36
+ klass = type.const_get(uri.scheme.upcase)
37
+ klass.resolve(uri)
38
+ else
39
+ fail "Unknown storage provider: #{uri.to_s}"
40
+ end
37
41
  else
38
- fail "Unknown storage provider: #{uri.to_s}"
42
+ # hack in support for passing a MemCache or Memcached object
43
+ # as the storage URI.
44
+ case
45
+ when defined?(::MemCache) && uri.kind_of?(::MemCache)
46
+ type.const_get(:MemCache).resolve(uri)
47
+ when defined?(::Memcached) && uri.respond_to?(:stats)
48
+ type.const_get(:MemCached).resolve(uri)
49
+ else
50
+ fail "Unknown storage provider: #{uri.to_s}"
51
+ end
39
52
  end
40
53
  end
41
54
 
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
3
3
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
4
 
5
5
  s.name = 'rack-cache'
6
- s.version = '0.5'
7
- s.date = '2009-05-25'
6
+ s.version = '0.5.2'
7
+ s.date = '2009-09-25'
8
8
 
9
9
  s.description = "HTTP Caching for Rack"
10
10
  s.summary = "HTTP Caching for Rack"
@@ -746,4 +746,29 @@ describe 'Rack::Cache::Context' do
746
746
  response['X-Response-Count'].should.equal '3'
747
747
  end
748
748
  end
749
+
750
+ it 'passes if there was a metastore exception' do
751
+ respond_with 200, 'Cache-Control' => 'max-age=10000' do |req,res|
752
+ res.body = ['Hello World']
753
+ end
754
+
755
+ get '/'
756
+ response.should.be.ok
757
+ response.body.should.equal 'Hello World'
758
+ cache.trace.should.include :store
759
+
760
+ get '/' do |cache|
761
+ cache.meta_def(:metastore) { raise Timeout::Error }
762
+ end
763
+ response.should.be.ok
764
+ response.body.should.equal 'Hello World'
765
+ cache.trace.should.include :pass
766
+
767
+ post '/' do |cache|
768
+ cache.meta_def(:metastore) { raise Timeout::Error }
769
+ end
770
+ response.should.be.ok
771
+ response.body.should.equal 'Hello World'
772
+ cache.trace.should.include :pass
773
+ end
749
774
  end
@@ -272,7 +272,7 @@ describe 'Rack::Cache::MetaStore' do
272
272
  end
273
273
  end
274
274
  end
275
-
275
+
276
276
  need_java 'entity store testing' do
277
277
  module Rack::Cache::AppEngine
278
278
  module MC
@@ -282,12 +282,12 @@ describe 'Rack::Cache::MetaStore' do
282
282
  def get(key); self[key]; end;
283
283
  def put(key, value, ttl = nil)
284
284
  self[key] = value
285
- end
285
+ end
286
286
 
287
287
  end
288
288
  end
289
289
  end
290
-
290
+
291
291
  describe 'GAEStore' do
292
292
  it_should_behave_like 'A Rack::Cache::MetaStore Implementation'
293
293
  before :each do
@@ -296,7 +296,7 @@ describe 'Rack::Cache::MetaStore' do
296
296
  @entity_store = Rack::Cache::EntityStore::Heap.new
297
297
  end
298
298
  end
299
-
299
+
300
300
  end
301
301
 
302
302
  end
@@ -74,5 +74,4 @@ describe 'Rack::Cache::Options' do
74
74
  @options.should.respond_to :verbose?
75
75
  @options.verbose.should.not.be.nil
76
76
  end
77
-
78
77
  end
@@ -13,7 +13,7 @@ end
13
13
 
14
14
  # Set the MEMCACHED environment variable as follows to enable testing
15
15
  # of the MemCached meta and entity stores.
16
- ENV['MEMCACHED'] ||= 'localhost:11215'
16
+ ENV['MEMCACHED'] ||= 'localhost:11211'
17
17
  $memcached = nil
18
18
  $memcache = nil
19
19
 
@@ -70,7 +70,6 @@ def need_memcache(forwhat)
70
70
  end
71
71
 
72
72
  def need_java(forwhat)
73
-
74
73
  if RUBY_PLATFORM =~ /java/
75
74
  yield
76
75
  else
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack-cache
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.5"
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Tomayko
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-25 00:00:00 -07:00
12
+ date: 2009-09-25 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -75,6 +75,8 @@ files:
75
75
  - test/storage_test.rb
76
76
  has_rdoc: true
77
77
  homepage: http://tomayko.com/src/rack-cache/
78
+ licenses: []
79
+
78
80
  post_install_message:
79
81
  rdoc_options:
80
82
  - --line-numbers
@@ -100,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
102
  requirements: []
101
103
 
102
104
  rubyforge_project: wink
103
- rubygems_version: 1.3.1
105
+ rubygems_version: 1.3.4
104
106
  signing_key:
105
107
  specification_version: 2
106
108
  summary: HTTP Caching for Rack