Project

General

Profile

Feature #14404

Adding writev support to IO#write_nonblock

Added by janko (Janko Marohnić) 12 months ago. Updated 12 months ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:85129]

Description

In Ruby 2.5 IO#write received writev support (https://github.com/ruby/ruby/commit/3efa7126e5e853f06cdd78d4d88837aeb72a9a3e), allowing it to accept multiple arguments and utilize writev when available.

Would it be possible to add this feature to IO#write_nonblock as well? IO#write_nonblock is used by the HTTP.rb and Socketry gems to implement their "write timeout" feature (the same way that IO#read_nonblock is used in Net::HTTP to implement "read timeout"). Since IO#write_nonblock doesn't yet support writev, at the moment it's not possible for HTTP.rb and Socketry to utilize writev when the "write timeout" is specified.

History

Updated by normalperson (Eric Wong) 12 months ago

janko.marohnic@gmail.com wrote:

Would it be possible to add this feature to IO#write_nonblock
as well? IO#write_nonblock is used by the HTTP.rb and Socketry
gems to implement their "write timeout" feature (the same way
that IO#read_nonblock is used in Net::HTTP to implement "read
timeout"). Since IO#write_nonblock doesn't yet support writev,
at the moment it's not possible for HTTP.rb and Socketry to
utilize writev when the "write timeout" is specified.

How ugly/tedious would it be for the users to deal with partial
writes to use write_nonblock?

It's a lot easier with IO#write because of the write-in-full
expectation, so no new strings get created; pointers just get
updated in C.

Fwiw, one longer-term idea is to integrate Timeout into the VM,
so internal rb_io_wait_*able calls can see the timeout and not
rely on being interrupted as with current timeout.rb.

Updated by janko (Janko Marohnić) 12 months ago

How ugly/tedious would it be for the users to deal with partial
writes to use write_nonblock?

It does take a bit of work, but I believe the following code would do the job:

until chunks.empty?
  length = io.write_nonblock(*chunks)
  break unless chunks.sum(&:bytesize) > length
  while length > 0
    chunk = chunks.shift
    length -= chunk.bytesize
    chunks.unshift string.byteslice(length..-1) if length < 0
  end
end

I remembered now that HTTP.rb and Socketry would probably only utilize
writev on "Transfer-Encoding: chunked" requests, which probably aren't used
very often (you'd probably use that only when uploading a file of unknown
length).

It's a lot easier with IO#write because of the write-in-full
expectation, so no new strings get created; pointers just get
updated in C.

I agree, it would be ideal to be able to always use IO#write.

Fwiw, one longer-term idea is to integrate Timeout into the VM,
so internal rb_io_wait_*able calls can see the timeout and not
rely on being interrupted as with current timeout.rb.

That sounds great!

Also available in: Atom PDF