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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/Gemfile +10 -1
- data/Gemfile.ci +13 -0
- data/Guardfile +40 -0
- data/README.md +282 -6
- data/Vagrantfile +13 -0
- data/example/blocking.rb +10 -0
- data/example/blocking/command_runner.rb +28 -0
- data/example/blocking/core.rb +24 -0
- data/example/blocking/server.rb +10 -0
- data/example/blocking/version.rb +3 -0
- data/example/callbacks.rb +9 -0
- data/example/callbacks/command_runner.rb +21 -0
- data/example/callbacks/core.rb +18 -0
- data/example/callbacks/server.rb +30 -0
- data/example/counter.rb +0 -2
- data/example/counter/command_runner.rb +4 -0
- data/example/counter/core.rb +4 -0
- data/example/http.rb +9 -0
- data/example/http/core.rb +18 -0
- data/example/http/responder.rb +7 -0
- data/example/http/server.rb +19 -0
- data/lib/rdkit.rb +20 -3
- data/lib/rdkit/callbacks.rb +10 -0
- data/lib/rdkit/client.rb +157 -0
- data/lib/rdkit/configuration.rb +31 -0
- data/lib/rdkit/core.rb +2 -4
- data/lib/rdkit/core_ext.rb +7 -0
- data/lib/rdkit/db.rb +257 -0
- data/lib/rdkit/db_commands.rb +182 -0
- data/lib/rdkit/errors.rb +32 -1
- data/lib/rdkit/http_parser.rb +56 -0
- data/lib/rdkit/http_responder.rb +74 -0
- data/lib/rdkit/introspection.rb +133 -21
- data/lib/rdkit/logger.rb +9 -4
- data/lib/rdkit/memory_monitoring.rb +29 -0
- data/lib/rdkit/notification_center.rb +21 -0
- data/lib/rdkit/rd_object.rb +69 -0
- data/lib/rdkit/resp.rb +9 -1
- data/lib/rdkit/{command_parser.rb → resp_parser.rb} +6 -18
- data/lib/rdkit/resp_responder.rb +105 -0
- data/lib/rdkit/server.rb +242 -86
- data/lib/rdkit/simple_commands.rb +17 -0
- data/lib/rdkit/slow_log.rb +52 -0
- data/lib/rdkit/subcommands.rb +157 -0
- data/lib/rdkit/version.rb +1 -1
- data/rdkit.gemspec +6 -0
- metadata +119 -5
- data/lib/rdkit/inheritable.rb +0 -15
- data/lib/rdkit/resp_runner.rb +0 -46
data/lib/rdkit/errors.rb
CHANGED
@@ -1,9 +1,40 @@
|
|
1
1
|
module RDKit
|
2
2
|
class RDKitError < StandardError; end
|
3
3
|
|
4
|
+
class WrongTypeError < RDKitError
|
5
|
+
def self.exception; new('Operation against a key holding the wrong kind of value'); end
|
6
|
+
end
|
7
|
+
|
4
8
|
class ProtocolError < RDKitError; end
|
5
9
|
class UnknownCommandError < ProtocolError; end
|
6
|
-
|
10
|
+
|
11
|
+
class SyntaxError < ProtocolError
|
12
|
+
def self.exception; new('syntax error'); end
|
13
|
+
end
|
14
|
+
|
15
|
+
class UnknownSubcommandError < ProtocolError; end
|
16
|
+
class WrongNumberOfArgumentForSubcommandError < ProtocolError; end
|
17
|
+
|
18
|
+
class IllegalArgumentError < ProtocolError; end
|
19
|
+
|
20
|
+
class InvalidDBIndexError < IllegalArgumentError
|
21
|
+
def self.exception; new('invalid DB index'); end
|
22
|
+
end
|
23
|
+
|
24
|
+
class WrongNumberOfArgumentError < IllegalArgumentError; end
|
25
|
+
|
26
|
+
class IllegalClientNameError < IllegalArgumentError
|
27
|
+
def self.exception; new('Client names cannot contain spaces, newlines or special characters.'); end
|
28
|
+
end
|
29
|
+
|
30
|
+
class ValueNotAnIntegerOrOutOfRangeError < IllegalArgumentError
|
31
|
+
def self.exception; new('value is not an integer or out of range'); end
|
32
|
+
end
|
33
|
+
|
34
|
+
class ClientDisconnectedError < RDKitError; end
|
35
|
+
class NoSuchClientError < RDKitError
|
36
|
+
def self.exception; new('No such client'); end
|
37
|
+
end
|
7
38
|
|
8
39
|
class NotImplementedError < RDKitError; end
|
9
40
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'http/parser'
|
2
|
+
|
3
|
+
module RDKit
|
4
|
+
class HTTPParser
|
5
|
+
def initialize
|
6
|
+
@parser = HTTP::Parser.new
|
7
|
+
|
8
|
+
@responses = []
|
9
|
+
|
10
|
+
# https://github.com/tmm1/http_parser.rb
|
11
|
+
|
12
|
+
@body = nil
|
13
|
+
|
14
|
+
@parser.on_message_begin = proc do
|
15
|
+
end
|
16
|
+
|
17
|
+
@parser.on_headers_complete = proc do
|
18
|
+
# p @parser.http_method
|
19
|
+
# p @parser.request_url
|
20
|
+
# p @parser.headers
|
21
|
+
|
22
|
+
if (length = @parser.headers['Content-Length']) && length.to_i > 0
|
23
|
+
@body = ''
|
24
|
+
else
|
25
|
+
@responses << [@parser.http_method.downcase + "|" + @parser.request_url, nil]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
@parser.on_body = proc do |chunk|
|
30
|
+
@body << chunk
|
31
|
+
end
|
32
|
+
|
33
|
+
@parser.on_message_complete = proc do
|
34
|
+
# Headers and body is all parsed
|
35
|
+
if @body
|
36
|
+
@responses << [@parser.http_method.downcase + "|" + @parser.request_url, @body]
|
37
|
+
|
38
|
+
@body = nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def feed(data)
|
44
|
+
@parser << data
|
45
|
+
end
|
46
|
+
|
47
|
+
def gets
|
48
|
+
if result = @responses.shift
|
49
|
+
|
50
|
+
result
|
51
|
+
else
|
52
|
+
false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'http/parser'
|
2
|
+
require 'cgi'
|
3
|
+
require 'rack'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
module RDKit
|
7
|
+
class HTTPResponder
|
8
|
+
def run(cmd)
|
9
|
+
method, path = cmd.first.split('|')
|
10
|
+
|
11
|
+
status, headers, body = case method
|
12
|
+
when 'get'
|
13
|
+
if @@endpoints_get[path]
|
14
|
+
status, headers, body = @@endpoints_get[path].call
|
15
|
+
|
16
|
+
[status, headers.merge(default_headers), body]
|
17
|
+
else
|
18
|
+
error_404
|
19
|
+
end
|
20
|
+
else
|
21
|
+
error_404
|
22
|
+
end
|
23
|
+
|
24
|
+
response = Rack::Response.new(body, status, headers)
|
25
|
+
|
26
|
+
status, headers, body = response.finish
|
27
|
+
|
28
|
+
out = StringIO.new
|
29
|
+
|
30
|
+
out.print "HTTP/1.1: #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]}\r\n"
|
31
|
+
|
32
|
+
headers.each do |k, vs|
|
33
|
+
vs.split("\n").each { |v| out.print "#{k}: #{v}\r\n"; }
|
34
|
+
end
|
35
|
+
out.print "\r\n"
|
36
|
+
out.flush
|
37
|
+
|
38
|
+
body.each do |part|
|
39
|
+
out.print part; out.flush
|
40
|
+
end
|
41
|
+
|
42
|
+
out.string
|
43
|
+
end
|
44
|
+
|
45
|
+
def server
|
46
|
+
Server.instance
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def error_400
|
52
|
+
[400, default_headers, []]
|
53
|
+
end
|
54
|
+
|
55
|
+
def error_404
|
56
|
+
[404, default_headers, ['Not Found']]
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_headers
|
60
|
+
{
|
61
|
+
"Date" => CGI.rfc1123_date(Time.now),
|
62
|
+
"Server" => "RDKit",
|
63
|
+
"Connection" => "Keep-Alive",
|
64
|
+
"Content-Type" => "text/plain"
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.get(path, &block)
|
69
|
+
@@endpoints_get ||= {}
|
70
|
+
|
71
|
+
@@endpoints_get[path] = block
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/rdkit/introspection.rb
CHANGED
@@ -1,45 +1,96 @@
|
|
1
1
|
# 127.0.0.1:6379> info
|
2
2
|
# # Server
|
3
|
-
# redis_version:
|
3
|
+
# redis_version:3.0.0
|
4
4
|
# redis_git_sha1:00000000
|
5
5
|
# redis_git_dirty:0
|
6
|
-
# redis_build_id:
|
6
|
+
# redis_build_id:c8fc3cfae8617ea3
|
7
7
|
# redis_mode:standalone
|
8
|
-
# os:Darwin
|
8
|
+
# os:Darwin 14.3.0 x86_64
|
9
9
|
# arch_bits:64
|
10
10
|
# multiplexing_api:kqueue
|
11
11
|
# gcc_version:4.2.1
|
12
|
-
# process_id:
|
13
|
-
# run_id:
|
12
|
+
# process_id:6503
|
13
|
+
# run_id:42575aa7185796a6a5e5addc5991a54e4baaf95e
|
14
14
|
# tcp_port:6379
|
15
|
-
# uptime_in_seconds:
|
16
|
-
# uptime_in_days:
|
15
|
+
# uptime_in_seconds:165102
|
16
|
+
# uptime_in_days:1
|
17
17
|
# hz:10
|
18
|
+
# lru_clock:7932005
|
19
|
+
# config_file:/usr/local/etc/redis.conf
|
18
20
|
#
|
19
21
|
# # Clients
|
20
22
|
# connected_clients:1
|
21
23
|
# client_longest_output_list:0
|
22
24
|
# client_biggest_input_buf:0
|
25
|
+
# blocked_clients:0
|
23
26
|
#
|
24
27
|
# # Memory
|
25
|
-
# used_memory:
|
26
|
-
# used_memory_human:
|
27
|
-
# used_memory_rss:
|
28
|
-
# used_memory_peak:
|
29
|
-
# used_memory_peak_human:
|
30
|
-
# used_memory_lua:
|
31
|
-
# mem_fragmentation_ratio:
|
28
|
+
# used_memory:1009568
|
29
|
+
# used_memory_human:985.91K
|
30
|
+
# used_memory_rss:1728512
|
31
|
+
# used_memory_peak:3486144
|
32
|
+
# used_memory_peak_human:3.32M
|
33
|
+
# used_memory_lua:35840
|
34
|
+
# mem_fragmentation_ratio:1.71
|
32
35
|
# mem_allocator:libc
|
33
36
|
#
|
34
37
|
# # Persistence
|
38
|
+
# loading:0
|
39
|
+
# rdb_changes_since_last_save:0
|
40
|
+
# rdb_bgsave_in_progress:0
|
41
|
+
# rdb_last_save_time:1433995353
|
42
|
+
# rdb_last_bgsave_status:ok
|
43
|
+
# rdb_last_bgsave_time_sec:0
|
44
|
+
# rdb_current_bgsave_time_sec:-1
|
45
|
+
# aof_enabled:0
|
46
|
+
# aof_rewrite_in_progress:0
|
47
|
+
# aof_rewrite_scheduled:0
|
48
|
+
# aof_last_rewrite_time_sec:-1
|
49
|
+
# aof_current_rewrite_time_sec:-1
|
50
|
+
# aof_last_bgrewrite_status:ok
|
51
|
+
# aof_last_write_status:ok
|
35
52
|
#
|
36
53
|
# # Stats
|
37
|
-
# total_connections_received:
|
38
|
-
# total_commands_processed:
|
54
|
+
# total_connections_received:98
|
55
|
+
# total_commands_processed:265
|
39
56
|
# instantaneous_ops_per_sec:0
|
57
|
+
# total_net_input_bytes:273320
|
58
|
+
# total_net_output_bytes:1024738
|
59
|
+
# instantaneous_input_kbps:0.00
|
60
|
+
# instantaneous_output_kbps:0.00
|
40
61
|
# rejected_connections:0
|
62
|
+
# sync_full:0
|
63
|
+
# sync_partial_ok:0
|
64
|
+
# sync_partial_err:0
|
65
|
+
# expired_keys:0
|
66
|
+
# evicted_keys:0
|
67
|
+
# keyspace_hits:28
|
68
|
+
# keyspace_misses:11
|
41
69
|
# pubsub_channels:0
|
42
70
|
# pubsub_patterns:0
|
71
|
+
# latest_fork_usec:483
|
72
|
+
# migrate_cached_sockets:0
|
73
|
+
#
|
74
|
+
# # Replication
|
75
|
+
# role:master
|
76
|
+
# connected_slaves:0
|
77
|
+
# master_repl_offset:0
|
78
|
+
# repl_backlog_active:0
|
79
|
+
# repl_backlog_size:1048576
|
80
|
+
# repl_backlog_first_byte_offset:0
|
81
|
+
# repl_backlog_histlen:0
|
82
|
+
#
|
83
|
+
# # CPU
|
84
|
+
# used_cpu_sys:34.00
|
85
|
+
# used_cpu_user:13.61
|
86
|
+
# used_cpu_sys_children:0.05
|
87
|
+
# used_cpu_user_children:0.11
|
88
|
+
#
|
89
|
+
# # Cluster
|
90
|
+
# cluster_enabled:0
|
91
|
+
#
|
92
|
+
# # Keyspace
|
93
|
+
# db0:keys=3,expires=0,avg_ttl=0
|
43
94
|
|
44
95
|
module RDKit
|
45
96
|
module Introspection
|
@@ -48,15 +99,18 @@ module RDKit
|
|
48
99
|
|
49
100
|
def initialize
|
50
101
|
@data = {}
|
51
|
-
|
52
102
|
@data.default = 0
|
53
103
|
end
|
54
104
|
|
55
105
|
module ClassMethods
|
56
106
|
@@instance = Stats.new
|
57
107
|
|
58
|
-
def incr(key)
|
59
|
-
@@instance.data[key] +=
|
108
|
+
def incr(key, amount=1)
|
109
|
+
@@instance.data[key] += amount
|
110
|
+
end
|
111
|
+
|
112
|
+
def clear(key)
|
113
|
+
@@instance.data[key] = 0
|
60
114
|
end
|
61
115
|
|
62
116
|
def info
|
@@ -67,13 +121,71 @@ module RDKit
|
|
67
121
|
class << self; include ClassMethods; end
|
68
122
|
end
|
69
123
|
|
124
|
+
class Commandstats
|
125
|
+
attr_reader :data
|
126
|
+
|
127
|
+
def initialize
|
128
|
+
@data = {}
|
129
|
+
@data.default = 0
|
130
|
+
end
|
131
|
+
|
132
|
+
module ClassMethods
|
133
|
+
@@instance = Commandstats.new
|
134
|
+
|
135
|
+
def reset
|
136
|
+
@@instance = Commandstats.new
|
137
|
+
end
|
138
|
+
|
139
|
+
def record(cmd, usec)
|
140
|
+
@@instance.data["#{cmd.downcase}_calls"] += 1
|
141
|
+
@@instance.data["#{cmd.downcase}_usec"] += usec
|
142
|
+
end
|
143
|
+
|
144
|
+
def info
|
145
|
+
cmds = @@instance.data.keys.map { |key| key.match(/^(.+)_/)[1] }.uniq
|
146
|
+
|
147
|
+
Hash[cmds.map do |cmd|
|
148
|
+
calls = @@instance.data["#{cmd}_calls"]
|
149
|
+
usec = @@instance.data["#{cmd}_usec"]
|
150
|
+
|
151
|
+
["comstat_#{cmd}", "calls=#{calls},usec=#{usec},usec_per_call=#{'%.2f' % (usec.to_f / calls)}"]
|
152
|
+
end].sort_by { |k,v| k }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class << self; include ClassMethods; end
|
157
|
+
end
|
158
|
+
|
70
159
|
module ClassMethods
|
71
160
|
def register(server)
|
72
161
|
@@server = server
|
73
162
|
end
|
74
163
|
|
75
|
-
def info
|
76
|
-
@@server.introspection.merge({ stats: Stats.info })
|
164
|
+
def info(section)
|
165
|
+
default = @@server.introspection.merge({ stats: Stats.info })
|
166
|
+
|
167
|
+
case section.downcase
|
168
|
+
when 'default'
|
169
|
+
default
|
170
|
+
when 'all'
|
171
|
+
default.merge({ commandstats: Commandstats.info, gc: GC.stat, objspace: ObjectSpace.count_objects, allobjects: all_objects })
|
172
|
+
when 'commandstats'
|
173
|
+
{ commandstats: Commandstats.info }
|
174
|
+
when 'gc'
|
175
|
+
{ gc: GC.stat }
|
176
|
+
when 'objspace'
|
177
|
+
{ objspace: ObjectSpace.count_objects, allobjects: all_objects }
|
178
|
+
else
|
179
|
+
default.keep_if { |k, v| k == section.downcase.to_sym }
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def all_objects
|
186
|
+
all = {}
|
187
|
+
ObjectSpace.each_object { |o| all[o.class] = (all[o.class] || 0) + 1 }
|
188
|
+
all.sort_by { |k,v| -v }
|
77
189
|
end
|
78
190
|
end
|
79
191
|
|
data/lib/rdkit/logger.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module RDKit
|
2
2
|
class Logger
|
3
|
+
def initialize(log_path=nil)
|
4
|
+
@io = log_path ? File.open(log_path, 'a') : $stdout
|
5
|
+
end
|
6
|
+
|
3
7
|
def debug(message)
|
4
8
|
return unless $DEBUG && ENV['RACK_ENV'] != 'test'
|
5
9
|
|
@@ -16,12 +20,13 @@ module RDKit
|
|
16
20
|
|
17
21
|
def log(message)
|
18
22
|
case message
|
19
|
-
when
|
20
|
-
puts message.inspect
|
21
|
-
puts message.backtrace.join("\n")
|
23
|
+
when Exception
|
24
|
+
@io.puts message.inspect
|
25
|
+
@io.puts message.backtrace.join("\n")
|
22
26
|
else
|
23
|
-
puts message
|
27
|
+
@io.puts message
|
24
28
|
end
|
29
|
+
@io.flush
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'newrelic_rpm'
|
2
|
+
|
3
|
+
module RDKit
|
4
|
+
module MemoryMonitoring
|
5
|
+
@@peak_memory = 0
|
6
|
+
|
7
|
+
def used_memory_rss_in_mb
|
8
|
+
update_peak_memory!
|
9
|
+
|
10
|
+
'%0.2f' % used_memory_rss + 'M'
|
11
|
+
end
|
12
|
+
|
13
|
+
def used_memory_peak_in_mb
|
14
|
+
'%0.2f' % @@peak_memory + 'M'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def update_peak_memory!
|
20
|
+
@@peak_memory = [@@peak_memory, used_memory_rss].max
|
21
|
+
end
|
22
|
+
|
23
|
+
def used_memory_rss
|
24
|
+
@@sampler ||= NewRelic::Agent::Samplers::MemorySampler.new.sampler
|
25
|
+
|
26
|
+
@@sampler.get_sample
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RDKit
|
2
|
+
class NotificationCenter
|
3
|
+
module ClassMethods
|
4
|
+
@@channels = {}
|
5
|
+
@@channels.default = Hash.new
|
6
|
+
|
7
|
+
def publish(channel, message)
|
8
|
+
@@channels[channel.to_sym].each { |_, block| block.call(message) }
|
9
|
+
end
|
10
|
+
|
11
|
+
def subscribe(channel, client, &block)
|
12
|
+
@@channels[channel.to_sym][client] = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def unsubscribe(channel, client)
|
16
|
+
@@channels[channel.to_sym].delete(client)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
class << self; include ClassMethods; end
|
20
|
+
end
|
21
|
+
end
|