rdkit 0.0.1 → 0.1.4

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/Gemfile +10 -1
  4. data/Gemfile.ci +13 -0
  5. data/Guardfile +40 -0
  6. data/README.md +282 -6
  7. data/Vagrantfile +13 -0
  8. data/example/blocking.rb +10 -0
  9. data/example/blocking/command_runner.rb +28 -0
  10. data/example/blocking/core.rb +24 -0
  11. data/example/blocking/server.rb +10 -0
  12. data/example/blocking/version.rb +3 -0
  13. data/example/callbacks.rb +9 -0
  14. data/example/callbacks/command_runner.rb +21 -0
  15. data/example/callbacks/core.rb +18 -0
  16. data/example/callbacks/server.rb +30 -0
  17. data/example/counter.rb +0 -2
  18. data/example/counter/command_runner.rb +4 -0
  19. data/example/counter/core.rb +4 -0
  20. data/example/http.rb +9 -0
  21. data/example/http/core.rb +18 -0
  22. data/example/http/responder.rb +7 -0
  23. data/example/http/server.rb +19 -0
  24. data/lib/rdkit.rb +20 -3
  25. data/lib/rdkit/callbacks.rb +10 -0
  26. data/lib/rdkit/client.rb +157 -0
  27. data/lib/rdkit/configuration.rb +31 -0
  28. data/lib/rdkit/core.rb +2 -4
  29. data/lib/rdkit/core_ext.rb +7 -0
  30. data/lib/rdkit/db.rb +257 -0
  31. data/lib/rdkit/db_commands.rb +182 -0
  32. data/lib/rdkit/errors.rb +32 -1
  33. data/lib/rdkit/http_parser.rb +56 -0
  34. data/lib/rdkit/http_responder.rb +74 -0
  35. data/lib/rdkit/introspection.rb +133 -21
  36. data/lib/rdkit/logger.rb +9 -4
  37. data/lib/rdkit/memory_monitoring.rb +29 -0
  38. data/lib/rdkit/notification_center.rb +21 -0
  39. data/lib/rdkit/rd_object.rb +69 -0
  40. data/lib/rdkit/resp.rb +9 -1
  41. data/lib/rdkit/{command_parser.rb → resp_parser.rb} +6 -18
  42. data/lib/rdkit/resp_responder.rb +105 -0
  43. data/lib/rdkit/server.rb +242 -86
  44. data/lib/rdkit/simple_commands.rb +17 -0
  45. data/lib/rdkit/slow_log.rb +52 -0
  46. data/lib/rdkit/subcommands.rb +157 -0
  47. data/lib/rdkit/version.rb +1 -1
  48. data/rdkit.gemspec +6 -0
  49. metadata +119 -5
  50. data/lib/rdkit/inheritable.rb +0 -15
  51. data/lib/rdkit/resp_runner.rb +0 -46
@@ -0,0 +1,28 @@
1
+ module Blocking
2
+ class CommandRunner < RDKit::RESPRunner
3
+ attr_reader :core
4
+
5
+ def initialize(core)
6
+ @core = core
7
+ end
8
+
9
+ def block_with_callback
10
+ core.block_with_callback
11
+
12
+ # this is ignored, instead `on_success` block of `core.block_with_callback` is evaluated and returned
13
+ 'OK'
14
+ end
15
+
16
+ def block
17
+ core.block
18
+
19
+ 'OK'
20
+ end
21
+
22
+ def nonblock
23
+ core.nonblock
24
+
25
+ 'OK'
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,24 @@
1
+ module Blocking
2
+ class Core < RDKit::Core
3
+ def block_with_callback
4
+ on_success = lambda { 'success' }
5
+
6
+ server.blocking(on_success) { do_something }
7
+ end
8
+
9
+ def block
10
+ server.blocking { do_something }
11
+ end
12
+
13
+ def nonblock
14
+ do_something
15
+ end
16
+
17
+ def do_something
18
+ sleep 1
19
+ end
20
+
21
+ def tick!
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,10 @@
1
+ module Blocking
2
+ class Server < RDKit::Server
3
+ def initialize
4
+ super('0.0.0.0', 3721)
5
+
6
+ @core = Core.new
7
+ @runner = CommandRunner.new(core)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ module Blocking
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'rdkit'
2
+
3
+ require_relative 'callbacks/core'
4
+ require_relative 'callbacks/command_runner'
5
+ require_relative 'callbacks/server'
6
+
7
+ server = Callbacks::Server.new
8
+
9
+ server.start
@@ -0,0 +1,21 @@
1
+ module Callbacks
2
+ class CommandRunner < RDKit::RESPRunner
3
+ attr_reader :core
4
+
5
+ def initialize(core)
6
+ @core = core
7
+ end
8
+
9
+ def block
10
+ core.block
11
+
12
+ 'OK'
13
+ end
14
+
15
+ def nonblock
16
+ core.nonblock
17
+
18
+ 'OK'
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ module Callbacks
2
+ class Core < RDKit::Core
3
+ def block
4
+ server.blocking { do_something }
5
+ end
6
+
7
+ def nonblock
8
+ do_something
9
+ end
10
+
11
+ def do_something
12
+ sleep(rand)
13
+ end
14
+
15
+ def tick!
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ module Callbacks
2
+ class Server < RDKit::Server
3
+ def initialize
4
+ super('0.0.0.0', 3721)
5
+
6
+ @core = Core.new
7
+ @runner = CommandRunner.new(core)
8
+ end
9
+
10
+ def client_connected(client)
11
+ puts "client_connected: #{client.id}"
12
+ end
13
+
14
+ def client_disconnected(client)
15
+ puts "client_disconnected: #{client.id}"
16
+ end
17
+
18
+ def client_command_processed(client)
19
+ puts "client_command_processed: #{client.id}"
20
+ end
21
+
22
+ def client_block_resumed(client)
23
+ puts "client_block_resumed: #{client.id}"
24
+ end
25
+
26
+ def client_blocked(client)
27
+ puts "client_blocked: #{client.id}"
28
+ end
29
+ end
30
+ end
data/example/counter.rb CHANGED
@@ -7,6 +7,4 @@ require_relative 'counter/server'
7
7
 
