Wednesday, June 04, 2008

overlapping io for mongrel-esi

I've been doing a little work on mongrel-esi to improve it's concurrency. Here's a little test script I wrote to verify some of my thinking. The tricky part, is keeping all the bytes in the correct order, while still requesting as much as possible in parallel. Here's my thinking at the moment.

# reading a file
# as we read and encounter <esi:include src="/foo"/>
# spawn a thread and simulate requesting, but continue parsing the file looking for more on the main thread
# tweak the sleep calls to get different behavior...
require 'thread'

# define a sample buffer here:
input_stream = %Q(
hello there world

<esi:include src='/foo/'/>

some more bytes here

<esi:include src='/bar/'/>

and some more here
)

# lets read line by line

count = 0
output = []
back_buffer = []
lock = Mutex.new
in_request = false
requesting = []
last_out = 0

input_stream.split("\n").each do|line|
if line.match(/<esi:/)
lock.synchronize do
in_request = true
back_buffer[count] = nil # reserve a location in back_buffer
end
requesting << Thread.new(count) do|id|
sleep 0.4 # some busy work
lock.synchronize do
back_buffer[id] = "#{id}: sample"
in_request = false
end
end
else
sleep 0.1
lock.synchronize do
if in_request
puts "buffering lines..."
back_buffer[count] = "#{count}: #{line}"
else
# roll up requests
puts "roll up requests..."
i = 0
until i == count
o = back_buffer.shift
output << o unless o.nil?
i += 1
end
output << "#{count}: #{line}"
last_out = count # mark the last buffer in back_buffer to be sent
end
end
end
count += 1
end
requesting.each do|t|
t.join
end
# roll up requests
while !back_buffer.empty?
o = back_buffer.shift
output << o unless o.nil?
end

puts back_buffer.inspect
puts output.join("\n")



One obvious issue with this implementation is the number of threads per request is bounded by the response document.
Update: I've checked the above into svn, with a few updates

0 comments:

Reading list