async-io 1.23.3 → 1.24.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b0dbae8c805f1cd5878161490bbb70a211ecf7ebd3252a55c81f8c901b583b82
4
- data.tar.gz: 5691a8fa37149cd0a79d9363e4b3a98588bf3f48f8df3ba8a683f0adc1fc1548
3
+ metadata.gz: c0614be3c203f3e9b8de82215fdacbe3a9bccdcd9b82784af349aa3149d63419
4
+ data.tar.gz: da66baf1cea7ee3ba1411eee6c09a7eeef5faef39e40ce6459fcd8002df2437b
5
5
  SHA512:
6
- metadata.gz: 49c21510120fe04d90283bdcf1041bd510057cf107b2d535e2d822d4aff0baff1c7e52f511903f7c8cc3e196985c2effc607b377bbd33dc8ccd50a34bae44785
7
- data.tar.gz: 3bbefda69345a03fdee012b84466d15788686e5944b53b5c835176d81c230b5ed521290f555d98ffe9f54a72bb113f3069f7d93cd0c3ad1263606b840d414d79
6
+ metadata.gz: 3624d5fe1177e65b87cb75fdec5eaeac9ef25543d423a66333c6de3b2826f656d0e7acdf5742741b2a7744518baa482f987584829aa6f2ebf140339161bf13be
7
+ data.tar.gz: d12bdfe724ba95f6f39cbc68bf21b7df0c16537f1c5dd689e70f102609ce6c75502d2cc41478546c9704d42bfdcdafbdc9e63a5cc5cc300ccf08610d4c533f96
@@ -23,9 +23,11 @@ require 'forwardable'
23
23
 
24
24
  module Async
25
25
  module IO
26
- # The default block size for IO buffers.
27
- # BLOCK_SIZE = ENV.fetch('BLOCK_SIZE', 1024*16).to_i
28
- BLOCK_SIZE = 1024*8
26
+ # The default block size for IO buffers. Defaults to 8KB.
27
+ BLOCK_SIZE = ENV.fetch('ASYNC_IO_BLOCK_SIZE', 1024*8).to_i
28
+
29
+ # The maximum read size when appending to IO buffers. Defaults to 8MB.
30
+ MAXIMUM_READ_SIZE = ENV.fetch('ASYNC_IO_MAXIMUM_READ_SIZE', BLOCK_SIZE * 128 * 8).to_i
29
31
 
30
32
  # Convert a Ruby ::IO object to a wrapped instance:
31
33
  def self.try_convert(io, &block)
@@ -26,7 +26,19 @@ module Async
26
26
  class Stream
27
27
  BLOCK_SIZE = IO::BLOCK_SIZE
28
28
 
29
- def initialize(io, block_size: BLOCK_SIZE, sync: true)
29
+ def self.open(path, mode = "r+", **options)
30
+ stream = self.new(File.open(path, mode), **options)
31
+
32
+ return stream unless block_given?
33
+
34
+ begin
35
+ yield stream
36
+ ensure
37
+ stream.close
38
+ end
39
+ end
40
+
41
+ def initialize(io, block_size: BLOCK_SIZE, maximum_read_size: MAXIMUM_READ_SIZE, sync: true)
30
42
  @io = io
31
43
  @eof = false
32
44
 
@@ -34,6 +46,7 @@ module Async
34
46
  @io.sync = sync
35
47
 
36
48
  @block_size = block_size
49
+ @maximum_read_size = maximum_read_size
37
50
 
38
51
  @read_buffer = Buffer.new
39
52
  @write_buffer = Buffer.new
@@ -220,6 +233,11 @@ module Async
220
233
 
221
234
  # Fills the buffer from the underlying stream.
222
235
  def fill_read_buffer(size = @block_size)
236
+ # We impose a limit because the underlying `read` system call can fail if we request too much data in one go.
237
+ if size > @maximum_read_size
238
+ size = @maximum_read_size
239
+ end
240
+
223
241
  if @read_buffer.empty? and @io.read_nonblock(size, @read_buffer, exception: false)
224
242
  return true
225
243
  elsif chunk = @io.read_nonblock(size, @input_buffer, exception: false)
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module IO
23
- VERSION = "1.23.3"
23
+ VERSION = "1.24.0"
24
24
  end
25
25
  end
@@ -19,6 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'async/io/socket'
22
+ require 'async/clock'
22
23
 
23
24
  require_relative 'generic_examples'
24
25
  require_relative 'stream_context'
@@ -46,14 +47,6 @@ RSpec.describe Async::IO::Stream do
46
47
  it_should_behave_like Async::IO
47
48
 
48
49
  describe '#close_read' do
49
- let(:sockets) do
50
- @sockets = Async::IO::Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
51
- end
52
-
53
- after do
54
- @sockets&.each(&:close)
55
- end
56
-
57
50
  subject {described_class.new(sockets.last)}
58
51
 
59
52
  it "can close the reading end of the stream" do
@@ -95,6 +88,28 @@ RSpec.describe Async::IO::Stream do
95
88
  end
96
89
  end
97
90
 
91
+ context "performance (BLOCK_SIZE: #{Async::IO::BLOCK_SIZE} MAXIMUM_READ_SIZE: #{Async::IO::MAXIMUM_READ_SIZE})" do
92
+ include_context Async::RSpec::Reactor
93
+
94
+ let!(:stream) {described_class.open("/dev/zero")}
95
+ after {stream.close}
96
+
97
+ it "can read data quickly" do |example|
98
+ data = nil
99
+
100
+ duration = Async::Clock.measure do
101
+ data = stream.read(4*1024**3)
102
+ end
103
+
104
+ size = data.bytesize / 1024**2
105
+ rate = size / duration
106
+
107
+ example.reporter.message "Read #{size.round(2)}MB of data at #{rate.round(2)}MB/s."
108
+
109
+ expect(rate).to be > 512
110
+ end
111
+ end
112
+
98
113
  context "buffered I/O" do
99
114
  include_context Async::IO::Stream
100
115
  include_context Async::RSpec::Memory
@@ -4,6 +4,12 @@ require "async/rspec"
4
4
 
5
5
  require_relative 'addrinfo'
6
6
 
7
+ class RSpec::Core::Formatters::DocumentationFormatter
8
+ def message(notification)
9
+ output.puts "#{current_indentation}#{notification.message}"
10
+ end
11
+ end
12
+
7
13
  RSpec.configure do |config|
8
14
  # Enable flags like --only-failures and --next-failure
9
15
  config.example_status_persistence_file_path = ".rspec_status"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-io
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.23.3
4
+ version: 1.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-06-27 00:00:00.000000000 Z
11
+ date: 2019-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: async