async-io 1.23.3 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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