sayso-dalli 1.0.3.001

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ class Dalli::Client
2
+
3
+ module MemcacheClientCompatibility
4
+
5
+ def initialize(*args)
6
+ Dalli.logger.error("Starting Dalli in memcache-client compatibility mode")
7
+ super(*args)
8
+ end
9
+
10
+ def set(key, value, ttl = nil, options = nil)
11
+ if options == true || options == false
12
+ Dalli.logger.error("Dalli: please use set(key, value, ttl, :raw => boolean): #{caller[0]}")
13
+ options = { :raw => options }
14
+ end
15
+ super(key, value, ttl, options) ? "STORED\r\n" : "NOT_STORED\r\n"
16
+
17
+ end
18
+
19
+ def add(key, value, ttl = nil, options = nil)
20
+ if options == true || options == false
21
+ Dalli.logger.error("Dalli: please use add(key, value, ttl, :raw => boolean): #{caller[0]}")
22
+ options = { :raw => options }
23
+ end
24
+ super(key, value, ttl, options) ? "STORED\r\n" : "NOT_STORED\r\n"
25
+ end
26
+
27
+ def replace(key, value, ttl = nil, options = nil)
28
+ if options == true || options == false
29
+ Dalli.logger.error("Dalli: please use replace(key, value, ttl, :raw => boolean): #{caller[0]}")
30
+ options = { :raw => options }
31
+ end
32
+ super(key, value, ttl, options) ? "STORED\r\n" : "NOT_STORED\r\n"
33
+ end
34
+
35
+ # Dalli does not unmarshall data that does not have the marshalled flag set so we need
36
+ # to unmarshall manually any marshalled data originally put in memcached by memcache-client.
37
+ # Peek at the data and see if it looks marshalled.
38
+ def get(key, options = nil)
39
+ value = super(key, options)
40
+ if value && value.is_a?(String) && !options && value.size > 2 &&
41
+ bytes = value.unpack('cc') && bytes[0] == 4 && bytes[1] == 8
42
+ return Marshal.load(value) rescue value
43
+ end
44
+ value
45
+ end
46
+
47
+ def delete(key)
48
+ super(key) ? "DELETED\r\n" : "NOT_DELETED\r\n"
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1 @@
1
+ Dalli::Client.compatibility_mode = true
@@ -0,0 +1,44 @@
1
+ require 'thread'
2
+ require 'monitor'
3
+
4
+ module Dalli
5
+
6
+ # Make Dalli threadsafe by using a lock around all
7
+ # public server methods.
8
+ #
9
+ # Dalli::Server.extend(Dalli::Threadsafe)
10
+ #
11
+ module Threadsafe
12
+ def request(op, *args)
13
+ lock.synchronize do
14
+ super
15
+ end
16
+ end
17
+
18
+ def alive?
19
+ lock.synchronize do
20
+ super
21
+ end
22
+ end
23
+
24
+ def close
25
+ lock.synchronize do
26
+ super
27
+ end
28
+ end
29
+
30
+ def lock!
31
+ lock.mon_enter
32
+ end
33
+
34
+ def unlock!
35
+ lock.mon_exit
36
+ end
37
+
38
+ private
39
+ def lock
40
+ @lock ||= Monitor.new
41
+ end
42
+
43
+ end
44
+ end
data/lib/dalli/ring.rb ADDED
@@ -0,0 +1,105 @@
1
+ require 'digest/sha1'
2
+ require 'zlib'
3
+
4
+ module Dalli
5
+ class Ring
6
+ POINTS_PER_SERVER = 160 # this is the default in libmemcached
7
+
8
+ attr_accessor :servers, :continuum
9
+
10
+ def initialize(servers, options)
11
+ @servers = servers
12
+ @continuum = nil
13
+ if servers.size > 1
14
+ total_weight = servers.inject(0) { |memo, srv| memo + srv.weight }
15
+ continuum = []
16
+ servers.each do |server|
17
+ entry_count_for(server, servers.size, total_weight).times do |idx|
18
+ hash = Digest::SHA1.hexdigest("#{server.hostname}:#{server.port}:#{idx}")
19
+ value = Integer("0x#{hash[0..7]}")
20
+ continuum << Dalli::Ring::Entry.new(value, server)
21
+ end
22
+ end
23
+ @continuum = continuum.sort { |a, b| a.value <=> b.value }
24
+ end
25
+
26
+ threadsafe! unless options[:threadsafe] == false
27
+ @failover = options[:failover] != false
28
+ end
29
+
30
+ def server_for_key(key)
31
+ if @continuum
32
+ hkey = hash_for(key)
33
+ 20.times do |try|
34
+ entryidx = self.class.binary_search(@continuum, hkey)
35
+ server = @continuum[entryidx].server
36
+ return server if server.alive?
37
+ break unless @failover
38
+ hkey = hash_for("#{try}#{key}")
39
+ end
40
+ else
41
+ server = @servers.first
42
+ return server if server && server.alive?
43
+ end
44
+
45
+ raise Dalli::RingError, "No server available"
46
+ end
47
+
48
+ def lock
49
+ @servers.each { |s| s.lock! }
50
+ begin
51
+ return yield
52
+ ensure
53
+ @servers.each { |s| s.unlock! }
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def threadsafe!
60
+ @servers.each do |s|
61
+ s.extend(Dalli::Threadsafe)
62
+ end
63
+ end
64
+
65
+ def hash_for(key)
66
+ Zlib.crc32(key)
67
+ end
68
+
69
+ def entry_count_for(server, total_servers, total_weight)
70
+ ((total_servers * POINTS_PER_SERVER * server.weight) / Float(total_weight)).floor
71
+ end
72
+
73
+ # Find the closest index in the Ring with value <= the given value
74
+ def self.binary_search(ary, value)
75
+ upper = ary.size - 1
76
+ lower = 0
77
+ idx = 0
78
+
79
+ while (lower <= upper) do
80
+ idx = (lower + upper) / 2
81
+ comp = ary[idx].value <=> value
82
+
83
+ if comp == 0
84
+ return idx
85
+ elsif comp > 0
86
+ upper = idx - 1
87
+ else
88
+ lower = idx + 1
89
+ end
90
+ end
91
+ return upper
92
+ end
93
+
94
+ class Entry
95
+ attr_reader :value
96
+ attr_reader :server
97
+
98
+ def initialize(val, srv)
99
+ @value = val
100
+ @server = srv
101
+ end
102
+ end
103
+
104
+ end
105
+ end