8
8
  server = Counter::Server.new
9
9
 
10
- trap(:INT) { server.stop }
11
-
12
10
  server.start
@@ -12,5 +12,9 @@ module Counter
12
12
  def incr(n=1)
13
13
  @counter.incr(n.to_i)
14
14
  end
15
+
16
+ def add(*elements)
17
+ @counter.add(elements.map(&:to_i))
18
+ end
15
19
  end
16
20
  end
@@ -11,6 +11,10 @@ module Counter
11
11
  @count += n
12
12
  end
13
13
 
14
+ def add(elements)
15
+ @count += elements.inject(&:+)
16
+ end
17
+
14
18
  ###########################################
15
19
  # overriding required RDKit::Core methods
16
20
  ###########################################
data/example/http.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'rdkit'
2
+
3
+ require_relative 'http/core'
4
+ require_relative 'http/responder'
5
+ require_relative 'http/server'
6
+
7
+ server = HTTP::Server.new
8
+
9
+ server.start
@@ -0,0 +1,18 @@
1
+ module HTTP
2
+ class Core < RDKit::Core
3
+ def initialize
4
+ @last_tick = Time.now
5
+ end
6
+
7
+ # `tick!` is called periodically by RDKit
8
+ def tick!
9
+ @last_tick = Time.now
10
+ end
11
+
12
+ def introspection
13
+ {
14
+ last_tick: @last_tick
15
+ }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module HTTP
2
+ class Responder < RDKit::HTTPResponder
3
+ get '/hello' do
4
+ [200, {}, ['OK']]
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ module HTTP
2
+ class Server < RDKit::Server
3
+ def initialize
4
+ super('0.0.0.0', 3721)
5
+
6
+ # @core is required by RDKit
7
+ @core = Core.new
8
+
9
+ # @responder is also required by RDKit
10
+ @responder = Responder.new
11
+
12
+ @parser_class = RDKit::HTTPParser
13
+ end
14
+
15
+ def introspection
16
+ super.merge(counter: @core.introspection)
17
+ end
18
+ end
19
+ end
data/lib/rdkit.rb CHANGED
@@ -1,10 +1,27 @@
1
1
  require_relative 'rdkit/version'
2
+ require_relative 'rdkit/core_ext'
2
3
  require_relative 'rdkit/errors'
4
+ require_relative 'rdkit/configuration'
5
+ require_relative 'rdkit/notification_center'
6
+ require_relative 'rdkit/slow_log'
3
7
  require_relative 'rdkit/resp'
4
8
  require_relative 'rdkit/logger'
5
9
  require_relative 'rdkit/introspection'
6
- require_relative 'rdkit/inheritable'
7
10
  require_relative 'rdkit/core'
8
- require_relative 'rdkit/command_parser'
9
- require_relative 'rdkit/resp_runner'
11
+
12
+ require_relative 'rdkit/resp_parser'
13
+ require_relative 'rdkit/http_parser'
14
+
15
+ require_relative 'rdkit/simple_commands'
16
+ require_relative 'rdkit/rd_object'
17
+ require_relative 'rdkit/db_commands'
18
+ require_relative 'rdkit/subcommands'
19
+
20
+ require_relative 'rdkit/resp_responder'
21
+ require_relative 'rdkit/http_responder'
22
+
23
+ require_relative 'rdkit/client'
24
+ require_relative 'rdkit/memory_monitoring'
25
+ require_relative 'rdkit/db'
26
+ require_relative 'rdkit/callbacks'
10
27
  require_relative 'rdkit/server'
