ninjudd-ninjudd-memcache-client 1.5.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ if not defined?(MemCache)
2
+ require File.dirname(__FILE__) + '/memcache'
3
+ end
4
+
5
+ module MemCacheExtensions
6
+ LOCK_TIMEOUT = 5 if not defined? LOCK_TIMEOUT
7
+ WRITE_LOCK_WAIT = 0.001 if not defined? WRITE_LOCK_WAIT
8
+
9
+ def get_some(keys, disable = false)
10
+ keys = keys.collect {|key| key.to_s}
11
+
12
+ records = {}
13
+ records = self.get_multi(keys) unless disable
14
+ keys_to_fetch = keys - records.keys
15
+
16
+ if keys_to_fetch.any?
17
+ yield(keys_to_fetch).each do |key, data_item|
18
+ self.set(key, data_item) unless disable
19
+ records[key] = data_item
20
+ end
21
+ end
22
+ records
23
+ end
24
+
25
+ def in_namespace(namespace)
26
+ begin
27
+ # Temporarily change the namespace for convenience.
28
+ ns = self.namespace
29
+ self.instance_variable_set(:@namespace, "#{ns}#{namespace}")
30
+ yield
31
+ ensure
32
+ self.instance_variable_set(:@namespace, ns)
33
+ end
34
+ end
35
+
36
+ def get_or_set(key)
37
+ get(key) || begin
38
+ value = yield
39
+ set(key, value)
40
+ value
41
+ end
42
+ end
43
+
44
+ def get_reset_expiry(key, expiry)
45
+ result = get(key)
46
+ set(key, result, expiry) if result
47
+ result
48
+ end
49
+
50
+ def lock(key)
51
+ # Returns true if the lock already exists.
52
+ response = add(lock_key(key), true, LOCK_TIMEOUT)
53
+ response.index('STORED') != 0
54
+ end
55
+
56
+ def unlock(key)
57
+ response = delete(lock_key(key))
58
+ response.index('DELETED') == 0
59
+ end
60
+
61
+ def with_lock(key, flag = nil)
62
+ while lock(key) do
63
+ return if flag == :ignore
64
+ sleep(WRITE_LOCK_WAIT) # just wait
65
+ end
66
+ yield
67
+ unlock(key) unless flag == :keep
68
+ end
69
+
70
+ def lock_key(key)
71
+ "lock:#{key}"
72
+ end
73
+
74
+ def locked?(key)
75
+ not get(lock_key(key)).nil?
76
+ end
77
+
78
+ def set_with_lock(*args)
79
+ with_lock(args.first, :ignore) do
80
+ set(*args)
81
+ end
82
+ end
83
+
84
+ def add_with_lock(*args)
85
+ with_lock(args.first, :ignore) do
86
+ add(*args)
87
+ end
88
+ end
89
+
90
+ def delete_with_lock(*args)
91
+ # leave a :delete lock around to prevent someone from
92
+ # adding stale data for a little while
93
+ with_lock(args.first, :keep) do
94
+ delete(*args)
95
+ end
96
+ end
97
+
98
+ ### To support using memcache in testing.
99
+ def clear; end
100
+ def empty?; false; end
101
+ ###
102
+ end
103
+
104
+ class MemCache
105
+ include MemCacheExtensions
106
+ end
107
+
108
+ if defined?(MemCacheMock)
109
+ class MemCacheMock
110
+ include MemCacheExtensions
111
+ end
112
+ end
@@ -0,0 +1,126 @@
1
+ class MemCacheMock
2
+ attr_writer :namespace
3
+
4
+ def initialize
5
+ @data = {}
6
+ @expiry = {}
7
+ @auto_clear = false
8
+ end
9
+
10
+ def namespace
11
+ @namespace.to_s
12
+ end
13
+
14
+ def cache_key(key)
15
+ "#{namespace}:#{key}"
16
+ end
17
+
18
+ # Note: This doesn't work exactly like memcache's incr
19
+ # because MemCacheMock doesn't support raw storage.
20
+ # This version will work on marshalled data.
21
+ # This is also not atomic.
22
+ def incr(key, amount=1)
23
+ oldval = get(key).to_i or return nil
24
+ newval = oldval + amount
25
+ set(key, newval) # Note: Loses the expiry.
26
+ return newval
27
+ end
28
+
29
+ def decr(key, amount=1)
30
+ incr(key, amount * -1)
31
+ end
32
+
33
+ def set(*args)
34
+ do_set(*args)
35
+ end
36
+
37
+ # Note: Raw not implemented.
38
+ def do_set(key, value, expiry = 0, raw=false)
39
+ return '' if @auto_clear
40
+ key = cache_key(key)
41
+
42
+ @data[key] = Marshal.dump(value)
43
+ @expiry[key] = Time.now + expiry if expiry != 0
44
+ 'STORED'
45
+ end
46
+
47
+ def add(key, value, expiry = 0)
48
+ do_set(key, value, expiry) unless get(key)
49
+ end
50
+
51
+ def kind_of?(type)
52
+ (type == MemCache) || super
53
+ end
54
+
55
+ def delete(key)
56
+ key = cache_key(key)
57
+ @data.delete(key)
58
+ end
59
+
60
+ def clear
61
+ @data.clear
62
+ @expiry.clear
63
+ end
64
+
65
+ def get_multi(*keys)
66
+ hash = {}
67
+ keys.each do |key|
68
+ val = get(key)
69
+ key = cache_key(key).sub("#{namespace}:",'')
70
+ hash[key] = val if val
71
+ end
72
+ hash
73
+ end
74
+
75
+ # Note: Raw not implemented.
76
+ def get(key, raw=false)
77
+ key = cache_key(key)
78
+ clear if @auto_clear
79
+ if @expiry[key] and Time.now > @expiry[key]
80
+ @data[key] = nil
81
+ @expiry[key] = nil
82
+ end
83
+ return if not @data[key]
84
+ Marshal.load(@data[key])
85
+ end
86
+
87
+ def [](key)
88
+ get(key)
89
+ end
90
+
91
+ def []=(key, value)
92
+ set(key, value)
93
+ end
94
+
95
+ def empty?
96
+ @data.empty?
97
+ end
98
+
99
+ def keys
100
+ @data.keys
101
+ end
102
+
103
+ def auto_clear_on(&block)
104
+ if block_given?
105
+ auto_clear_block(true, &block)
106
+ else
107
+ @auto_clear = true
108
+ end
109
+ end
110
+
111
+ def auto_clear_off(&block)
112
+ if block_given?
113
+ auto_clear_block(false, &block)
114
+ else
115
+ @auto_clear = false
116
+ end
117
+ end
118
+
119
+ def auto_clear_block(value, &block)
120
+ old_auto_clear = @auto_clear
121
+ @auto_clear = value
122
+ block.call
123
+ @auto_clear = old_auto_clear
124
+ end
125
+
126
+ end
@@ -0,0 +1,90 @@
1
+ ##
2
+ # A utility wrapper around the MemCache client to simplify cache access. All
3
+ # methods silently ignore MemCache errors.
4
+
5
+ module Cache
6
+
7
+ ##
8
+ # Returns the object at +key+ from the cache if successful, or nil if either
9
+ # the object is not in the cache or if there was an error attermpting to
10
+ # access the cache.
11
+ #
12
+ # If there is a cache miss and a block is given the result of the block will
13
+ # be stored in the cache with optional +expiry+, using the +add+ method rather
14
+ # than +set+.
15
+
16
+ def self.get(key, expiry = 0)
17
+ start_time = Time.now
18
+ value = CACHE.get key
19
+ elapsed = Time.now - start_time
20
+ ActiveRecord::Base.logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
21
+ if value.nil? and block_given? then
22
+ value = yield
23
+ add key, value, expiry
24
+ end
25
+ value
26
+ rescue MemCache::MemCacheError => err
27
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
28
+ if block_given? then
29
+ value = yield
30
+ put key, value, expiry
31
+ end
32
+ value
33
+ end
34
+
35
+ ##
36
+ # Sets +value+ in the cache at +key+, with an optional +expiry+ time in
37
+ # seconds.
38
+
39
+ def self.put(key, value, expiry = 0)
40
+ start_time = Time.now
41
+ CACHE.set key, value, expiry
42
+ elapsed = Time.now - start_time
43
+ ActiveRecord::Base.logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
44
+ value
45
+ rescue MemCache::MemCacheError => err
46
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
47
+ nil
48
+ end
49
+
50
+ ##
51
+ # Sets +value+ in the cache at +key+, with an optional +expiry+ time in
52
+ # seconds. If +key+ already exists in cache, returns nil.
53
+
54
+ def self.add(key, value, expiry = 0)
55
+ start_time = Time.now
56
+ response = CACHE.add key, value, expiry
57
+ elapsed = Time.now - start_time
58
+ ActiveRecord::Base.logger.debug('MemCache Add (%0.6f) %s' % [elapsed, key])
59
+ (response == "STORED\r\n") ? value : nil
60
+ rescue MemCache::MemCacheError => err
61
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
62
+ nil
63
+ end
64
+
65
+ ##
66
+ # Deletes +key+ from the cache in +delay+ seconds.
67
+
68
+ def self.delete(key, delay = nil)
69
+ start_time = Time.now
70
+ CACHE.delete key, delay
71
+ elapsed = Time.now - start_time
72
+ ActiveRecord::Base.logger.debug('MemCache Delete (%0.6f) %s' %
73
+ [elapsed, key])
74
+ nil
75
+ rescue MemCache::MemCacheError => err
76
+ ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
77
+ nil
78
+ end
79
+
80
+ ##
81
+ # Resets all connections to MemCache servers.
82
+
83
+ def self.reset
84
+ CACHE.reset
85
+ ActiveRecord::Base.logger.debug 'MemCache Connections Reset'
86
+ nil
87
+ end
88
+
89
+ end
90
+