ngmoco-cache-money 0.2.10 → 0.2.13

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.
@@ -9,4 +9,10 @@ ActiveRecord::Schema.define(:version => 2) do
9
9
  t.integer "story_id"
10
10
  t.string "name"
11
11
  end
12
+
13
+ create_table :sessions, :force => true do |t|
14
+ t.string :session_id
15
+ t.text :data
16
+ t.timestamps
17
+ end
12
18
  end
@@ -1,8 +1,5 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__))
2
-
3
- require 'rubygems'
4
- require 'activesupport'
5
- require 'activerecord'
1
+ require 'active_support'
2
+ require 'active_record'
6
3
 
7
4
  require 'cash/lock'
8
5
  require 'cash/transactional'
@@ -27,9 +24,21 @@ require 'cash/util/marshal'
27
24
 
28
25
  class ActiveRecord::Base
29
26
  def self.is_cached(options = {})
30
- options.assert_valid_keys(:ttl, :repository, :version)
31
- include Cash unless ancestors.include?(Cash)
32
- Cash::Config.create(self, options)
27
+ if options == false
28
+ include NoCash
29
+ else
30
+ options.assert_valid_keys(:ttl, :repository, :version)
31
+ include Cash unless ancestors.include?(Cash)
32
+ Cash::Config.create(self, options)
33
+ end
34
+ end
35
+
36
+ def <=>(other)
37
+ if self.id == other.id then
38
+ 0
39
+ else
40
+ self.id < other.id ? -1 : 1
41
+ end
33
42
  end
34
43
  end
35
44
 
@@ -49,7 +58,27 @@ module Cash
49
58
  end
50
59
 
51
60
  def transaction_with_cache_transaction(&block)
52
- repository.transaction { transaction_without_cache_transaction(&block) }
61
+ if cache_config
62
+ repository.transaction { transaction_without_cache_transaction(&block) }
63
+ else
64
+ transaction_without_cache_transaction(&block)
65
+ end
66
+ end
67
+
68
+ def cacheable?(*args)
69
+ true
53
70
  end
54
71
  end
55
72
  end
73
+ module NoCash
74
+ def self.included(active_record_class)
75
+ active_record_class.class_eval do
76
+ extend ClassMethods
77
+ end
78
+ end
79
+ module ClassMethods
80
+ def cachable?(*args)
81
+ false
82
+ end
83
+ end
84
+ end
@@ -80,15 +80,12 @@ module Cash
80
80
  end
81
81
  end
82
82
 
83
- def method_missing(method, *args, &block)
84
- @cache.send(method, *args, &block)
85
- end
86
-
87
83
  def respond_to?(method)
88
84
  @cache.respond_to?(method)
89
85
  end
90
86
 
91
87
  protected
88
+
92
89
  def perform_commands
93
90
  @commands.each do |command|
94
91
  command.call(@cache)
@@ -98,6 +95,12 @@ module Cash
98
95
  def buffer_command(command)
99
96
  @commands << command
100
97
  end
98
+
99
+ private
100
+
101
+ def method_missing(method, *args, &block)
102
+ @cache.send(method, *args, &block)
103
+ end
101
104
  end
102
105
 
103
106
  class NestedBuffered < Buffered
@@ -15,8 +15,11 @@ module Cash
15
15
  module ClassMethods
16
16
  def self.extended(a_class)
17
17
  class << a_class
18
- attr_reader :cache_config
19
- delegate :repository, :indices, :to => :@cache_config
18
+ def cache_config
19
+ @cache_config ? @cache_config : superclass.cache_config
20
+ end
21
+
22
+ delegate :repository, :indices, :to => :cache_config
20
23
  alias_method_chain :inherited, :cache_config
21
24
  end
22
25
  end
@@ -52,7 +55,7 @@ module Cash
52
55
  end
53
56
 
54
57
  def ttl
55
- @options[:ttl] || 0
58
+ @ttl ||= @options[:ttl] || repository.default_ttl || 1.day
56
59
  end
57
60
 
58
61
  def version
