As a note, if I run the instance_exec echo server, I get some weirdness. The code works and it does echo, but on_connect doesn''t seem to ever work. If I add in a print statement to the def event_callback(*methods) methods.each do |method| module_eval <<-EOD def #{method}(*args, &block) print "within it#{method}\n" I get Echo server listening on 127.0.0.1:4321 within iton_connect within iton_connect within iton_close within iton_read with a single read. Not quite sure where all those are coming from, but hey. I may look into it sometime. The ''normal'' echo server in examples/echo_server works as expected, though. Also as a note, with revem we ''used to'' "re super class" the Connection class. These days it appears to throw TypeError: superclass mismatch [I think--it''s been awhile] So will attempt to redo it. Thanks! -R
Also I assume that we keep track of timers in memory somewhere so they don''t get collected? :) Thanks. -R
On Thu, Jul 24, 2008 at 11:55 PM, Roger Pack < roger.pack at leadmediapartners.com> wrote:> As a note, if I run the instance_exec echo server, I get some > weirdness.There seems to be lots of weirdness with the instance_exec syntax. You''re really convincing me of the need for specs. I get> Echo server listening on 127.0.0.1:4321 > within iton_connect > within iton_connect > within iton_close > within iton_read >So on_connect fires twice, and read fires after close? Very weird.> Also as a note, with revem we ''used to'' "re super class" the > Connection class. These days it appears to throw > > TypeError: superclass mismatch [I think--it''s been awhile] >How were you attempting to do it? Can you give me a code snippet? Also I assume that we keep track of timers in memory somewhere so they> don''t get collected? :) >All watchers that are attached to a given loop are added to what is, for now, an array which is an ivar within the loop object so they don''t get garbage collected. An array is a poor choice for that structure algorithmically and right now is Rev''s #1 performance bottleneck for things like HTTP servers that receive lots of short lived connections, as it makes Rev::Loop#detach O(n) for n connections, as Array#delete is O(n). I''ve tried to replace it with a "bag" type data structure which isn''t order-preserving and would be O(1) in all cases, but I was trying to do it in C and couldn''t get the implementation correct. -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080725/35758335/attachment-0001.html>
On Fri, Jul 25, 2008 at 2:45 PM, Roger Pack < roger.pack at leadmediapartners.com> wrote:> My attempt is to > require ''eventmachine'' > then ''monkey patch'' it to use rev for the actual connections. > Which quickly yielded: > > ~/dev/rev_committable/contrib/revem ruby revem.rb > revem.rb:49: superclass mismatch for class Connection (TypeError) > > So I''m working on the revem2.rb which is in there currently. > The benefit of this is that you can use things like EM::Timer ''without > changing its code at all'' [which class I use in my existing app]. > That''s the goal, anyway :) >Aah. I had never tried loading revem and eventmachine at the same time, but now I see why it would be problematic. Feel free to modify revem directly. You don''t need to make a revem2.> I asume the code works such that it doesn''t create a ''real'' tcpsocket > class [with write buffer] until the connection completes.Actually, it does. I''ll need to look more in depth as to why this isn''t working. Can you send me the error you were getting? So it''s ok> to just create the write buffer early, but then I get confused about > the writer being attached to the event loop, and how it seems like the > reader is attached [only] to the event loop and such.The write watcher is only attached to the event loop when there''s data in the write buffer.> And how sockets, when you create them ''auto bind'' to the current event > loop. Is that right?No. You need to attach any subclass of Rev::IO (including Sockets) to the event loop explicitly.> Incoming sockets from acceptors ''auto bind'' to the current event loop. > And tcp sockets also need to bind to an event loop? >If you''re using something like Rev::TCPServer then yes, the newly created connection objects are automatically bound to the same loop the server is attached to.> Yeah. Once it''s working then maybe will look at performance :) >There''s lots of opportunities for performance improvements. I''d really like to look at doing simple proactor objects in C that work like IOWatchers but actually perform the I/O completely in C when readiness is signaled. Right now performing I/O involves quite a few rb_funcalls -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080725/69001239/attachment.html>
On Fri, Jul 25, 2008 at 4:03 PM, Roger Pack < roger.pack at leadmediapartners.com> wrote:> I see that it does. But just doesn''t create the write buffer until later. > I tried creating the write buffer early but...I think the error then > was that if I called write before the ''real connection'' had been > established: > > /Users/rogerpack/dev/rev_committable/trunk/lib/rev/io.rb:142:in > `enable_write_watcher'': undefined method `attached?'' for nil:NilClass > (NoMethodError) > from /Users/rogerpack/dev/rev_committable/trunk/lib/rev/io.rb:136:in > `schedule_write'' > from /Users/rogerpack/dev/rev_committable/trunk/lib/rev/io.rb:81:in > `write'' > from ./lib/opendht/../../revem.rb:147:in `send_data''Aah, so the real problem is the connection objects aren''t "fully" initialized until the connection completes. Furthermore, Rev does async DNS. This means that there actually isn''t a TCP socket to write to at all until the DNS lookup completes. If you want to support this behavior, you''ll really need to make an internal buffer that''s used until the connection is fully established. Yeah that would for sure make sense with [for example] an internal> write watcher. Problematic would only be its calling > ''on_write_complete'' when its done. But if you gave it a hash for its > call-back object you''d be good. >Well, instead of it having an on_writable callback as the present Reactor objects, the watcher itself would have an on_write_complete which could in turn call the on_write_complete method for the Rev::IO object.> I guess the only difference between EM and Rev [that I can see] is > that Rev uses ruby calls for reading the incoming data and creating > the sockets. Move that to C and hopefully it would be the same speed. > Theoretically.That''s the hope, anyway.> Do what you can I guess :) I personally prefer it in Ruby since hacking on > C is painful and scary. >Yeah, my goal would be to do the absolute bare minimum amount of C I can while still being performant. This would involve rewriting the Rev::IO::Watcher class in C and moving some of the logic from Rev::IO into it (specifically the write buffering). -- Tony Arcieri medioh.com -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://rubyforge.org/pipermail/rev-talk/attachments/20080725/727adaa3/attachment.html>
Question: Can you think why on_connect_failed is being called with this? It just starts up a ''normal'' TCP Server, and connects to it. ? require File.dirname(__FILE__) + ''/../../trunk/lib/rev'' #require ''rubygems'' #require ''rev'' ADDR = ''127.0.0.1'' PORT = 4321 require ''socket'' a = TCPServer.new ADDR, PORT # one that won''t resolve your connections class ClientConnection < Rev::TCPSocket def on_connect puts "#{remote_addr}:#{remote_port} connected" write "bounce this back to me" end def on_close puts "#{remote_addr}:#{remote_port} disconnected" end def on_read(data) print "got #{data}" close end def on_connect_failed print "WHY do we get here" end end event_loop = Rev::Loop.default a = ClientConnection.connect(ADDR, PORT) a.attach a.write "yep" puts "Echo client started to #{ADDR}:#{PORT}" event_loop.run