Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 2 commits
  • 5 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 26, 2011
Florian Schwab Updated Gemfile 47780cb
Commits on Nov 27, 2011
Florian Schwab Switch to rails caching 7bf91ca
9 Gemfile
View
@@ -1,6 +1,6 @@
source 'http://rubygems.org'
-gem 'rails', '3.1.1'
+gem 'rails', '3.1.3'
gem 'sqlite3'
gem 'mime-types'
@@ -15,14 +15,19 @@ group :assets do
gem 'uglifier', '>= 1.0.3'
end
-group :test do
+group :production, :test do
gem 'execjs'
gem 'therubyracer'
+end
+
+group :test do
+ gem 'minitest'
# Pretty printed test output
gem 'turn', :require => false
end
+
# Plugins
gem 'raki_git_provider', :path => 'vendor/plugins/git_provider'
gem 'raki_openid_authenticator', :path => 'vendor/plugins/openid_authenticator'
56 Gemfile.lock
View
@@ -13,33 +13,33 @@ PATH
GEM
remote: http://rubygems.org/
specs:
- actionmailer (3.1.1)
- actionpack (= 3.1.1)
+ actionmailer (3.1.3)
+ actionpack (= 3.1.3)
mail (~> 2.3.0)
- actionpack (3.1.1)
- activemodel (= 3.1.1)
- activesupport (= 3.1.1)
+ actionpack (3.1.3)
+ activemodel (= 3.1.3)
+ activesupport (= 3.1.3)
builder (~> 3.0.0)
erubis (~> 2.7.0)
i18n (~> 0.6)
- rack (~> 1.3.2)
+ rack (~> 1.3.5)
rack-cache (~> 1.1)
rack-mount (~> 0.8.2)
rack-test (~> 0.6.1)
- sprockets (~> 2.0.2)
- activemodel (3.1.1)
- activesupport (= 3.1.1)
+ sprockets (~> 2.0.3)
+ activemodel (3.1.3)
+ activesupport (= 3.1.3)
builder (~> 3.0.0)
i18n (~> 0.6)
- activerecord (3.1.1)
- activemodel (= 3.1.1)
- activesupport (= 3.1.1)
+ activerecord (3.1.3)
+ activemodel (= 3.1.3)
+ activesupport (= 3.1.3)
arel (~> 2.2.1)
tzinfo (~> 0.3.29)
- activeresource (3.1.1)
- activemodel (= 3.1.1)
- activesupport (= 3.1.1)
- activesupport (3.1.1)
+ activeresource (3.1.3)
+ activemodel (= 3.1.3)
+ activesupport (= 3.1.3)
+ activesupport (3.1.3)
multi_json (~> 1.0)
ansi (1.4.1)
arel (2.2.1)
@@ -63,6 +63,7 @@ GEM
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.17.2)
+ minitest (2.8.1)
multi_json (1.0.3)
polyglot (0.3.3)
rack (1.3.5)
@@ -74,17 +75,17 @@ GEM
rack
rack-test (0.6.1)
rack (>= 1.0)
- rails (3.1.1)
- actionmailer (= 3.1.1)
- actionpack (= 3.1.1)
- activerecord (= 3.1.1)
- activeresource (= 3.1.1)
- activesupport (= 3.1.1)
+ rails (3.1.3)
+ actionmailer (= 3.1.3)
+ actionpack (= 3.1.3)
+ activerecord (= 3.1.3)
+ activeresource (= 3.1.3)
+ activesupport (= 3.1.3)
bundler (~> 1.0)
- railties (= 3.1.1)
- railties (3.1.1)
- actionpack (= 3.1.1)
- activesupport (= 3.1.1)
+ railties (= 3.1.3)
+ railties (3.1.3)
+ actionpack (= 3.1.3)
+ activesupport (= 3.1.3)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
@@ -126,7 +127,8 @@ DEPENDENCIES
coffee-rails (~> 3.1.1)
execjs
mime-types
- rails (= 3.1.1)
+ minitest
+ rails (= 3.1.3)
raki_git_provider!
raki_openid_authenticator!
sass-rails (~> 3.1.4)
213 lib/cacheable.rb
View
@@ -1,5 +1,5 @@
# Raki - extensible rails-based wiki
-# Copyright (C) 2010 Florian Schwab & Martin Sigloch
+# Copyright (C) 2011 Florian Schwab & Martin Sigloch
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -19,48 +19,26 @@
module Cacheable
- @cache = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new{|h,k| h[k] = {}}}}
- @queue = ::Queue.new
+ class CacheError < StandardError; end
+ class UncacheableArgumentsError < CacheError; end
- # Refresh enqueued values.
- Thread.new do
- while true do
- op = nil
- begin
- op = @queue.pop
- $stdout.flush
- cache = @cache[op[:object]][op[:method]][op[:args]]
- cache[:data] = op[:object].send("__uncached_#{op[:method].to_s}", *op[:args])
- cache[:time] = Time.new
- cache[:enqueued] = false
- op = nil
- rescue => e
- @queue << op unless op.nil?
- end
- end
+
+ def self.caching_enabled?
+ Rails.application.config.cache_classes && Rails.cache
end
- # Remove unused values from cache and reduce cache size.
- Thread.new do
- while true do
- begin
- @cache.each do |clazz, methods|
- methods.each do |method, method_args|
- method_args.delete_if do |args, params|
- params[:last_access] < (Time.new - params[:ttl]*10)
- end
- end
- methods.delete_if do |method, method_args|
- method_args.length == 0
- end
- end
- @cache.delete_if do |clazz, methods|
- methods.length == 0
- end
- rescue => e
+ def self.cache_key obj, method, args
+ args_keys = args.collect do |a|
+ if a.respond_to? :cache_key
+ a.cache_key
+ elsif a.respond_to? :to_param
+ a.to_param
+ else
+ raise UncacheableArgumentsError
end
- sleep 60
end
+
+ {:object_class => obj.class.to_s.to_sym, :object_id => obj.object_id, :method => method.to_sym, :args => args_keys}
end
def self.included(base)
@@ -73,40 +51,62 @@ module ClassMethods
#
# Available options:
# * :ttl => TTL for cached value in seconds.
- # * :force => Don't return cached value if value has exceed TTL.
#
# def foobar(p1,p2); end
- # cache :foobar, :ttl => 10, :force => true
+ # cache :foobar, :ttl => 10
#
- def cache(name, options={})
- return if ::Rails.env == 'development'
+ def cache method, options={}
+ return unless Cacheable.caching_enabled?
- name = name.to_s
- name_uncached = "__uncached_#{name.to_s}"
+ method = method.to_s
+ method_uncached = "__uncached_#{method.to_s}"
ttl = options.key?(:ttl) ? options[:ttl].to_i : 10
- force = options.key?(:force) ? options[:ttl] : false
- class_eval("alias :#{name_uncached} :#{name}")
- class_eval("private :#{name_uncached}")
+ class_eval("alias :#{method_uncached} :#{method}")
+ class_eval("private :#{method_uncached}")
class_eval do
- define_method name do |*args|
- cache = Cacheable.cache[self][name.to_sym]
- unless cache.key?(args)
- cache[args] = {:data => send(name_uncached.to_sym, *args), :time => Time.new, :ttl => ttl, :force => force}
- else
- if cache[args][:time] < (Time.new - ttl)
- if force
- cache[args] = {:data => send(name_uncached.to_sym, *args), :time => Time.new, :ttl => ttl, :force => force}
- elsif !cache[args][:enqueued]
- Cacheable.queue << {:object => self, :method => name.to_sym, :args => args}
- cache[args][:enqueued] = true
+ define_method method do |*args|
+ begin
+ cache_key = Cacheable.cache_key self, method, args
+
+ return_value = Rails.cache.fetch cache_key, :expires_in => ttl.seconds do
+ cache_value = nil
+ begin
+ v = send method_uncached.to_sym, *args
+ cache_value = {:type => :value, :data => v}
+ rescue => e
+ cache_value = {:type => :error, :data => e}
end
+
+ cache_value
end
+
+ @cache_keys ||= []
+ @cache_keys << cache_key unless @cache_keys.include? cache_key
+
+ if @cache_cleanup_time && @cache_cleanup_time <= Time.now
+ @cache_keys.delete_if do |ck|
+ !Rails.cache.exist? ck
+ end
+
+ @cache_cleanup_time = Time.now + 20
+ end
+
+ if return_value[:type] == :error
+ raise return_value[:data]
+ else
+ return return_value[:data]
+ end
+ rescue => e
+ p e.to_s
+ print e.backtrace.join("\n")
+ raise e
+ Rails.logger "Caching for #{self.class.to_s}(#{self.object_id})##{method.to_s} with args #{args.inspect} not possible: #{e.to_s}"
+
+ raise CacheError
end
- cache[args][:last_access] = Time.new
- cache[args][:data]
end
end
@@ -115,86 +115,37 @@ def cache(name, options={})
end
- def self.cache
- @cache
- end
-
- def self.queue
- @queue
- end
-
- # Mark all values as expired.
- def self.expire
- return if Rails.env == 'development'
-
- time = Time.at(0)
- @cache.values.each do |clazz|
- clazz.values.each do |cached|
- cached.values.each do |params|
- params[:time] = time
- end
- end
- end
- end
-
- # Remove all values from cache.
- def self.flush
- return if Rails.env == 'development'
-
- @cache.values.each do |clazz|
- clazz.values.each do |cached|
- cached.clear
- end
- clazz.clear
- end
- end
-
- # Mark value(s) as expired.
- def expire(name=nil, *args)
- return if Rails.env == 'development'
+ # Removes value(s) from the cache.
+ def cache_delete method=nil, *args
+ return nil unless Cacheable.caching_enabled?
- name = name.to_sym
- cache = Cacheable.cache[self]
- time = Time.at(0)
- if name.nil?
- cache.values.each do |method_args|
- method_args.values.each do |params|
- params[:time] = time
+ if method && args.count > 0
+ cache_key = Cacheable.cache_key self, method, args
+ Rails.cache.delete cache_key
+ elsif method
+ @cache_keys.delete_if do |ck|
+ if ck[:method] == method.to_sym
+ Rails.cache.delete ck
+ true
+ else
+ false
end
end
- elsif args.nil? || args.empty?
- cache[name].values.each do |params|
- params[:time] = time
- end
else
- cache[name][args][:time] = time
- end
- end
-
- # Removes value(s) from the cache.
- def flush(name=nil, *args)
- return if Rails.env == 'development'
-
- name = name.to_sym
- cache = Cacheable.cache[self]
- if name.nil?
- cache.each do |method, params|
- params.clear
+ @cache_keys.delete_if do |ck|
+ Rails.cache.delete ck
+ true
end
- elsif args.nil? || args.empty?
- cache[name].clear
- else
- cache[name].delete(args)
end
end
# Check if value is cached.
- def cached?(name, *args)
- return false if Rails.env == 'development'
- cache = Cacheable.cache[self][name.to_sym]
- return false unless cache.key?(args)
- params = cache[args]
- !(params[:force] && (params[:time] < (Time.new - params[:ttl])))
+ def cached? method, *args
+ return nil unless Cacheable.caching_enabled?
+
+ cache_key = Cacheable.cache_key self, method, args
+
+ Rails.cache.exist? cache_key
end
end
86 test/unit/lib/cacheable_test.rb
View
@@ -21,24 +21,19 @@ class CacheableTest < Test::Unit::TestCase
class TestCache
include Cacheable
def initialize
- @m1 = @m2 = -1
- @m3 = Hash.new{|h,k| h[k] = -1}
+ @m1 = -1
+ @m2 = Hash.new{|h,k| h[k] = -1}
end
def m1
@m1 += 1
@m1
end
cache :m1, :ttl => 3
- def m2
- @m2 += 1
- @m2
+ def m2(p1)
+ @m2[p1] += 1
+ @m2[p1]
end
- cache :m2, :ttl => 3, :force => true
- def m3(p1)
- @m3[p1] += 1
- @m3[p1]
- end
- cache :m3, :ttl => 3
+ cache :m2, :ttl => 3
end
# Test if method is cached.
@@ -46,20 +41,13 @@ def test_refresh
cached = TestCache.new
5.times do |i|
assert_equal i, cached.m1
- assert_equal i, cached.m2
- assert_equal i, cached.m3(1)
- assert_equal i, cached.m3(2)
+ assert_equal i, cached.m2(1)
+ assert_equal i, cached.m2(2)
sleep 1
assert_equal i, cached.m1
- assert_equal i, cached.m2
- assert_equal i, cached.m3(1)
- assert_equal i, cached.m3(2)
- sleep 2
- assert_equal i, cached.m1
- assert_equal (i+1), cached.m2
- assert_equal i, cached.m3(1)
- assert_equal i, cached.m3(2)
- sleep 1
+ assert_equal i, cached.m2(1)
+ assert_equal i, cached.m2(2)
+ sleep 2.1
end
end
@@ -71,51 +59,35 @@ def test_cached
assert !cached.cached?(:m1)
cached.m1
assert cached.cached?(:m1)
- sleep 4
+ sleep 2
assert cached.cached?(:m1)
+ sleep 4
+ assert !cached.cached?(:m1)
# force = true
- assert !cached.cached?(:m2)
- cached.m2
+ assert !cached.cached?(:m2, 'test')
+ assert !cached.cached?(:m2, 1)
+ cached.m2 1
sleep 1
- assert cached.cached?(:m2)
+ assert !cached.cached?(:m2, 'test')
+ assert cached.cached?(:m2, 1)
sleep 3
- assert !cached.cached?(:m2)
+ assert !cached.cached?(:m2, 1)
end
- # Test if cache can be flushed.
- def test_flush
+ # Test if cache can be deleted.
+ def test_delete
cached = TestCache.new
cached.m1
- assert cached.cached?(:m1)
- cached.flush(:m1)
- assert !cached.cached?(:m1)
-
- cached.m3('test')
- assert cached.cached?(:m3, 'test')
- cached.flush(:m3, 'test')
- assert !cached.cached?(:m3, 'test')
- end
-
- # Test if cache can be expired.
- def test_expire
- cached = TestCache.new
-
- cached.m1
- assert cached.cached?(:m1)
- cached.expire(:m1)
- assert cached.cached?(:m1)
-
- cached.m2
- assert cached.cached?(:m2)
- cached.expire(:m2)
- assert !cached.cached?(:m2)
+ assert cached.cached?(:m1),"1"
+ cached.cache_delete(:m1)
+ assert !cached.cached?(:m1),"2"
- cached.m3('test')
- assert cached.cached?(:m3, 'test')
- cached.expire(:m3, 'test')
- assert cached.cached?(:m3, 'test')
+ cached.m2('test')
+ assert cached.cached?(:m2, 'test'),"3"
+ cached.cache_delete(:m2, 'test')
+ assert !cached.cached?(:m2, 'test'),"4"
end
end
38 vendor/plugins/git_provider/lib/git_provider.rb
View
@@ -190,10 +190,10 @@ def save(obj, contents, message, user)
@repo.commit(message, format_user(user), obj)
git_push
- flush(:exists?, obj, nil)
- flush(:page_contents, obj, nil)
- flush(:revisions)
- flush(:namespaces)
+ cache_delete :exists?, obj, nil
+ cache_delete :page_contents, obj, nil
+ cache_delete :revisions
+ cache_delete :namespaces
end
def rename(old_obj, new_obj, message, user)
@@ -212,11 +212,11 @@ def rename(old_obj, new_obj, message, user)
@repo.commit(message, format_user(user), pathspecs)
git_push
- flush(:exists?)
- flush(:page_contents)
- flush(:revisions)
- flush(:changes)
- flush(:namespaces)
+ cache_delete :exists?
+ cache_delete :page_contents
+ cache_delete :revisions
+ cache_delete :changes
+ cache_delete :namespaces
end
def delete(obj, message, user)
@@ -234,11 +234,11 @@ def delete(obj, message, user)
@repo.commit(message, format_user(user), pathspecs)
git_push
- flush(:exists?, obj, nil)
- flush(:page_contents)
- flush(:revisions)
- flush(:changes)
- flush(:namespaces)
+ cache_delete :exists?, obj, nil
+ cache_delete :page_contents
+ cache_delete :revisions
+ cache_delete :changes
+ cache_delete :namespaces
end
def revisions(obj, options)
@@ -383,11 +383,11 @@ def git_pull
changed_files = @repo.pull('origin', @branch)
changed_files.each do |file|
logger.debug "Flushing cached data for '#{file}'"
- flush :exists?
- flush :page_contents
- flush :revisions
- flush :changes
- flush :namespaces
+ cache_delete :exists?
+ cache_delete :page_contents
+ cache_delete :revisions
+ cache_delete :changes
+ cache_delete :namespaces
end
logger.debug "Pulled from '#{@repo.remotes['origin'][:url]}'"

No commit comments for this range

Something went wrong with that request. Please try again.