@@ -7,6 +7,7 @@ module Cash
7
7
  DEFAULT_OPTIONS = { :ttl => 1.day }
8
8
 
9
9
  def initialize(config, active_record, attributes, options = {})
10
+ DEFAULT_OPTIONS[:ttl] = config.ttl || DEFAULT_OPTIONS[:ttl]
10
11
  @config, @active_record, @attributes, @options = config, active_record, Array(attributes).collect(&:to_s).sort, DEFAULT_OPTIONS.merge(options)
11
12
  end
12
13
 
@@ -87,7 +88,11 @@ module Cash
87
88
  new_attribute_value_pairs = []
88
89
  @attributes.each do |name|
89
90
  new_value = object.attributes[name]
90
- original_value = object.send("#{name}_was")
91
+ if object.changed.include? name
92
+ original_value = object.send("#{name}_was")
93
+ else
94
+ original_value = new_value
95
+ end
91
96
  old_attribute_value_pairs << [name, original_value]
92
97
  new_attribute_value_pairs << [name, new_value]
93
98
  end
@@ -12,12 +12,6 @@ module Cash
12
12
  ensure
13
13
  @remote_cache = original_cache
14
14
  end
15
-
16
- def method_missing(method, *args, &block)
17
- autoload_missing_constants do
18
- @remote_cache.send(method, *args, &block)
19
- end
20
- end
21
15
 
22
16
  def autoload_missing_constants
23
17
  yield if block_given?
@@ -29,6 +23,14 @@ module Cash
29
23
  raise error
30
24
  end
31
25
  end
26
+
27
+ private
28
+
29
+ def method_missing(method, *args, &block)
30
+ autoload_missing_constants do
31
+ @remote_cache.send(method, *args, &block)
32
+ end
33
+ end
32
34
  end
33
35
 
34
36
  class LocalBuffer
@@ -65,6 +67,8 @@ module Cash
65
67
  @local_cache.delete(key)
66
68
  end
67
69
 
70
+ private
71
+
68
72
  def method_missing(method, *args, &block)
69
73
  @remote_cache.send(method, *args, &block)
70
74
  end
@@ -1,3 +1,5 @@
1
+ require 'socket'
2
+
1
3
  module Cash
2
4
  class Lock
3
5
  class Error < RuntimeError; end
@@ -25,12 +27,13 @@ module Cash
25
27
 
26
28
  def acquire_lock(key, lock_expiry = DEFAULT_EXPIRY, retries = DEFAULT_RETRY, initial_wait = INITIAL_WAIT)
27
29
  retries.times do |count|
28
- response = @cache.add("lock/#{key}", Process.pid, lock_expiry)
30
+ response = @cache.add("lock/#{key}", host_pid, lock_expiry)
29
31
  return if response == "STORED\r\n"
32
+ return if recursive_lock?(key)
30
33
  exponential_sleep(count, initial_wait) unless count == retries - 1
31
34
  end
32
35
  debug_lock(key)
33
- raise Error, "Couldn't acquire memcache lock for: #{key} server: #{@cache.get_server_for_key(key)}"
36
+ raise Error, "Couldn't acquire memcache lock on #{@cache.get_server_for_key("lock/#{key}")}"
34
37
  end
35
38
 
36
39
  def release_lock(key)
@@ -44,13 +47,17 @@ module Cash
44
47
  private
45
48
 
46
49
  def recursive_lock?(key)
47
- @cache.get("lock/#{key}") == Process.pid
50
+ @cache.get("lock/#{key}") == host_pid
48
51
  end
49
52
 
50
53
  def debug_lock(key)
