cacheAR 0.9.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.
- data/cacheAR-CHANGES +0 -0
- data/lib/cachear.rb +218 -0
- metadata +38 -0
data/cacheAR-CHANGES
ADDED
File without changes
|
data/lib/cachear.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
########################################
|
2
|
+
#
|
3
|
+
# Author:: Dmitry V. Sabanin <dmitry@sabanin.ru>
|
4
|
+
# Copyright:: Copyright (c) 2005 MuraveyLabs, Ltd
|
5
|
+
# URL:: http://muravey.net/opensource/
|
6
|
+
# Revision:: $Date: 2004/11/17 07:37:13 $ $Revision: 1.7 $
|
7
|
+
# License:: MIT
|
8
|
+
#
|
9
|
+
########################################
|
10
|
+
|
11
|
+
require_gem 'ruby-cache'
|
12
|
+
|
13
|
+
# ActiveRecord::MemoryCache.logger = ActiveRecord::Base.logger
|
14
|
+
# ActiveRecord::Base.cacher = ActiveRecord::MemoryCache.instance
|
15
|
+
module ActiveRecord::Caching
|
16
|
+
|
17
|
+
def self.append_features(base)
|
18
|
+
super
|
19
|
+
base.class_eval do
|
20
|
+
cattr_accessor :cacher
|
21
|
+
class << self
|
22
|
+
alias_method :ar_find_by_sql, :find_by_sql
|
23
|
+
alias_method :ar_count_by_sql, :count_by_sql
|
24
|
+
undef :find_by_sql, :count_by_sql
|
25
|
+
|
26
|
+
def find_by_sql(sql)
|
27
|
+
cacher.cache_query( self, sanitize_sql(sql) ) do |s|
|
28
|
+
ar_find_by_sql(s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def count_by_sql(sql)
|
33
|
+
cacher.cache_query( self, sanitize_sql(sql) ) do |s|
|
34
|
+
ar_count_by_sql(s)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def ===(inst)
|
39
|
+
i = 0
|
40
|
+
while( (kl = inst.class.ancestors[i]) != Object )
|
41
|
+
return true if self.to_s == kl.to_s
|
42
|
+
i += 1
|
43
|
+
end
|
44
|
+
super
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def kind_of?(klass)
|
54
|
+
return true if klass === self
|
55
|
+
super
|
56
|
+
end
|
57
|
+
|
58
|
+
def is_a?(klass)
|
59
|
+
kind_of?(klass)
|
60
|
+
end
|
61
|
+
|
62
|
+
def after_save
|
63
|
+
self.class.cacher.expire(self.class)
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
ActiveRecord::Base.class_eval do
|
69
|
+
include ActiveRecord::Caching
|
70
|
+
end
|
71
|
+
|
72
|
+
class ActiveRecord::CacheSQLQuery
|
73
|
+
|
74
|
+
RE_TABLES = /FROM(.+?)(?:(WHERE)|(LIMIT)|($))/i
|
75
|
+
|
76
|
+
attr_reader :sql
|
77
|
+
|
78
|
+
@@queries = Hash.new { |hsh, query| hsh[query] = self.new(query) }
|
79
|
+
|
80
|
+
def self.create(str)
|
81
|
+
@@queries[str]
|
82
|
+
end
|
83
|
+
|
84
|
+
def initialize(str)
|
85
|
+
@sql = str.gsub(/[\r\n]/,' ')
|
86
|
+
end
|
87
|
+
|
88
|
+
def tables
|
89
|
+
return @tables if @tables
|
90
|
+
raw = @sql.scan(RE_TABLES).flatten[0].strip.split(/,/)
|
91
|
+
@tables = raw.map do |r|
|
92
|
+
r.strip.gsub(/\s+.+$/,'').strip
|
93
|
+
end.uniq
|
94
|
+
end
|
95
|
+
|
96
|
+
def to_s
|
97
|
+
@sql
|
98
|
+
end
|
99
|
+
|
100
|
+
def to_str
|
101
|
+
to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
def inspect
|
105
|
+
"<sql: #{to_s.inspect}>"
|
106
|
+
end
|
107
|
+
|
108
|
+
def == (oth)
|
109
|
+
@sql == oth.sql
|
110
|
+
end
|
111
|
+
|
112
|
+
def eql?(oth)
|
113
|
+
self == oth
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
class ActiveRecord::CacheInstance
|
119
|
+
|
120
|
+
def initialize(inst)
|
121
|
+
begin
|
122
|
+
@inst = inst.dup
|
123
|
+
rescue TypeError
|
124
|
+
@inst = inst
|
125
|
+
end
|
126
|
+
@expired = false
|
127
|
+
end
|
128
|
+
|
129
|
+
def instance
|
130
|
+
begin
|
131
|
+
@inst.dup
|
132
|
+
rescue
|
133
|
+
@inst
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def expire!
|
138
|
+
@inst = nil
|
139
|
+
@expired = true
|
140
|
+
end
|
141
|
+
|
142
|
+
def expired?
|
143
|
+
@expired
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
class ActiveRecord::MemoryCache
|
149
|
+
|
150
|
+
include Singleton
|
151
|
+
|
152
|
+
cattr_accessor :max_size
|
153
|
+
|
154
|
+
# Maximal cache size for one model is 10MB by default
|
155
|
+
@@max_size = 10 * 1024 * 1024
|
156
|
+
|
157
|
+
cattr_accessor :log
|
158
|
+
@@log = false
|
159
|
+
|
160
|
+
cattr_accessor :logger
|
161
|
+
|
162
|
+
def initialize
|
163
|
+
@tables = Hash.new do |hsh, table|
|
164
|
+
hsh[table] = Cache.new
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def cache_query(klass, sql, &blk)
|
169
|
+
sql = ActiveRecord::CacheSQLQuery.create(sql)
|
170
|
+
tbl = klass.table_name()
|
171
|
+
if @tables[tbl].cached?(sql) and !@tables[tbl][sql].expired?
|
172
|
+
log_hit(sql)
|
173
|
+
inst = @tables[tbl][sql].instance
|
174
|
+
inst
|
175
|
+
else
|
176
|
+
log_miss(sql)
|
177
|
+
inst = store_result( sql, blk.call(sql.to_s) ).instance
|
178
|
+
inst
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def expire(klass)
|
183
|
+
if(cache = @tables[ klass.table_name() ])
|
184
|
+
cache.each do |key, inst|
|
185
|
+
inst.expire!
|
186
|
+
cache.delete(key)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
def store_result(sql, obj)
|
194
|
+
inst = ActiveRecord::CacheInstance.new( obj )
|
195
|
+
sql.tables.each do |tbl|
|
196
|
+
@tables[tbl].store(sql, inst)
|
197
|
+
end
|
198
|
+
inst
|
199
|
+
end
|
200
|
+
|
201
|
+
def log_hit(sql)
|
202
|
+
do_log("Cache hit for tables #{sql.tables.inspect}: #{sql.inspect}")
|
203
|
+
end
|
204
|
+
|
205
|
+
def log_miss(sql)
|
206
|
+
do_log("Cache miss for tables #{sql.tables.inspect}: #{sql.inspect}")
|
207
|
+
end
|
208
|
+
|
209
|
+
def log_stats
|
210
|
+
size, num, hits, misses = @cache[tbl].statistics
|
211
|
+
do_log("Cache stat for #{tbl}: size=#{size}B; num=#{num}; hits=#{hits}; misses=#{misses}")
|
212
|
+
end
|
213
|
+
|
214
|
+
def do_log(str)
|
215
|
+
logger.info(str) if log
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
metadata
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.6
|
3
|
+
specification_version: 1
|
4
|
+
name: cacheAR
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.9.0
|
7
|
+
date: 2005-04-09
|
8
|
+
summary: cacheAR is a tiny Ruby on Rails add-on to enable support of caching ActiveRecord lookup results.
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: dmitry@sabanin.ru
|
12
|
+
homepage: http://rubyforge.org/projects/muravey-tools
|
13
|
+
rubyforge_project: muravey-tools
|
14
|
+
description:
|
15
|
+
autorequire: cachear
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
authors:
|
28
|
+
- Dmitry V. Sabanin
|
29
|
+
files:
|
30
|
+
- lib/cachear.rb
|
31
|
+
- cacheAR-CHANGES
|
32
|
+
test_files: []
|
33
|
+
rdoc_options: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
requirements: []
|
38
|
+
dependencies: []
|