evented-memcache-client 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGELOG +113 -0
  2. data/COPYING +348 -0
  3. data/README +75 -0
  4. data/Rakefile +123 -0
  5. data/doc/classes/EventMachine.html +146 -0
  6. data/doc/classes/EventMachine/Protocols.html +135 -0
  7. data/doc/classes/EventMachine/Protocols/Memcache.html +153 -0
  8. data/doc/classes/EventMachine/Protocols/Memcache/Client.html +121 -0
  9. data/doc/classes/EventMachine/Protocols/Memcache/Connectable.html +615 -0
  10. data/doc/classes/EventMachine/Protocols/Memcache/Connection.html +192 -0
  11. data/doc/classes/EventMachine/Protocols/Memcache/Sender.html +389 -0
  12. data/doc/classes/EventMachine/Protocols/Memcache/Server.html +463 -0
  13. data/doc/classes/EventMachine/Protocols/Memcache/TenaciousMC.html +277 -0
  14. data/doc/classes/MyHandler.html +197 -0
  15. data/doc/created.rid +1 -0
  16. data/doc/files/COPYING.html +473 -0
  17. data/doc/files/README.html +187 -0
  18. data/doc/files/extras/consumer_rb.html +110 -0
  19. data/doc/files/extras/producer_rb.html +110 -0
  20. data/doc/files/extras/server_rb.html +110 -0
  21. data/doc/files/lib/evented-memcache-client_rb.html +125 -0
  22. data/doc/files/lib/evented_memcache_client/client_rb.html +120 -0
  23. data/doc/files/lib/evented_memcache_client/connectable_rb.html +120 -0
  24. data/doc/files/lib/evented_memcache_client/connection_rb.html +120 -0
  25. data/doc/files/lib/evented_memcache_client/sender_rb.html +112 -0
  26. data/doc/files/lib/evented_memcache_client/server_rb.html +120 -0
  27. data/doc/files/lib/evented_memcache_client/tenacious_rb.html +120 -0
  28. data/doc/fr_class_index.html +36 -0
  29. data/doc/fr_file_index.html +38 -0
  30. data/doc/fr_method_index.html +66 -0
  31. data/doc/index.html +24 -0
  32. data/doc/rdoc-style.css +208 -0
  33. data/extras/consumer.rb +41 -0
  34. data/extras/producer.rb +22 -0
  35. data/extras/server.rb +33 -0
  36. data/lib/evented-memcache-client.rb +37 -0
  37. data/lib/evented_memcache_client/client.rb +36 -0
  38. data/lib/evented_memcache_client/connectable.rb +324 -0
  39. data/lib/evented_memcache_client/connection.rb +73 -0
  40. data/lib/evented_memcache_client/sender.rb +184 -0
  41. data/lib/evented_memcache_client/server.rb +118 -0
  42. data/lib/evented_memcache_client/tenacious.rb +106 -0
  43. metadata +115 -0
