conveyor 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +15 -0
- data/Manifest.txt +1 -0
- data/Rakefile +1 -0
- data/bin/conveyor-rebuild-index +14 -0
- data/lib/conveyor.rb +1 -1
- data/lib/conveyor/base_channel.rb +175 -80
- data/lib/conveyor/channel.rb +5 -10
- data/lib/conveyor/server.rb +7 -1
- data/test/test_channel.rb +11 -12
- data/test/test_replicated_channel.rb +8 -6
- data/test/test_server.rb +7 -3
- metadata +20 -4
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
== 0.2.3 / 2008-10-21
|
2
|
+
* update channel reading code for base-36
|
3
|
+
* adding logging to the server startup process
|
4
|
+
* new 2-level indexing scheme. only %10 of index items are held in memory
|
5
|
+
* 10x reduction in memory useage
|
6
|
+
* 1000x speedup in startup time
|
7
|
+
* added rack dependency
|
8
|
+
* index rebuilding script
|
9
|
+
* time the startup
|
10
|
+
* some performance improvements for index loading
|
11
|
+
* initial block caching strategy for lookups by id
|
12
|
+
* cache rejecting + dealing with an edge case on nearest_after
|
13
|
+
* refuse to open an index that isn't in sequential id order
|
14
|
+
* log http response code when channel already exists
|
15
|
+
|
1
16
|
== 0.2.2 / 2008-04-10
|
2
17
|
* make sure that an empty channel still has @last_id set
|
3
18
|
* switch back to mongrel. too many problems with event machine on solaris
|
data/Manifest.txt
CHANGED
data/Rakefile
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby -KU
|
2
|
+
|
3
|
+
$: << 'lib'
|
4
|
+
|
5
|
+
require 'conveyor/server'
|
6
|
+
require 'conveyor/upgrader'
|
7
|
+
|
8
|
+
if ARGV.first
|
9
|
+
FileUtils.mv(File.join(ARGV.first, 'index'), File.join(ARGV.first, 'index.bak'))
|
10
|
+
FileUtils.touch(File.join(ARGV.first, 'index'))
|
11
|
+
u = Conveyor::Channel.new ARGV.first
|
12
|
+
|
13
|
+
u.rebuild_index
|
14
|
+
end
|
data/lib/conveyor.rb
CHANGED
@@ -11,21 +11,42 @@ module Conveyor
|
|
11
11
|
# Base implementation for channels. Not useful to instantiate directly.
|
12
12
|
class BaseChannel
|
13
13
|
|
14
|
-
NAME_PATTERN
|
15
|
-
BUCKET_SIZE
|
16
|
-
FORMAT_VERSION =
|
14
|
+
NAME_PATTERN = %r{\A[a-zA-Z\-0-9\_]+\Z}
|
15
|
+
BUCKET_SIZE = 100_000
|
16
|
+
FORMAT_VERSION = 1
|
17
|
+
BLOCK_SIZE = 1000
|
18
|
+
CACHE_SIZE = 100
|
17
19
|
|
18
20
|
module Flags
|
19
21
|
GZIP = 1
|
20
22
|
end
|
21
23
|
|
24
|
+
def self.parse_headers str, index_file=false
|
25
|
+
id, time, offset, length, hash, flags, file = str.split ' '
|
26
|
+
{
|
27
|
+
:id => id.to_i(36),
|
28
|
+
:time => time.to_i(36),
|
29
|
+
:offset => offset.to_i(36),
|
30
|
+
:length => length.to_i(36),
|
31
|
+
:hash => hash,
|
32
|
+
:flags => flags.to_i(36),
|
33
|
+
:file => (index_file ? file.to_i(36) : nil)
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.valid_channel_name? name
|
38
|
+
!!name.match(NAME_PATTERN)
|
39
|
+
end
|
40
|
+
|
22
41
|
def initialize directory
|
23
|
-
@directory
|
24
|
-
@data_files
|
25
|
-
@file_mutexes
|
26
|
-
@
|
27
|
-
@
|
28
|
-
@
|
42
|
+
@directory = directory
|
43
|
+
@data_files = []
|
44
|
+
@file_mutexes = []
|
45
|
+
@iterator = 1 #TODO: move to Channel.rb
|
46
|
+
@id_lock = Mutex.new
|
47
|
+
@index_file_lock = Mutex.new
|
48
|
+
@block_cache = {}
|
49
|
+
@block_last_used = {}
|
29
50
|
|
30
51
|
if File.exists?(@directory)
|
31
52
|
if !File.directory?(@directory)
|
@@ -44,27 +65,6 @@ module Conveyor
|
|
44
65
|
"<#{self.class} dir:'#{@directory.to_s}' last_id:#{@last_id} iterator:#{@iterator}>"
|
45
66
|
end
|
46
67
|
|
47
|
-
def pick_bucket i
|
48
|
-
(i / BUCKET_SIZE).to_i
|
49
|
-
end
|
50
|
-
|
51
|
-
def bucket_file i
|
52
|
-
unless @data_files[i]
|
53
|
-
@data_files[i] = File.open(File.join(@directory, i.to_s), 'a+')
|
54
|
-
@data_files[i].sync = true
|
55
|
-
@file_mutexes[i] = Mutex.new
|
56
|
-
end
|
57
|
-
@file_mutexes[i].synchronize do
|
58
|
-
yield @data_files[i]
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def id_lock
|
63
|
-
@id_lock.synchronize do
|
64
|
-
yield
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
68
|
def commit data, time=nil
|
69
69
|
l = nil
|
70
70
|
gzip = data.length >= 256
|
@@ -84,7 +84,7 @@ module Conveyor
|
|
84
84
|
|
85
85
|
id_lock do
|
86
86
|
i = @last_id + 1
|
87
|
-
t = time || Time.now
|
87
|
+
t = time || Time.now.to_i
|
88
88
|
b = pick_bucket(i)
|
89
89
|
flags = 0
|
90
90
|
flags = flags | Flags::GZIP if gzip
|
@@ -99,20 +99,33 @@ module Conveyor
|
|
99
99
|
end
|
100
100
|
|
101
101
|
@last_id = i
|
102
|
-
|
103
|
-
|
102
|
+
index_offset = nil
|
103
|
+
index_file_lock do
|
104
|
+
@index_file.seek(0, IO::SEEK_END)
|
105
|
+
index_offset = @index_file.pos
|
106
|
+
@index_file.write "#{header} #{b.to_s(36)}\n"
|
107
|
+
end
|
108
|
+
block_num = block_num(i)
|
109
|
+
if !@blocks[block_num]
|
110
|
+
@blocks << {:offset => index_offset}
|
111
|
+
end
|
112
|
+
if @block_cache.key?(block_num)
|
113
|
+
@block_cache[block_num] << {:id => i, :time => t, :offset => o, :length => l, :hash => h, :file => b}
|
114
|
+
end
|
104
115
|
i
|
105
116
|
end
|
106
117
|
end
|
107
118
|
|
108
119
|
def get id, stream=false
|
109
120
|
return nil unless id <= @last_id && id > 0
|
110
|
-
|
121
|
+
|
122
|
+
index_entry = search_index(id)
|
123
|
+
|
111
124
|
headers, content, compressed_content, g = nil
|
112
|
-
bucket_file(
|
113
|
-
f.seek
|
114
|
-
headers = parse_headers(f.readline.strip)
|
115
|
-
compressed_content = f.read(
|
125
|
+
bucket_file(index_entry[:file]) do |f|
|
126
|
+
f.seek index_entry[:offset]
|
127
|
+
headers = self.class.parse_headers(f.readline.strip)
|
128
|
+
compressed_content = f.read(index_entry[:length])
|
116
129
|
end
|
117
130
|
io = StringIO.new(compressed_content)
|
118
131
|
if (headers[:flags] & Flags::GZIP) != 0
|
@@ -128,48 +141,89 @@ module Conveyor
|
|
128
141
|
end
|
129
142
|
|
130
143
|
def get_nearest_after_timestamp timestamp, stream=false
|
131
|
-
# i = binary search to find nearest item at or after timestamp
|
132
144
|
i = nearest_after(timestamp)
|
133
145
|
get(i) if i
|
134
146
|
end
|
135
147
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
148
|
+
def delete!
|
149
|
+
FileUtils.rm_r(@directory)
|
150
|
+
@data_files =[]
|
151
|
+
@last_id = 0
|
152
|
+
@blocks = []
|
153
|
+
end
|
154
|
+
|
155
|
+
def rebuild_index
|
156
|
+
files = Dir.glob(@directory + '/' + '[0-9]*')
|
157
|
+
files = files.map{|f| [f, f.split('/').last.to_i]}
|
158
|
+
files.sort!{|a,b| a[1] <=> b[1]}
|
159
|
+
files.each do |(f, b)|
|
160
|
+
File.open(f, 'r') do |file|
|
161
|
+
puts "reading #{f}"
|
162
|
+
while line = file.gets
|
163
|
+
headers = self.class.parse_headers(line.strip)
|
164
|
+
content = file.read(headers[:length])
|
165
|
+
file.read(1)
|
166
|
+
index_offset = nil
|
167
|
+
header = "#{headers[:id].to_s(36)} #{headers[:time].to_s(36)} #{headers[:offset].to_s(36)} #{headers[:length].to_s(36)} #{headers[:hash]} #{headers[:flags].to_s(36)}"
|
168
|
+
index_file_lock do
|
169
|
+
@index_file.seek(0, IO::SEEK_END)
|
170
|
+
index_offset = @index_file.pos
|
171
|
+
@index_file.write "#{header} #{b.to_s(36)}\n"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def status
|
141
179
|
{
|
142
|
-
:
|
143
|
-
:
|
144
|
-
:
|
145
|
-
:
|
146
|
-
:
|
147
|
-
:
|
148
|
-
:file => (index_file ? m.captures[6].to_i(36) : nil)
|
180
|
+
:directory => @directory,
|
181
|
+
:data_files => @data_files.collect{|f| {:path => f.path, :bytes => File.size(f.path)}},
|
182
|
+
:iterator => @iterator,
|
183
|
+
:block_cache_keys => @block_cache.keys,
|
184
|
+
:last_id => @last_id,
|
185
|
+
:blocks => @blocks.length,
|
149
186
|
}
|
150
187
|
end
|
151
188
|
|
152
|
-
|
153
|
-
|
189
|
+
protected
|
190
|
+
|
191
|
+
def block_num i
|
192
|
+
((i-1) / BLOCK_SIZE)
|
154
193
|
end
|
155
|
-
|
156
|
-
def
|
157
|
-
|
194
|
+
|
195
|
+
def pick_bucket i
|
196
|
+
(i / BUCKET_SIZE).to_i
|
158
197
|
end
|
159
198
|
|
160
|
-
def
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
199
|
+
def bucket_file i
|
200
|
+
unless @data_files[i]
|
201
|
+
@data_files[i] = File.open(File.join(@directory, i.to_s), 'a+')
|
202
|
+
@data_files[i].sync = true
|
203
|
+
@file_mutexes[i] = Mutex.new
|
204
|
+
end
|
205
|
+
@file_mutexes[i].synchronize do
|
206
|
+
yield @data_files[i]
|
207
|
+
end
|
165
208
|
end
|
166
209
|
|
167
|
-
|
210
|
+
def id_lock
|
211
|
+
@id_lock.synchronize do
|
212
|
+
yield
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def index_file_lock
|
217
|
+
@index_file_lock.synchronize do
|
218
|
+
yield
|
219
|
+
end
|
220
|
+
end
|
168
221
|
|
169
222
|
def setup_channel
|
170
|
-
@index_file = File.open(index_path, 'a')
|
223
|
+
@index_file = File.open(index_path, 'a+')
|
171
224
|
@last_id = 0
|
172
225
|
@version = FORMAT_VERSION
|
226
|
+
@blocks = []
|
173
227
|
File.open(version_path, 'w+'){|f| f.write(@version.to_s)}
|
174
228
|
end
|
175
229
|
|
@@ -185,16 +239,21 @@ module Conveyor
|
|
185
239
|
end
|
186
240
|
|
187
241
|
@index_file = File.open(index_path, 'r+')
|
188
|
-
|
242
|
+
@blocks = []
|
189
243
|
@last_id = 0
|
190
|
-
|
191
|
-
|
192
|
-
|
244
|
+
index_offset = 0
|
245
|
+
while line = @index_file.gets
|
246
|
+
entry = self.class.parse_headers(line.strip, true)
|
247
|
+
raise "corrupt index. try rebuilding." unless entry[:id] == @last_id + 1
|
248
|
+
if entry[:id] % BLOCK_SIZE == 1
|
249
|
+
@blocks << {:offset => index_offset}
|
250
|
+
end
|
251
|
+
@last_id = entry[:id]
|
252
|
+
index_offset = @index_file.pos
|
193
253
|
end
|
194
254
|
@index_file.seek(0, IO::SEEK_END)
|
195
255
|
end
|
196
256
|
|
197
|
-
|
198
257
|
def index_path
|
199
258
|
File.join(@directory, 'index')
|
200
259
|
end
|
@@ -203,21 +262,57 @@ module Conveyor
|
|
203
262
|
File.join(@directory, 'version')
|
204
263
|
end
|
205
264
|
|
206
|
-
def
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
265
|
+
def cache_block block_num
|
266
|
+
if @block_cache.length > CACHE_SIZE
|
267
|
+
reject = @block_last_used.sort{|a,b| a[1] <=> b[1]}.last.first
|
268
|
+
@block_cache.delete(reject)
|
269
|
+
puts "rejected #{reject}"
|
270
|
+
end
|
271
|
+
a = []
|
272
|
+
|
273
|
+
buf = ''
|
274
|
+
block_start = @blocks[block_num][:offset]
|
275
|
+
block_end = @blocks[block_num + 1] ? @blocks[block_num + 1][:offset] : nil
|
276
|
+
index_file_lock do
|
277
|
+
@index_file.seek(block_start)
|
278
|
+
if block_end
|
279
|
+
buf = @index_file.read(block_end - block_start)
|
215
280
|
else
|
216
|
-
|
281
|
+
buf = @index_file.read
|
282
|
+
end
|
283
|
+
@index_file.seek(0, IO::SEEK_END)
|
284
|
+
end
|
285
|
+
buf.split(/\n/).each do |line|
|
286
|
+
a << self.class.parse_headers(line.strip, true)
|
287
|
+
end
|
288
|
+
@block_cache[block_num] = a
|
289
|
+
end
|
290
|
+
|
291
|
+
def search_index id
|
292
|
+
block_num = block_num(id)
|
293
|
+
|
294
|
+
if !@block_cache.has_key?(block_num)
|
295
|
+
cache_block(block_num)
|
296
|
+
end
|
297
|
+
@block_last_used[block_num] = Time.now.to_i
|
298
|
+
entry = @block_cache[block_num][id - 1 - (block_num * BLOCK_SIZE)]
|
299
|
+
end
|
300
|
+
|
301
|
+
def nearest_after(timestamp)
|
302
|
+
i = 0
|
303
|
+
while (i < @blocks.length - 1) && timestamp < @blocks[i+1][:time]
|
304
|
+
i += 1
|
305
|
+
end
|
306
|
+
cache_block(i) if !@block_cache.has_key?(i)
|
307
|
+
@block_last_used[i] = Time.now.to_i
|
308
|
+
@block_cache[i].each do |entry|
|
309
|
+
if entry[:time] > timestamp
|
310
|
+
return entry[:id]
|
217
311
|
end
|
218
312
|
end
|
219
|
-
if
|
220
|
-
|
313
|
+
if @blocks[i+1]
|
314
|
+
cache_block(i+1)
|
315
|
+
@block_cache[i+1].first[:id]
|
221
316
|
else
|
222
317
|
nil
|
223
318
|
end
|
data/lib/conveyor/channel.rb
CHANGED
@@ -85,15 +85,9 @@ module Conveyor
|
|
85
85
|
end
|
86
86
|
|
87
87
|
def status
|
88
|
-
{
|
89
|
-
:
|
90
|
-
|
91
|
-
:size => @index.length
|
92
|
-
},
|
93
|
-
:data_files => @data_files.collect{|f| {:path => f.path, :bytes => File.size(f.path)}},
|
94
|
-
:iterator => {:position => @iterator},
|
95
|
-
:iterator_groups => @group_iterators.inject({}){|m,(k,v)| m[k] = v; m}
|
96
|
-
}
|
88
|
+
super.merge({
|
89
|
+
:iterator_groups => @group_iterators.inject({}){|m,(k,v)| m[k] = v; m},
|
90
|
+
})
|
97
91
|
end
|
98
92
|
|
99
93
|
def rewind *opts
|
@@ -146,7 +140,8 @@ module Conveyor
|
|
146
140
|
|
147
141
|
def load_channel
|
148
142
|
super
|
149
|
-
@iterator_file = File.open(iterator_path, '
|
143
|
+
@iterator_file = File.open(iterator_path, 'a+')
|
144
|
+
@iterator_file.seek(0)
|
150
145
|
@iterator_file.each_line do |line|
|
151
146
|
@iterator = line.to_i(36)
|
152
147
|
end
|
data/lib/conveyor/server.rb
CHANGED
@@ -21,13 +21,19 @@ module Conveyor
|
|
21
21
|
@logger = Logger.new '/dev/null'
|
22
22
|
end
|
23
23
|
|
24
|
+
t0 = Time.now
|
25
|
+
i "reading data"
|
26
|
+
|
24
27
|
@channels = {}
|
25
28
|
Dir.entries(@data_directory).each do |e|
|
26
29
|
if !['.', '..'].include?(e) && File.directory?(File.join(@data_directory, e)) && Channel.valid_channel_name?(e)
|
30
|
+
i "initializing channel '#{e}'"
|
27
31
|
@channels[e] = Channel.new(File.join(@data_directory, e))
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
35
|
+
i "done reading data (took #{Time.now - t0} sec.)"
|
36
|
+
|
31
37
|
@requests = 0
|
32
38
|
end
|
33
39
|
|
@@ -50,7 +56,7 @@ module Conveyor
|
|
50
56
|
i "#{env["REMOTE_ADDR"]} PUT #{env["REQUEST_PATH"]} 201"
|
51
57
|
[201, {}, "created channel #{m.captures[0]}"]
|
52
58
|
else
|
53
|
-
i "#{env["REMOTE_ADDR"]} PUT #{env["REQUEST_PATH"]}"
|
59
|
+
i "#{env["REMOTE_ADDR"]} PUT #{env["REQUEST_PATH"]} 202"
|
54
60
|
[202, {}, "channel already exists. didn't do anything"]
|
55
61
|
end
|
56
62
|
else
|
data/test/test_channel.rb
CHANGED
@@ -21,15 +21,12 @@ class TestConveyorChannel < Test::Unit::TestCase
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_parse_headers
|
24
|
-
FileUtils.rm_r '/tmp/foo' rescue nil
|
25
|
-
|
26
|
-
i = Channel.new '/tmp/foo'
|
27
24
|
[
|
28
25
|
["1 jucfvs 0 3 acbd18db4cc2f85cedef654fccc4a4d8 0\n",
|
29
26
|
{:id => 1, :time => 1199826280, :offset => 0, :length => 3, :hash => "acbd18db4cc2f85cedef654fccc4a4d8", :file => nil, :flags => 0}
|
30
27
|
]
|
31
28
|
].each do |(str, ret)|
|
32
|
-
assert_equal ret,
|
29
|
+
assert_equal ret, Channel.parse_headers(str)
|
33
30
|
end
|
34
31
|
|
35
32
|
[
|
@@ -37,10 +34,8 @@ class TestConveyorChannel < Test::Unit::TestCase
|
|
37
34
|
{:id => 2, :time => 1199826280, :offset => 0, :length => 3, :hash => "acbd18db4cc2f85cedef654fccc4a4d8", :file => 1, :flags => 0}
|
38
35
|
]
|
39
36
|
].each do |(str, ret)|
|
40
|
-
assert_equal ret,
|
37
|
+
assert_equal ret, Channel.parse_headers(str, true)
|
41
38
|
end
|
42
|
-
|
43
|
-
FileUtils.rm_r '/tmp/foo'
|
44
39
|
end
|
45
40
|
|
46
41
|
def test_init_existing
|
@@ -70,7 +65,7 @@ class TestConveyorChannel < Test::Unit::TestCase
|
|
70
65
|
assert_equal 'bar', c.get_next[1]
|
71
66
|
assert_equal 'bam', c.get_next[1]
|
72
67
|
assert_equal nil, c.get_next
|
73
|
-
assert_equal 4, c.status[:iterator]
|
68
|
+
assert_equal 4, c.status[:iterator]
|
74
69
|
end
|
75
70
|
|
76
71
|
def test_get_next_interupted
|
@@ -138,12 +133,14 @@ class TestConveyorChannel < Test::Unit::TestCase
|
|
138
133
|
|
139
134
|
status = {
|
140
135
|
:directory => '/tmp/bar',
|
141
|
-
:
|
136
|
+
:blocks => 1,
|
142
137
|
:data_files => [
|
143
138
|
{:path => '/tmp/bar/0', :bytes => 158}
|
144
139
|
],
|
145
|
-
:iterator =>
|
146
|
-
:iterator_groups => {}
|
140
|
+
:iterator => 1,
|
141
|
+
:iterator_groups => {},
|
142
|
+
:last_id => 3,
|
143
|
+
:block_cache_keys => []
|
147
144
|
}
|
148
145
|
|
149
146
|
assert_equal(status, c.status)
|
@@ -261,8 +258,10 @@ class TestConveyorChannel < Test::Unit::TestCase
|
|
261
258
|
assert_equal nil, c.get_nearest_after_timestamp(2**32)
|
262
259
|
|
263
260
|
t0 = Time.now.to_i
|
261
|
+
sleep 1 # we only have second-level granularity on time
|
262
|
+
|
264
263
|
10.times{|i| c.post((10 + i).to_s)}
|
265
|
-
assert_equal '
|
264
|
+
assert_equal '10', c.get_nearest_after_timestamp(t0)[1]
|
266
265
|
end
|
267
266
|
|
268
267
|
def test_rewind_to_timestamp
|
@@ -5,11 +5,13 @@ require 'priority_queue'
|
|
5
5
|
|
6
6
|
class TestReplicatedChannel < Test::Unit::TestCase
|
7
7
|
def test_basic
|
8
|
-
|
9
|
-
|
8
|
+
chan1 = '/tmp/test_basic1'
|
9
|
+
chan2 = '/tmp/test_basic2'
|
10
|
+
FileUtils.rm_r chan1 rescue nil
|
11
|
+
FileUtils.rm_r chan2 rescue nil
|
10
12
|
|
11
|
-
c1 = Conveyor::ReplicatedChannel.new
|
12
|
-
c2 = Conveyor::ReplicatedChannel.new
|
13
|
+
c1 = Conveyor::ReplicatedChannel.new chan1
|
14
|
+
c2 = Conveyor::ReplicatedChannel.new chan2
|
13
15
|
|
14
16
|
c1.peers << c2
|
15
17
|
c2.peers << c1
|
@@ -34,8 +36,8 @@ class TestReplicatedChannel < Test::Unit::TestCase
|
|
34
36
|
assert_equal c1.get(1), c2.get(1)
|
35
37
|
assert_equal c1.get(2), c2.get(2)
|
36
38
|
|
37
|
-
FileUtils.rm_r
|
38
|
-
FileUtils.rm_r
|
39
|
+
FileUtils.rm_r chan1 rescue nil
|
40
|
+
FileUtils.rm_r chan2 rescue nil
|
39
41
|
end
|
40
42
|
|
41
43
|
def test_more
|
data/test/test_server.rb
CHANGED
@@ -19,6 +19,7 @@ class TestConveyorServer < Test::Unit::TestCase
|
|
19
19
|
|
20
20
|
Rack::Handler::Mongrel.run(app, :Host => '0.0.0.0', :Port => 8011)
|
21
21
|
end
|
22
|
+
sleep 1
|
22
23
|
|
23
24
|
def test_channels
|
24
25
|
Net::HTTP.start("localhost", 8011) do |h|
|
@@ -117,10 +118,12 @@ class TestConveyorServer < Test::Unit::TestCase
|
|
117
118
|
assert_kind_of Net::HTTPOK, req
|
118
119
|
json = {
|
119
120
|
"iterator_groups" => {},
|
120
|
-
"
|
121
|
+
"blocks" => 1,
|
121
122
|
"directory"=>"/tmp/asdf/#{chan}",
|
122
123
|
"data_files"=>[{"path"=>"/tmp/asdf/#{chan}/0","bytes"=>122}],
|
123
|
-
"iterator"=>
|
124
|
+
"iterator"=>1,
|
125
|
+
"last_id" => 1,
|
126
|
+
"block_cache_keys" => []
|
124
127
|
}
|
125
128
|
assert_equal json, JSON::parse(req.body)
|
126
129
|
|
@@ -287,8 +290,9 @@ class TestConveyorServer < Test::Unit::TestCase
|
|
287
290
|
assert_equal '', c.get_nearest_after_timestamp(2**32)
|
288
291
|
|
289
292
|
t0 = Time.now.to_i
|
293
|
+
sleep 1
|
290
294
|
10.times{|i| c.post((10 + i).to_s)}
|
291
|
-
assert_equal '
|
295
|
+
assert_equal '10', c.get_nearest_after_timestamp(t0)
|
292
296
|
end
|
293
297
|
|
294
298
|
def test_rewind_to_timestamp
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: conveyor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan King
|
@@ -30,11 +30,12 @@ cert_chain:
|
|
30
30
|
Zls3y84CmyAEGg==
|
31
31
|
-----END CERTIFICATE-----
|
32
32
|
|
33
|
-
date: 2008-
|
33
|
+
date: 2008-10-21 00:00:00 -07:00
|
34
34
|
default_executable:
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: mongrel
|
38
|
+
type: :runtime
|
38
39
|
version_requirement:
|
39
40
|
version_requirements: !ruby/object:Gem::Requirement
|
40
41
|
requirements:
|
@@ -44,6 +45,7 @@ dependencies:
|
|
44
45
|
version:
|
45
46
|
- !ruby/object:Gem::Dependency
|
46
47
|
name: json
|
48
|
+
type: :runtime
|
47
49
|
version_requirement:
|
48
50
|
version_requirements: !ruby/object:Gem::Requirement
|
49
51
|
requirements:
|
@@ -53,6 +55,17 @@ dependencies:
|
|
53
55
|
version:
|
54
56
|
- !ruby/object:Gem::Dependency
|
55
57
|
name: daemons
|
58
|
+
type: :runtime
|
59
|
+
version_requirement:
|
60
|
+
version_requirements: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
- !ruby/object:Gem::Dependency
|
67
|
+
name: rack
|
68
|
+
type: :runtime
|
56
69
|
version_requirement:
|
57
70
|
version_requirements: !ruby/object:Gem::Requirement
|
58
71
|
requirements:
|
@@ -62,17 +75,19 @@ dependencies:
|
|
62
75
|
version:
|
63
76
|
- !ruby/object:Gem::Dependency
|
64
77
|
name: hoe
|
78
|
+
type: :development
|
65
79
|
version_requirement:
|
66
80
|
version_requirements: !ruby/object:Gem::Requirement
|
67
81
|
requirements:
|
68
82
|
- - ">="
|
69
83
|
- !ruby/object:Gem::Version
|
70
|
-
version: 1.
|
84
|
+
version: 1.7.0
|
71
85
|
version:
|
72
86
|
description: "* Like TiVo for your data * A distributed rewindable multi-queue"
|
73
87
|
email: ryan@theryanking.com
|
74
88
|
executables:
|
75
89
|
- conveyor
|
90
|
+
- conveyor-rebuild-index
|
76
91
|
- conveyor-upgrade
|
77
92
|
extensions: []
|
78
93
|
|
@@ -87,6 +102,7 @@ files:
|
|
87
102
|
- README.txt
|
88
103
|
- Rakefile
|
89
104
|
- bin/conveyor
|
105
|
+
- bin/conveyor-rebuild-index
|
90
106
|
- bin/conveyor-upgrade
|
91
107
|
- docs/file-formats.rdoc
|
92
108
|
- docs/protocol.rdoc
|
@@ -125,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
141
|
requirements: []
|
126
142
|
|
127
143
|
rubyforge_project: conveyor
|
128
|
-
rubygems_version: 1.
|
144
|
+
rubygems_version: 1.2.0
|
129
145
|
signing_key:
|
130
146
|
specification_version: 2
|
131
147
|
summary: "* Like TiVo for your data * A distributed rewindable multi-queue"
|
metadata.gz.sig
CHANGED
Binary file
|