ninjudd-ninjudd-memcache-client 1.5.0.3

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.
@@ -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
+