cacheAR 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/cacheAR-CHANGES +0 -0
  2. data/lib/cachear.rb +218 -0
  3. metadata +38 -0
File without changes
@@ -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: []