51
- @cache.logger.warn("#{@cache.get("lock/#{key}")}") if @cache.respond_to?(:logger) && @cache.logger.respond_to?(:warn)
54
+ @cache.logger.warn("Cash::Lock[#{key}]: #{@cache.get("lock/#{key}")}") if @cache.respond_to?(:logger) && @cache.logger.respond_to?(:warn)
52
55
  rescue
53
56
  @cache.logger.warn("#{$!}") if @cache.respond_to?(:logger) && @cache.logger.respond_to?(:warn)
54
57
  end
58
+
59
+ def host_pid
60
+ "#{Socket.gethostname} #{Process.pid}"
61
+ end
55
62
  end
56
63
  end
@@ -0,0 +1,154 @@
1
+ module Cash
2
+ class Mock < HashWithIndifferentAccess
3
+ attr_accessor :servers
4
+
5
+ class CacheEntry
6
+ attr_reader :value
7
+
8
+ def self.default_ttl
9
+ 1_000_000
10
+ end
11
+
12
+ def self.now
13
+ Time.now
14
+ end
15
+
16
+ def initialize(value, raw, ttl)
17
+ if raw
18
+ @value = value.to_s
19
+ else
20
+ @value = Marshal.dump(value)
21
+ end
22
+
23
+ if ttl.zero?
24
+ @ttl = self.class.default_ttl
25
+ else
26
+ @ttl = ttl
27
+ end
28
+
29
+ @expires_at = self.class.now + @ttl
30
+ end
31
+
32
+
33
+ def expired?
34
+ self.class.now > @expires_at
35
+ end
36
+
37
+ def increment(amount = 1)
38
+ @value = (@value.to_i + amount).to_s
39
+ end
40
+
41
+ def decrement(amount = 1)
42
+ @value = (@value.to_i - amount).to_s
43
+ end
44
+
45
+ def unmarshal
46
+ Marshal.load(@value)
47
+ end
48
+
49
+ def to_i
50
+ @value.to_i
51
+ end
52
+ end
53
+
54
+ attr_accessor :logging
55
+
56
+ def initialize
57
+ @logging = false
58
+ end
59
+
60
+ def get_multi(keys)
61
+ slice(*keys).collect { |k,v| [k, v.unmarshal] }.to_hash_without_nils
62
+ end
63
+
64
+ def set(key, value, ttl = CacheEntry.default_ttl, raw = false)
65
+ log "< set #{key} #{ttl}"
66
+ self[key] = CacheEntry.new(value, raw, ttl)
67
+ log('> STORED')
68
+ end
69
+
70
+ def get(key, raw = false)
71
+ log "< get #{key}"
72
+ unless self.has_unexpired_key?(key)
73
+ log('> END')
74
+ return nil
75
+ end
76
+
77
+ log("> sending key #{key}")
78
+ log('> END')
79
+ if raw
80
+ self[key].value
81
+ else
82
+ self[key].unmarshal
83
+ end
84
+ end
85
+
86
+ def delete(key, options = {})
87
+ log "< delete #{key}"
88
+ if self.has_unexpired_key?(key)
89
+ log "> DELETED"
90
+ super(key)
91
+ else
92
+ log "> NOT FOUND"
93
+ end
94
+ end
95
+
96
+ def incr(key, amount = 1)
97
+ if self.has_unexpired_key?(key)
98
+ self[key].increment(amount)
99
+ self[key].to_i
100
+ end
101
+ end
102
+
103
+ def decr(key, amount = 1)
104
+ if self.has_unexpired_key?(key)
105
+ self[key].decrement(amount)
106
+ self[key].to_i
107
+ end
108
+ end
109
+
110
+ def add(key, value, ttl = CacheEntry.default_ttl, raw = false)
111
+ if self.has_unexpired_key?(key)
112
+ "NOT_STORED\r\n"
113
+ else
114
+ set(key, value, ttl, raw)
115
+ "STORED\r\n"
116
+ end
117
+ end
118
+
119
+ def append(key, value)
120
+ set(key, get(key, true).to_s + value.to_s, nil, true)
121
+ end
122
+
123
+ def namespace
124
+ nil
125
+ end
126
+
127
+ def flush_all
128
+ log('< flush_all')
129
+ clear
130
+ end
131
+
132
+ def stats
133
+ {}
134
+ end
135
+
136
+ def reset_runtime
137
+ [0, Hash.new(0)]
138
+ end
139
+
140
+ def has_unexpired_key?(key)
141
+ self.has_key?(key) && !self[key].expired?
142
+ end
143
+
144
+ def log(message)
145
+ return unless logging
146
+ logger.debug(message)
147
+ end
148
+
149
+ def logger
150
+ @logger ||= ActiveSupport::BufferedLogger.new(Rails.root.join('log/cash_mock.log'))
151
+ end
152
+
153
+ end
154
+ end
@@ -27,7 +27,7 @@ module Cash
27
27
  misses, missed_keys, objects = hit_or_miss(cache_keys, index, get_options)
28
28
  format_results(cache_keys, choose_deserialized_objects_if_possible(missed_keys, cache_keys, misses, objects))
29
29
  else
30
- logger.debug("---- UNCACHEABLE #{table_name} - #{find_options.inspect} - #{get_options.inspect} - #{@options1.inspect} - #{@options2.inspect}") if logger
30
+ logger.debug(" \e[1;4;31mUNCACHEABLE\e[0m #{table_name} - #{find_options.inspect} - #{get_options.inspect} - #{@options1.inspect} - #{@options2.inspect}") if logger
31
31
  uncacheable
32
32
  end
33
33
  end
@@ -61,6 +61,7 @@ module Cash
61
61
 
62
62
  private
63
63
  def cacheable?(*optionss)
64
+ return false if @active_record.respond_to?(:cachable?) && ! @active_record.cachable?(*optionss)
64
65
  optionss.each { |options| return unless safe_options_for_cache?(options) }
65
66
  partial_indices = optionss.collect { |options| attribute_value_pairs_for_conditions(options[:conditions]) }
66
67
  return if partial_indices.include?(nil)
@@ -122,11 +123,15 @@ module Cash
122
123
  # value = sql_value == '?' ? values.shift : columns_hash[column_name].type_cast(sql_value)
123
124
  if sql_value == '?'
124
125
  value = values.shift
125
- elsif sql_value[0..0] == ':' && values && values.count > 0 && values[0].is_a?(Hash)
126
- symb = sql_value[1..-1].to_sym
127
- value = columns_hash[column_name].type_cast(values[0][symb])
128
126
  else
129
- value = columns_hash[column_name].type_cast(sql_value)
127
+ column = columns_hash[column_name]
128
+ raise "could not find column #{column_name} in columns #{columns_hash.keys.join(',')}" if column.nil?
129
+ if sql_value[0..0] == ':' && values && values.count > 0 && values[0].is_a?(Hash)
130
+ symb = sql_value[1..-1].to_sym
131
+ value = column.type_cast(values[0][symb])
132
+ else
133
+ value = column.type_cast(sql_value)
134
+ end
130
135
  end
131
136
  indices << [column_name, value]
132
137
  else
@@ -182,7 +187,10 @@ module Cash
182
187
 
183
188
  def find_from_keys(*missing_keys)
184
189
  missing_ids = Array(missing_keys).flatten.collect { |key| key.split('/')[2].to_i }
185
- find_from_ids_without_cache(missing_ids, @options1)
190
+ options = @options1.dup
191
+ options.delete(:conditions)
192
+ options.delete(:limit)
193
+ find_from_ids_without_cache(missing_ids, options)
186
194
  end
187
195
  end
188
196
  end
@@ -26,7 +26,6 @@ module Cash
26
26
  @ids.collect { |id| "id/#{id}" }
27
27
  end
28
28
 
29
-
30
29
  def miss(missing_keys, options)
31
30
  find_from_keys(*missing_keys)
32
31
  end
@@ -22,15 +22,16 @@ module Cash
22
22
  end
23
23
  end
24
24
 
25
- def method_missing(method, *args, &block)
26
- @cache.send(method, *args, &block)
27
- end
28
-
29
25
  def respond_to?(method)
30
26
  @cache.respond_to?(method)
31
27
  end
32
28
 
33
29
  private
30
+
31
+ def method_missing(method, *args, &block)
32
+ @cache.send(method, *args, &block)
33
+ end
34
+
34
35
  def begin_transaction
35
36
  @cache = Buffered.push(@cache, @lock)
36
37
  end