@@ -0,0 +1,10 @@
1
+ module RDKit
2
+ module Callbacks
3
+ def server_started; end
4
+ def client_connected(client); end
5
+ def client_disconnected(client); end
6
+ def client_command_processed(client); end
7
+ def client_block_resumed(client); end
8
+ def client_blocked(client); end
9
+ end
10
+ end
@@ -0,0 +1,157 @@
1
+ require 'thread/future'
2
+
3
+ module RDKit
4
+ class Client
5
+ attr_accessor :id
6
+ attr_accessor :name
7
+ attr_accessor :fd
8
+ attr_accessor :last_command
9
+ attr_reader :socket
10
+
11
+ def initialize(socket, server)
12
+ @server = server
13
+ @socket = socket
14
+ @responder = server.responder
15
+ @command_parser = server.parser_class.new
16
+ @logger = server.logger
17
+ @created_at = Time.now
18
+ @last_interacted_at = Time.now
19
+
20
+ @fiber = Fiber.new do
21
+ with_error_handling(socket) do |io|
22
+ loop { process; Fiber.yield }
23
+ end
24
+ end
25
+ end
26
+
27
+ def resume
28
+ @last_interacted_at = Time.now
29
+
30
+ @fiber.resume
31
+ end
32
+
33
+ def blocking(on_success=nil, &block)
34
+ @blocked_at = Time.now
35
+
36
+ @on_block_success = on_success
37
+
38
+ @future = Thread.future(@server.pool) { block.call }
39
+ end
40
+
41
+ def finished?
42
+ @future.delivered?
43
+ end
44
+
45
+ def unblock!
46
+ Introspection::Commandstats.record("bg_#{last_command}", ((Time.now - @blocked_at) * 1_000_000).to_i)
47
+
48
+ @blocked_at = nil
49
+
50
+ @server.client_block_resumed(self)
51
+ @fiber.resume
52
+ end
53
+
54
+ def info
55
+ {
56
+ id: @id,
57
+ addr: socket_addr,
58
+ fd: @socket.fileno,
59
+ name: @name,
60
+ age: age,
61
+ idle: idle,
62
+ cmd: @last_command
63
+ }
64
+ end
65
+
66
+ def socket_addr
67
+ @socket.remote_address.inspect_sockaddr
68
+ end
69
+
70
+ def name=(name)
71
+ # http://www.asciitable.com
72
+ # `networking.c` in redis source code
73
+ name.each_char { |c| raise IllegalClientNameError unless c >= '!' && c <= '~' }
74
+
75
+ @name = name
76
+ end
77
+
78
+ def kill!
79
+ @socket.close
80
+ @server.delete(@socket)
81
+ end
82
+
83
+ private
84
+
85
+ def age
86
+ (Time.now - @created_at).to_i
87
+ end
88
+
89
+ def idle
90
+ (Time.now - @last_interacted_at).to_i
91
+ end
92
+
93
+ def with_error_handling(socket, &block)
94
+
95
+ block.call(socket)
96
+
97
+ rescue IOError, Errno::ECONNRESET, EOFError => e
98
+ # client disconnected
99
+ @logger.debug "client #{socket.inspect} has disconnected"
100
+ @logger.debug e
101
+
102
+ raise ClientDisconnectedError
103
+ rescue ProtocolError => e
104
+ # client protocol error, force disconnect
105
+ @logger.debug "client protocol error"
106
+ @logger.debug e
107
+
108
+ raise ClientDisconnectedError
109
+ end
110
+
111
+ def process
112
+ feed_parser
113
+
114
+ until (reply = get_parser_reply) == false
115
+ execute_and_send_response(reply)
116
+ end
117
+ end
118
+
119
+ def feed_parser
120
+ cmd = @socket.readpartial(1024)
121
+
122
+ Introspection::Stats.incr(:total_net_input_bytes, cmd.bytesize)
123
+
124
+ @command_parser.feed(cmd)
125
+ end
126
+
127
+ def get_parser_reply
128
+ @command_parser.gets
129
+ end
130
+
131
+ def execute_and_send_response(cmd)
132
+ @last_command = cmd.first
133
+
134
+ @server.monitors.each do |client|
135
+ msg = "+#{Time.now.to_f} [#{socket_addr}] #{ cmd.map { |c| %Q{"#{c}"}}.join(' ') }\r\n"
136
+
137
+ client.socket.write(msg)
138
+ end
139
+
140
+ resp, usec = SlowLog.monitor(cmd) { @responder.run(cmd) }
141
+
142
+ if @blocked_at
143
+ @server.client_blocked(self)
144
+ Fiber.yield
145
+
146
+ resp = @responder.run(@on_block_success) if @on_block_success
147
+ end
148
+
149
+ Introspection::Commandstats.record(cmd.first, usec)
150
+ Introspection::Stats.incr(:total_net_output_bytes, resp.bytesize)
151
+
152
+ @logger.debug(resp)
153
+
154
+ @socket.write(resp)
155
+ end
156
+ end
157
+ end