dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH] lib/net/*: recycle and clear short-lived read buffers
@ 2017-05-21 23:15 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2017-05-21 23:15 UTC (permalink / raw)
  To: spew

Using a parallel Net::HTTP downloader, this reduced memory usage
from around 120MB to 27MB on my 32-bit x86 system.

* lib/net/protocol.rb (rbuf_fill): accept destination buffer, clear if used
  (read): reuse result of rbuf_consume for rbuf_fill
  (read_all): ditto
  (read_until): ditto
* lib/net/ftp.rb (rbuf_fill): update to match

Test script I used:

  require 'net/http'
  require 'uri'
  require 'digest/sha1'
  url = 'http://80x24.org/git-i-forgot-to-pack/objects/pack/pack-97b25a76c03b489d4cbbd85b12d0e1ad28717e55.idx'
  uri = URI(url)
  use_ssl = "https" == uri.scheme
  thrs = 30.times.map do
    Thread.start do
      cur = Thread.current.object_id
      Net::HTTP.start(uri.host, uri.port, use_ssl: use_ssl) do |http|
        req = Net::HTTP::Get.new(uri)
        http.request(req) do |res|
          dig = Digest::SHA1.new
          res.read_body do |buf|
            dig.update(buf)
            #buf.clear # most Ruby programmers don't do this :<
          end
          warn "#{Time.now} #{cur} #{dig.hexdigest}\n"
        end
      end
      :done
    end
  end

  p thrs.map(&:value)
---
 lib/net/ftp.rb      |  4 ++--
 lib/net/protocol.rb | 15 +++++++++------
 2 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/lib/net/ftp.rb b/lib/net/ftp.rb
index 601d2cb4c3..af163885bc 100644
--- a/lib/net/ftp.rb
+++ b/lib/net/ftp.rb
@@ -1478,11 +1478,11 @@ def send(mesg, flags, dest = nil)
 
         private
 
-        def rbuf_fill
+        def rbuf_fill(dst)
           if @is_shutdown
             raise EOFError, "shutdown has been called"
           else
-            super
+            super(dst)
           end
         end
       end
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb
index 518b92c4ab..f492298a03 100644
--- a/lib/net/protocol.rb
+++ b/lib/net/protocol.rb
@@ -121,10 +121,11 @@ def read(len, dest = ''.dup, ignore_eof = false)
         while read_bytes + @rbuf.size < len
           dest << (s = rbuf_consume(@rbuf.size))
           read_bytes += s.size
-          rbuf_fill
+          rbuf_fill(s)
         end
         dest << (s = rbuf_consume(len - read_bytes))
         read_bytes += s.size
+        s.clear
       rescue EOFError
         raise unless ignore_eof
       end
@@ -139,7 +140,7 @@ def read_all(dest = ''.dup)
         while true
           dest << (s = rbuf_consume(@rbuf.size))
           read_bytes += s.size
-          rbuf_fill
+          rbuf_fill(s)
         end
       rescue EOFError
         ;
@@ -151,7 +152,7 @@ def read_all(dest = ''.dup)
     def readuntil(terminator, ignore_eof = false)
       begin
         until idx = @rbuf.index(terminator)
-          rbuf_fill
+          rbuf_fill(''.b)
         end
         return rbuf_consume(idx + terminator.size)
       rescue EOFError
@@ -168,10 +169,12 @@ def readline
 
     BUFSIZE = 1024 * 16
 
-    def rbuf_fill
-      case rv = @io.read_nonblock(BUFSIZE, exception: false)
+    def rbuf_fill(dst)
+      case rv = @io.read_nonblock(BUFSIZE, dst, exception: false)
       when String
-        return @rbuf << rv
+        @rbuf << rv
+        dst.clear
+        return
       when :wait_readable
         @io.to_io.wait_readable(@read_timeout) or raise Net::ReadTimeout
         # continue looping
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2017-05-21 23:16 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-05-21 23:15 [PATCH] lib/net/*: recycle and clear short-lived read buffers Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).