@@ -0,0 +1,73 @@
1
+ #############################################################################
2
+ #
3
+ # Author:: Colin Steele (colin@colinsteele.org)
4
+ # Homepage::
5
+ #
6
+ #----------------------------------------------------------------------------
7
+ #
8
+ # Copyright (C) 2008 by Colin Steele. All Rights Reserved.
9
+ # colin@colinsteele.org
10
+ #
11
+ # This program is free software; you can redistribute it and/or modify
12
+ # it under the terms of either: 1) the GNU General Public License
13
+ # as published by the Free Software Foundation; either version 2 of the
14
+ # License, or (at your option) any later version; or 2) Ruby's License.
15
+ #
16
+ # See the file COPYING for complete licensing information.
17
+ #
18
+ #---------------------------------------------------------------------------
19
+ #
20
+ #
21
+ #############################################################################
22
+
23
+ require 'rubygems'
24
+ require 'eventmachine'
25
+
26
+ module EventMachine
27
+ module Protocols
28
+ module Memcache
29
+
30
+ # Implements a memcache protocol connection.
31
+
32
+ class Connection < EventMachine::Connection
33
+
34
+ include Connectable
35
+
36
+ ######################################################################
37
+ # EventMachine::Connection entry points
38
+ ######################################################################
39
+
40
+ # Create a new connection. Args are a hash of callbacks (or a
41
+ # Module -- see Connectable#set_handler).
42
+ #
43
+ # Note that when you're using EventMachine, you won't be
44
+ # calling Connection::new yourself - EM does it for you when a
45
+ # connection is established.
46
+ #
47
+ # Eg:
48
+ # callbacks = {
49
+ # :open => Proc.new { |conn|
50
+ # conn.set(:key => 'x', :data => Time.now.to_s)
51
+ # },
52
+ # :stored => Proc.new { |conn, data, args|
53
+ # puts "Stored a value"
54
+ # EventMachine::stop
55
+ # },
56
+ # }
57
+ # EventMachine::run {
58
+ # EventMachine::connect('127.0.0.1',
59
+ # 12345,
60
+ # EventMachine::Protocols::Memcache::Connection,
61
+ # callbacks)
62
+ # }
63
+ #
64
+ def initialize(*args)
65
+ super(*args)
66
+ return if !args || args.empty?
67
+ set_handler(args[0])
68
+ end
69
+
70
+ end # Connection
71
+ end # Memcache
72
+ end # module Protocols
73
+ end # module EventMachine
@@ -0,0 +1,184 @@
1
+ #############################################################################
2
+ #
3
+ # Author:: Colin Steele (colin@colinsteele.org)
4
+ # Homepage::
5
+ #
6
+ #----------------------------------------------------------------------------
7
+ #
8
+ # Copyright (C) 2008 by Colin Steele. All Rights Reserved.
9
+ # colin@colinsteele.org
10
+ #
11
+ # This program is free software; you can redistribute it and/or modify
12
+ # it under the terms of either: 1) the GNU General Public License
13
+ # as published by the Free Software Foundation; either version 2 of the
14
+ # License, or (at your option) any later version; or 2) Ruby's License.
15
+ #
16
+ # See the file COPYING for complete licensing information.
17
+ #
18
+ #---------------------------------------------------------------------------
19
+ #
20
+ #
21
+ #############################################################################
22
+
23
+ module EventMachine
24
+ module Protocols
25
+ module Memcache
26
+
27
+ # Interface for sending memcache protocol messages like STORE,
28
+ # END, etc. See
29
+ # http://code.sixapart.com/svn/memcached/trunk/server/doc/protocol.txt
30
+ # for more details.
31
+ #
32
+ # NB: since several methods are defined dynamically here using
33
+ # define_method, they don't show up in the RDoc-generated
34
+ # documentation. Sorry.
35
+
36
+ module Sender
37
+
38
+ # Keeps stats on message sends.
39
+ def book_it(msg_type)
40
+ @snd_stats[msg_type] ||= 0
41
+ @snd_stats[msg_type] += 1
42
+ end
43
+
44
+ # Wish these could be properly rdoc'd...
45
+ %w(set add replace append prepend).each { |cmd|
46
+ class_eval do
47
+ define_method "#{cmd}" do |args|
48
+ book_it(cmd.to_sym)
49
+ key = args[:key]
50
+ flags = args[:flags] || 0
51
+ exptime = args[:exptime] || 0
52
+ noreply = args[:noreply] || false
53
+ data = args[:data]
54
+ raise ArgumentError.new(':data cannot be nil') unless data
55
+ raise ArgumentError.new(':key cannot be nil') unless key
56
+ cmd_str = "#{cmd} #{key} #{flags} #{exptime} #{data.length}"
57
+ cmd_str << " noreply" if noreply
58
+ send_to_peer "#{cmd_str}\r\n#{data}\r\n"
59
+ end
60
+ end
61
+ }
62
+
63
+ # Send a cas request to the memcached server.
64
+ def cas(*args)
65
+ book_it(:cas)
66
+ key = args[:key]
67
+ flags = args[:flags] || 0
68
+ exptime = args[:exptime] || 0
69
+ cas_uniq = args[:cas_uniq]
70
+ noreply = args[:noreply] || false
71
+ data = args[:data]
72
+ raise ArgumentError.new(':data cannot be nil') unless data
73
+ raise ArgumentError.new(':key cannot be nil') unless key
74
+ raise ArgumentError.new(':cas_uniq cannot be nil') unless cas_uniq
75
+ cmd_str = "cas #{key} #{flags} #{exptime} #{data.length} #{cas_uniq}"
76
+ cmd_str << " noreply" if noreply
77
+ send_to_peer "#{cmd_str}\r\n#{data}\r\n"
78
+ end
79
+
80
+ # Send a get request to the memcached server. +args+ must
81
+ # have a :keys key if it is a hash, otherwise it's assumed
82
+ # that it is a single key. Eg., get('queue') or
83
+ # get(:keys=>['queue_a', 'queue_b']) or get(:key=>'queue').
84
+ def get(args)
85
+ if args.respond_to?(:keys)
86
+ keys = args[:keys] || [args[:key]]
87
+ else
88
+ keys = [args]
89
+ end
90
+ raise ArgumentError.new('No keys specified.') if keys.empty?
91
+ send_to_peer "get #{keys.join(' ')}\r\n"
92
+ end
93
+ alias_method :gets, :get
94
+
95
+ # Send a delete request to the memcached server. +args+ is a
96
+ # Hash with a required :key member, and optional :time and
97
+ # :noreply members.
98
+ def delete(*args)
99
+ book_it(:delete)
100
+ key = args[:key]
101
+ time = args[:time] || 0
102
+ noreply = args[:noreply] || false
103
+ raise ArgumentError.new(':key cannot be nil') unless key
104
+ cmd_str = "delete #{key}"
105
+ cmd_str << " #{time}" if time > 0
106
+ cmd_str << " noreply" if noreply
107
+ send_to_peer "#{cmd_str}\r\n"
108
+ end
109
+
110
+ # Wish these could be properly rdoc'd...
111
+ %w(incr decr).each { |cmd|
112
+ class_eval do
113
+ define_method "#{cmd}" do |args|
114
+ book_it(cmd.to_sym)
115
+ key = args[:key]
116
+ value = args[:value] || 0
117
+ noreply = args[:noreply] || false
118
+ raise ArgumentError.new(':key cannot be nil') unless key
119
+ raise ArgumentError.new(':value cannot be nil') unless value
120
+ cmd_str = "#{cmd} #{key} #{value}"
121
+ cmd_str << " noreply" if noreply
122
+ send_to_peer "#{cmd_str}\r\n"
123
+ end
124
+ end
125
+ }
126
+
127
+ # Send a stats request to the memcached server. +args+ is a
128
+ # Array that specifies the specific stats command as defined
129
+ # in the memcache protocol.
130
+ def stats(*args)
131
+ book_it(:stats)
132
+ cmd_str = "stats #{args.join(' ')}"
133
+ send_to_peer "#{cmd_str}\r\n"
134
+ end
135
+
136
+ # Wish these could be properly rdoc'd...
137
+ %w(flush_all version quit).each { |cmd|
138
+ class_eval do
139
+ define_method "#{cmd}" do
140
+ book_it(cmd.to_sym)
141
+ send_to_peer "#{cmd}\r\n"
142
+ end
143
+ end
144
+ }
145
+
146
+ # Wish these could be properly rdoc'd...
147
+ %w(stored end).each { |cmd|
148
+ class_eval do
149
+ define_method "#{cmd}" do
150
+ book_it(cmd.to_sym)
151
+ send_to_peer "#{cmd.upcase}\r\n"
152
+ end
153
+ end
154
+ }
155
+
156
+ # Send a value message to the remote endpoint (client); this
157
+ # is a server-sent message. +args+ is a
158
+ # Hash with a required :key member, and optional :flash and
159
+ # :cas_uniq members. Hash must also include a :data
160
+ # member (the payload to be sent).
161
+ def value(args)
162
+ book_it(:value)
163
+ key = args[:key]
164
+ flags = args[:flags] || 0
165
+ cas_uniq = args[:cas_uniq]
166
+ data = args[:data]
167
+ raise ArgumentError.new(':data cannot be nil') unless data
168
+ raise ArgumentError.new(':key cannot be nil') unless key
169
+ cmd_str = "VALUE #{key} #{flags} #{data.length}"
170
+ cmd_str << " #{cas_uniq}" if cas_uniq
171
+ send_to_peer "#{cmd_str}\r\n#{data}\r\n"
172
+ end
173
+
174
+ # Send a memcache protocol message contained in the :data
175
+ # argument to the remote endpoint.
176
+ def send_to_peer(data)
177
+ @msgs_out ||= 0
178
+ @msgs_out += 1
179
+ send_data(data)
180
+ end
181
+ end # Sender
182
+ end # Memcache
183
+ end # Protocols
184
+ end # EventMachine
@@ -0,0 +1,118 @@
1
+ #############################################################################
2
+ #
3
+ # Author:: Colin Steele (colin@colinsteele.org)
4
+ # Homepage::
5
+ #
6
+ #----------------------------------------------------------------------------
7
+ #
8
+ # Copyright (C) 2008 by Colin Steele. All Rights Reserved.
9
+ # colin@colinsteele.org
10
+ #
11
+ # This program is free software; you can redistribute it and/or modify
12
+ # it under the terms of either: 1) the GNU General Public License
13
+ # as published by the Free Software Foundation; either version 2 of the
14
+ # License, or (at your option) any later version; or 2) Ruby's License.
15
+ #
16
+ # See the file COPYING for complete licensing information.
17
+ #
18
+ #---------------------------------------------------------------------------
19
+ #
20
+ #
21
+ #############################################################################
22
+
23
+ require 'rubygems'
24
+ require 'eventmachine'
25
+
26
+ module EventMachine
27
+ module Protocols
28
+ module Memcache
29
+ class Server
30
+
31
+ DEFAULT_PORT = 22122
32
+ DEFAULT_HOST = 'localhost'
33
+
34
+ attr_accessor :connections
35
+ attr :host, true
36
+ attr :port, true
37
+
38
+ # Create a new memcache server listener, on the specified host
39
+ # and port.
40
+ def initialize(host=nil, port=nil)
41
+ @host = host || DEFAULT_HOST
42
+ @port = port || DEFAULT_PORT
43
+ @connections = []
44
+ end
45
+
46
+ # Start listening for client connections.
47
+ def start
48
+ begin
49
+ @signature = EventMachine.start_server(@host,
50
+ @port.to_i,
51
+ Connectable,
52
+ self) { |conn|
53
+ conn.set_handler(self)
54
+
55
+ # Usually called from EM; we fake it out.
56
+ conn.connection_completed
57
+ }
58
+ rescue => e
59
+ return false
60
+ else
61
+ return true
62
+ end
63
+ end
64
+
65
+ # Stop listening for client connections, and close any open
66
+ # clients.
67
+ def stop
68
+ EventMachine.stop_server(@signature)
69
+ unless wait_for_connections
70
+ # Still some running
71
+ EventMachine.add_periodic_timer(1) {
72
+ wait_for_connections
73
+ }
74
+ end
75
+ end
76
+
77
+
78
+ ######################################################################
79
+ # Callbacks from the connection
80
+ ######################################################################
81
+
82
+ def open(conn)
83
+ @connections << conn
84
+ end
85
+
86
+ def close(conn)
87
+ @connections.delete(conn)
88
+ end
89
+
90
+ def set(conn, data, args)
91
+ # we don't do nuffing
92
+ end
93
+ alias_method :replace, :set
94
+ alias_method :prepend, :set
95
+ alias_method :append, :set
96
+ alias_method :add, :set
97
+
98
+ def get(conn, data, args)
99
+ # we don't do nuffing
100
+ end
101
+
102
+ protected
103
+
104
+ def wait_for_connections
105
+ if @connections.empty?
106
+ true
107
+ else
108
+ @connections.each { |c|
109
+ c.close_connection_after_writing
110
+ }
111
+ false
112
+ end
113
+ end
114
+
115
+ end # Server
116
+ end # Memcache
117
+ end # module Protocols
118
+ end # module EventMachine
@@ -0,0 +1,106 @@
1
+ #############################################################################
2
+ #
3
+ # Author:: Colin Steele (colin@colinsteele.org)
4
+ # Homepage::
5
+ #
6
+ #----------------------------------------------------------------------------
7
+ #
8
+ # Copyright (C) 2008 by Colin Steele. All Rights Reserved.
9
+ # colin@colinsteele.org
10
+ #
11
+ # This program is free software; you can redistribute it and/or modify
12
+ # it under the terms of either: 1) the GNU General Public License
13
+ # as published by the Free Software Foundation; either version 2 of the
14
+ # License, or (at your option) any later version; or 2) Ruby's License.
15
+ #
16
+ # See the file COPYING for complete licensing information.
17
+ #
18
+ #---------------------------------------------------------------------------
19
+ #
20
+ #
21
+ #############################################################################
22
+
23
+ require 'rubygems'
24
+ require 'eventmachine'
25
+
26
+ module EventMachine
27
+ module Protocols
28
+ module Memcache
29
+
30
+ # TenaciousMC is a "tenacious" memcache client connection. When
31
+ # the underlying connection is lost, it attempts to reacquire it
32
+ # automatically.
33
+
34
+ class TenaciousMC < Client
35
+
36
+ # Create a new "tenacious" connection, which will attempt to
37
+ # reacquire a connection to the server if it is lost.
38
+ #
39
+ # Note that when you're using EventMachine, you won't be
40
+ # calling TenaciousMC::new yourself - EM does it for you when a
41
+ # connection is established.
42
+ #
43
+ # First argument as per EventMachine::Protocols::Memcache::Client.
44
+ # Ie., callback hash, module or handler object.
45
+ #
46
+ # Second argument is hash of options governing TenaciousMC's
47
+ # behavior:
48
+ #
49
+ # { :host => 'somewhere.com', :port=>12345, :interval => 5 }
50
+ #
51
+ # If the options hash includes a :eager key, and its value is
52
+ # true, then when the connection opens, TenaciousMC will
53
+ # immediately send a 'get' to the server to fetch data, using
54
+ # the value of the :key option as the key fetched.
55
+ #
56
+ # So a typical invocation:
57
+ #
58
+ # EventMachine::run {
59
+ # EventMachine::connect('over.there',
60
+ # 12345,
61
+ # EventMachine::Protocols::Memcache::TenaciousMC,
62
+ # MyHandlerModule,
63
+ # {:host => 'over.there', :port => 12345})
64
+ # }
65
+ def initialize(*args)
66
+ @handle_arg = args[0]
67
+ options = args[1]
68
+ @host = options[:host] || 'localhost'
69
+ @port = options[:port]
70
+ raise "No port option is set" unless @port
71
+ @interval = options[:interval] || 5
72
+ @eager = options[:eager] || false
73
+ @key = options[:key] || nil
74
+ super(*args)
75
+ end
76
+
77
+ # Called from EM::Connection after the connection is established.
78
+ def connection_completed
79
+ super
80
+ if @eager && @key
81
+ self.get(:key => @key)
82
+ end
83
+ end
84
+
85
+ # Called from EM::Connection when the connection is dead.
86
+ def unbind
87
+ super
88
+ if @interval > 0
89
+ EventMachine::add_timer(@interval) do
90
+ EventMachine::connect(@host,
91
+ @port,
92
+ self.class,
93
+ @handle_arg,
94
+ {
95
+ :host => @host,
96
+ :port => @port,
97
+ :interval => @interval
98
+ })
99
+ end
100
+ end
101
+ end
102
+
103
+ end # TenaciousMC
104
+ end # Memcache
105
+ end # module Protocols
106
+ end # module EventMachine