dharmarth-starling 0.9.9
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.
- data/CHANGELOG +56 -0
- data/LICENSE +20 -0
- data/README.rdoc +106 -0
- data/Rakefile +56 -0
- data/bin/starling +6 -0
- data/bin/starling_top +57 -0
- data/etc/sample-config.yml +9 -0
- data/etc/starling.redhat +66 -0
- data/etc/starling.ubuntu +71 -0
- data/lib/starling.rb +181 -0
- data/lib/starling/handler.rb +237 -0
- data/lib/starling/persistent_queue.rb +156 -0
- data/lib/starling/queue_collection.rb +147 -0
- data/lib/starling/server.rb +125 -0
- data/lib/starling/server_runner.rb +317 -0
- data/spec/starling_server_spec.rb +216 -0
- metadata +107 -0
@@ -0,0 +1,216 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'memcache'
|
6
|
+
require 'digest/md5'
|
7
|
+
require 'starling'
|
8
|
+
|
9
|
+
require 'starling/server'
|
10
|
+
|
11
|
+
class StarlingServer::PersistentQueue
|
12
|
+
remove_const :SOFT_LOG_MAX_SIZE
|
13
|
+
SOFT_LOG_MAX_SIZE = 16 * 1024 # 16 KB
|
14
|
+
end
|
15
|
+
|
16
|
+
def safely_fork(&block)
|
17
|
+
# anti-race juice:
|
18
|
+
blocking = true
|
19
|
+
Signal.trap("USR1") { blocking = false }
|
20
|
+
|
21
|
+
pid = Process.fork(&block)
|
22
|
+
|
23
|
+
while blocking
|
24
|
+
sleep 0.1
|
25
|
+
end
|
26
|
+
|
27
|
+
pid
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "StarlingServer" do
|
31
|
+
before do
|
32
|
+
@tmp_path = File.join(File.dirname(__FILE__), "tmp")
|
33
|
+
|
34
|
+
begin
|
35
|
+
Dir::mkdir(@tmp_path)
|
36
|
+
rescue Errno::EEXIST
|
37
|
+
end
|
38
|
+
|
39
|
+
@server_pid = safely_fork do
|
40
|
+
server = StarlingServer::Base.new(:host => '127.0.0.1',
|
41
|
+
:port => 22133,
|
42
|
+
:path => @tmp_path,
|
43
|
+
:logger => Logger.new(STDERR),
|
44
|
+
:log_level => Logger::FATAL)
|
45
|
+
Signal.trap("INT") {
|
46
|
+
server.stop
|
47
|
+
exit
|
48
|
+
}
|
49
|
+
|
50
|
+
Process.kill("USR1", Process.ppid)
|
51
|
+
server.run
|
52
|
+
end
|
53
|
+
|
54
|
+
@client = MemCache.new('127.0.0.1:22133')
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should test if temp_path exists and is writeable" do
|
59
|
+
File.exist?(@tmp_path).should be_true
|
60
|
+
File.directory?(@tmp_path).should be_true
|
61
|
+
File.writable?(@tmp_path).should be_true
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should set and get" do
|
65
|
+
v = rand((2**32)-1)
|
66
|
+
@client.get('test_set_and_get_one_entry').should be_nil
|
67
|
+
@client.set('test_set_and_get_one_entry', v)
|
68
|
+
@client.get('test_set_and_get_one_entry').should eql(v)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should respond to delete" do
|
72
|
+
@client.delete("my_queue").should eql("END\r\n")
|
73
|
+
starling_client = Starling.new('127.0.0.1:22133')
|
74
|
+
starling_client.set('my_queue', 50)
|
75
|
+
starling_client.available_queues.size.should eql(1)
|
76
|
+
starling_client.delete("my_queue")
|
77
|
+
starling_client.available_queues.size.should eql(0)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should expire entries" do
|
81
|
+
v = rand((2**32)-1)
|
82
|
+
@client.get('test_set_with_expiry').should be_nil
|
83
|
+
now = Time.now.to_i
|
84
|
+
@client.set('test_set_with_expiry', v + 2, now)
|
85
|
+
@client.set('test_set_with_expiry', v)
|
86
|
+
sleep(1.0)
|
87
|
+
@client.get('test_set_with_expiry').should eql(v)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should have age stat" do
|
91
|
+
now = Time.now.to_i
|
92
|
+
@client.set('test_age', 'nibbler')
|
93
|
+
sleep(1.0)
|
94
|
+
@client.get('test_age').should eql('nibbler')
|
95
|
+
|
96
|
+
stats = @client.stats['127.0.0.1:22133']
|
97
|
+
stats.has_key?('queue_test_age_age').should be_true
|
98
|
+
(stats['queue_test_age_age'] >= 1000).should be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should rotate log" do
|
102
|
+
log_rotation_path = File.join(@tmp_path, 'test_log_rotation')
|
103
|
+
|
104
|
+
Dir.glob("#{log_rotation_path}*").each do |file|
|
105
|
+
File.unlink(file) rescue nil
|
106
|
+
end
|
107
|
+
@client.get('test_log_rotation').should be_nil
|
108
|
+
|
109
|
+
v = 'x' * 8192
|
110
|
+
|
111
|
+
@client.set('test_log_rotation', v)
|
112
|
+
File.size(log_rotation_path).should eql(8207)
|
113
|
+
@client.get('test_log_rotation')
|
114
|
+
|
115
|
+
@client.get('test_log_rotation').should be_nil
|
116
|
+
|
117
|
+
@client.set('test_log_rotation', v)
|
118
|
+
@client.get('test_log_rotation').should eql(v)
|
119
|
+
|
120
|
+
File.size(log_rotation_path).should eql(1)
|
121
|
+
# rotated log should be erased after a successful roll.
|
122
|
+
Dir.glob("#{log_rotation_path}*").size.should eql(1)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should output statistics per server" do
|
126
|
+
stats = @client.stats
|
127
|
+
assert_kind_of Hash, stats
|
128
|
+
assert stats.has_key?('127.0.0.1:22133')
|
129
|
+
|
130
|
+
server_stats = stats['127.0.0.1:22133']
|
131
|
+
|
132
|
+
basic_stats = %w( bytes pid time limit_maxbytes cmd_get version
|
133
|
+
bytes_written cmd_set get_misses total_connections
|
134
|
+
curr_connections curr_items uptime get_hits total_items
|
135
|
+
rusage_system rusage_user bytes_read )
|
136
|
+
|
137
|
+
basic_stats.each do |stat|
|
138
|
+
server_stats.has_key?(stat).should be_true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should return valid response with unkown command" do
|
143
|
+
response = @client.add('blah', 1)
|
144
|
+
response.should eql("CLIENT_ERROR bad command line format\r\n")
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should disconnect and reconnect again" do
|
148
|
+
v = rand(2**32-1)
|
149
|
+
@client.set('test_that_disconnecting_and_reconnecting_works', v)
|
150
|
+
@client.reset
|
151
|
+
@client.get('test_that_disconnecting_and_reconnecting_works').should eql(v)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should use epoll on linux" do
|
155
|
+
# this may take a few seconds.
|
156
|
+
# the point is to make sure that we're using epoll on Linux, so we can
|
157
|
+
# handle more than 1024 connections.
|
158
|
+
|
159
|
+
unless IO::popen("uname").read.chomp == "Linux"
|
160
|
+
pending "skipping epoll test: not on Linux"
|
161
|
+
end
|
162
|
+
|
163
|
+
fd_limit = IO::popen("bash -c 'ulimit -n'").read.chomp.to_i
|
164
|
+
unless fd_limit > 1024
|
165
|
+
pending "skipping epoll test: 'ulimit -n' = #{fd_limit}, need > 1024"
|
166
|
+
end
|
167
|
+
|
168
|
+
v = rand(2**32 - 1)
|
169
|
+
@client.set('test_epoll', v)
|
170
|
+
|
171
|
+
# we can't open 1024 connections to memcache from within this process,
|
172
|
+
# because we will hit ruby's 1024 fd limit ourselves!
|
173
|
+
pid1 = safely_fork do
|
174
|
+
unused_sockets = []
|
175
|
+
600.times do
|
176
|
+
unused_sockets << TCPSocket.new("127.0.0.1", 22133)
|
177
|
+
end
|
178
|
+
Process.kill("USR1", Process.ppid)
|
179
|
+
sleep 90
|
180
|
+
end
|
181
|
+
pid2 = safely_fork do
|
182
|
+
unused_sockets = []
|
183
|
+
600.times do
|
184
|
+
unused_sockets << TCPSocket.new("127.0.0.1", 22133)
|
185
|
+
end
|
186
|
+
Process.kill("USR1", Process.ppid)
|
187
|
+
sleep 90
|
188
|
+
end
|
189
|
+
|
190
|
+
begin
|
191
|
+
client = MemCache.new('127.0.0.1:22133')
|
192
|
+
client.get('test_epoll').should eql(v)
|
193
|
+
ensure
|
194
|
+
Process.kill("TERM", pid1)
|
195
|
+
Process.kill("TERM", pid2)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should raise error if queue collection is an invalid path" do
|
200
|
+
invalid_path = nil
|
201
|
+
while invalid_path.nil? || File.exist?(invalid_path)
|
202
|
+
invalid_path = File.join('/', Digest::MD5.hexdigest(rand(2**32-1).to_s)[0,8])
|
203
|
+
end
|
204
|
+
|
205
|
+
lambda {
|
206
|
+
StarlingServer::QueueCollection.new(invalid_path)
|
207
|
+
}.should raise_error(StarlingServer::InaccessibleQueuePath)
|
208
|
+
end
|
209
|
+
|
210
|
+
after do
|
211
|
+
Process.kill("INT", @server_pid)
|
212
|
+
Process.wait(@server_pid)
|
213
|
+
@client.reset
|
214
|
+
FileUtils.rm(Dir.glob(File.join(@tmp_path, '*')))
|
215
|
+
end
|
216
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dharmarth-starling
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.9.9
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Blaine Cook
|
8
|
+
- Chris Wanstrath
|
9
|
+
- Britt Selvitelle
|
10
|
+
- Glenn Rempe
|
11
|
+
- Abdul-Rahman Advany
|
12
|
+
- Seth Fitzsimmons
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2009-04-01 00:00:00 -07:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: fiveruns-memcache-client
|
22
|
+
type: :runtime
|
23
|
+
version_requirement:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: "0"
|
29
|
+
version:
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: eventmachine
|
32
|
+
type: :runtime
|
33
|
+
version_requirement:
|
34
|
+
version_requirements: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - ">="
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 0.12.0
|
39
|
+
version:
|
40
|
+
description: Starling is a lightweight, transactional, distributed queue server
|
41
|
+
email:
|
42
|
+
- blaine@twitter.com
|
43
|
+
- chris@ozmm.org
|
44
|
+
- abdulrahman@advany.com
|
45
|
+
- starlingmq@groups.google.com
|
46
|
+
executables:
|
47
|
+
- starling
|
48
|
+
- starling_top
|
49
|
+
extensions: []
|
50
|
+
|
51
|
+
extra_rdoc_files:
|
52
|
+
- README.rdoc
|
53
|
+
- CHANGELOG
|
54
|
+
- LICENSE
|
55
|
+
files:
|
56
|
+
- bin/starling
|
57
|
+
- bin/starling_top
|
58
|
+
- CHANGELOG
|
59
|
+
- etc/sample-config.yml
|
60
|
+
- etc/starling.redhat
|
61
|
+
- etc/starling.ubuntu
|
62
|
+
- lib/starling/handler.rb
|
63
|
+
- lib/starling/persistent_queue.rb
|
64
|
+
- lib/starling/queue_collection.rb
|
65
|
+
- lib/starling/server.rb
|
66
|
+
- lib/starling/server_runner.rb
|
67
|
+
- lib/starling.rb
|
68
|
+
- LICENSE
|
69
|
+
- Rakefile
|
70
|
+
- README.rdoc
|
71
|
+
- spec/starling_server_spec.rb
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/starling/starling/
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --quiet
|
77
|
+
- --title
|
78
|
+
- starling documentation
|
79
|
+
- --opname
|
80
|
+
- index.html
|
81
|
+
- --line-numbers
|
82
|
+
- --main
|
83
|
+
- README.rdoc
|
84
|
+
- --inline-source
|
85
|
+
require_paths:
|
86
|
+
- lib
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: "0"
|
92
|
+
version:
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: "0"
|
98
|
+
version:
|
99
|
+
requirements: []
|
100
|
+
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 1.2.0
|
103
|
+
signing_key:
|
104
|
+
specification_version: 2
|
105
|
+
summary: Starling is a lightweight, transactional, distributed queue server
|
106
|
+
test_files: []
|
107
|
+
|