io_splice 4.1.1 → 4.2.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.
- data/GIT-VERSION-GEN +1 -1
- data/README +2 -2
- data/ext/io_splice/io_splice_ext.c +48 -22
- data/io_splice.gemspec +1 -1
- data/lib/io/splice.rb +8 -10
- data/test/test_tcp_splice.rb +17 -0
- metadata +88 -77
data/GIT-VERSION-GEN
CHANGED
data/README
CHANGED
@@ -89,11 +89,11 @@ don't email the git mailing list or maintainer with io_splice patches.
|
|
89
89
|
== Contact
|
90
90
|
|
91
91
|
All feedback (bug reports, user/development discussion, patches, pull
|
92
|
-
requests) go to the mailing list: mailto:ruby.io.splice@librelist.
|
92
|
+
requests) go to the mailing list: mailto:ruby.io.splice@librelist.org
|
93
93
|
|
94
94
|
== Mailing List Archives
|
95
95
|
|
96
|
-
In addition to the rsync-able archives provided by http://librelist.
|
96
|
+
In addition to the rsync-able archives provided by http://librelist.org/, we
|
97
97
|
are also mirrored to
|
98
98
|
{Gmane}[http://gmane.org/info.php?group=gmane.comp.lang.ruby.io-splice.general]
|
99
99
|
and maintain our own mbox mirrors downloadable via HTTP.
|
@@ -10,11 +10,14 @@
|
|
10
10
|
#include <sys/uio.h>
|
11
11
|
#include <limits.h>
|
12
12
|
#include <alloca.h>
|
13
|
-
#include <
|
13
|
+
#include <unistd.h>
|
14
14
|
|
15
15
|
static VALUE sym_EAGAIN;
|
16
16
|
#define WAITALL 0x4000000
|
17
17
|
|
18
|
+
/* taken from haproxy */
|
19
|
+
#define MAX_AT_ONCE (1 << 30)
|
20
|
+
|
18
21
|
#ifndef F_LINUX_SPECIFIC_BASE
|
19
22
|
# define F_LINUX_SPECIFIC_BASE 1024
|
20
23
|
#endif
|
@@ -130,6 +133,9 @@ static VALUE nogvl_splice(void *ptr)
|
|
130
133
|
{
|
131
134
|
struct splice_args *a = ptr;
|
132
135
|
|
136
|
+
if (a->len > MAX_AT_ONCE)
|
137
|
+
a->len = MAX_AT_ONCE;
|
138
|
+
|
133
139
|
return (VALUE)splice(a->fd_in, a->off_in, a->fd_out, a->off_out,
|
134
140
|
a->len, a->flags);
|
135
141
|
}
|
@@ -276,6 +282,9 @@ static VALUE nogvl_tee(void *ptr)
|
|
276
282
|
{
|
277
283
|
struct tee_args *a = ptr;
|
278
284
|
|
285
|
+
if (a->len > MAX_AT_ONCE)
|
286
|
+
a->len = MAX_AT_ONCE;
|
287
|
+
|
279
288
|
return (VALUE)tee(a->fd_in, a->fd_out, a->len, a->flags);
|
280
289
|
}
|
281
290
|
|
@@ -468,7 +477,7 @@ static void advance_vmsplice_args(struct vmsplice_args *a, long n)
|
|
468
477
|
* This may allow the kernel to avoid data copies in some cases.
|
469
478
|
* but is (probably) of limited usefulness in Ruby. If you have
|
470
479
|
* use cases or ideas for making this more useful for Ruby users,
|
471
|
-
* please tell us at ruby.io.splice@librelist.
|
480
|
+
* please tell us at ruby.io.splice@librelist.org!
|
472
481
|
*
|
473
482
|
* Also consider the "sendfile" RubyGem or IO.copy_stream in Ruby 1.9
|
474
483
|
* if you want to do zero-copy file transfers to pipes or sockets. As
|
@@ -483,19 +492,19 @@ static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self)
|
|
483
492
|
ssize_t rv = 0;
|
484
493
|
ssize_t left;
|
485
494
|
struct vmsplice_args a;
|
495
|
+
struct iovec iov;
|
496
|
+
ssize_t n;
|
497
|
+
|
486
498
|
VALUE io, data, flags;
|
487
499
|
|
488
500
|
rb_scan_args(argc, argv, "21", &io, &data, &flags);
|
489
501
|
|
490
502
|
switch (TYPE(data)) {
|
491
|
-
case T_STRING:
|
492
|
-
struct iovec iov;
|
493
|
-
|
503
|
+
case T_STRING:
|
494
504
|
iov.iov_base = RSTRING_PTR(data);
|
495
505
|
iov.iov_len = (size_t)(left = (ssize_t)RSTRING_LEN(data));
|
496
506
|
a.iov = &iov;
|
497
507
|
a.nr_segs = 1;
|
498
|
-
}
|
499
508
|
break;
|
500
509
|
case T_ARRAY:
|
501
510
|
ARY2IOVEC(a.iov, a.nr_segs, left, data);
|
@@ -505,21 +514,19 @@ static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self)
|
|
505
514
|
"(expected a String or Array of strings)",
|
506
515
|
rb_obj_classname(data));
|
507
516
|
}
|
508
|
-
|
517
|
+
|
509
518
|
a.flags = NIL_P(flags) ? 0 : NUM2UINT(flags);
|
510
519
|
|
511
520
|
for (;;) {
|
512
|
-
|
521
|
+
a.fd = check_fileno(io);
|
522
|
+
n = (ssize_t)io_run(nogvl_vmsplice, &a);
|
513
523
|
|
514
524
|
if (n == -1) {
|
515
525
|
if (errno == EAGAIN) {
|
516
|
-
if (a.flags & SPLICE_F_NONBLOCK)
|
526
|
+
if (a.flags & SPLICE_F_NONBLOCK)
|
517
527
|
rb_sys_fail("vmsplice");
|
518
|
-
|
519
|
-
|
520
|
-
if (rb_io_wait_writable(a.fd))
|
521
|
-
continue;
|
522
|
-
}
|
528
|
+
if (rb_io_wait_writable(check_fileno(io)))
|
529
|
+
continue;
|
523
530
|
/* fall through on error */
|
524
531
|
}
|
525
532
|
/*
|
@@ -529,10 +536,8 @@ static VALUE my_vmsplice(int argc, VALUE * argv, VALUE self)
|
|
529
536
|
*/
|
530
537
|
if (rv > 0)
|
531
538
|
break;
|
532
|
-
if (errno == EINTR)
|
533
|
-
a.fd = check_fileno(io);
|
539
|
+
if (errno == EINTR)
|
534
540
|
continue;
|
535
|
-
}
|
536
541
|
rb_sys_fail("vmsplice");
|
537
542
|
}
|
538
543
|
|
@@ -612,10 +617,28 @@ static VALUE set_pipe_size(VALUE self, VALUE size)
|
|
612
617
|
return size;
|
613
618
|
}
|
614
619
|
|
620
|
+
static int can_mod_pipe_size(void)
|
621
|
+
{
|
622
|
+
int fds[2];
|
623
|
+
int rc = pipe(fds);
|
624
|
+
|
625
|
+
if (rc == 0) {
|
626
|
+
rc = fcntl(fds[0], F_GETPIPE_SZ);
|
627
|
+
rc = rc < 0 ? 0 : 1;
|
628
|
+
|
629
|
+
(void)close(fds[0]);
|
630
|
+
(void)close(fds[1]);
|
631
|
+
} else {
|
632
|
+
/* weird error, but don't raise during init */
|
633
|
+
rc = 0;
|
634
|
+
}
|
635
|
+
errno = 0;
|
636
|
+
return rc;
|
637
|
+
}
|
638
|
+
|
615
639
|
void Init_io_splice_ext(void)
|
616
640
|
{
|
617
641
|
VALUE mSplice = rb_define_module_under(rb_cIO, "Splice");
|
618
|
-
struct utsname utsname;
|
619
642
|
|
620
643
|
rb_define_singleton_method(rb_cIO, "splice", my_splice, -1);
|
621
644
|
rb_define_singleton_method(rb_cIO, "trysplice", trysplice, -1);
|
@@ -682,11 +705,14 @@ void Init_io_splice_ext(void)
|
|
682
705
|
*/
|
683
706
|
rb_define_const(mSplice, "PIPE_BUF", UINT2NUM(PIPE_BUF));
|
684
707
|
|
685
|
-
|
686
|
-
|
708
|
+
/*
|
709
|
+
* The maximum size we're allowed to splice at once. Larger
|
710
|
+
* sizes will be broken up and retried if the WAITALL flag or
|
711
|
+
* IO::Splice.copy_stream is used.
|
712
|
+
*/
|
713
|
+
rb_define_const(mSplice, "MAX_AT_ONCE", SIZET2NUM(MAX_AT_ONCE));
|
687
714
|
|
688
|
-
|
689
|
-
if (strcmp(utsname.release, "2.6.35") >= 0) {
|
715
|
+
if (can_mod_pipe_size()) {
|
690
716
|
rb_define_method(rb_cIO, "pipe_size", pipe_size, 0);
|
691
717
|
rb_define_method(rb_cIO, "pipe_size=", set_pipe_size, 1);
|
692
718
|
|
data/io_splice.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.authors = ["Ruby io_splice hackers"]
|
12
12
|
s.date = Time.now.utc.strftime('%Y-%m-%d')
|
13
13
|
s.description = readme_description
|
14
|
-
s.email = %q{ruby.io.splice@librelist.
|
14
|
+
s.email = %q{ruby.io.splice@librelist.org}
|
15
15
|
s.extensions = %w(ext/io_splice/extconf.rb)
|
16
16
|
s.extra_rdoc_files = extra_rdoc_files(manifest)
|
17
17
|
s.files = manifest
|
data/lib/io/splice.rb
CHANGED
@@ -47,26 +47,24 @@ module IO::Splice
|
|
47
47
|
src, dst = src.to_io, dst.to_io
|
48
48
|
|
49
49
|
if src.stat.pipe? || dst.stat.pipe?
|
50
|
-
if len
|
51
|
-
|
52
|
-
|
53
|
-
rv
|
54
|
-
|
55
|
-
rv += n
|
56
|
-
src_offset += n if src_offset
|
57
|
-
end
|
50
|
+
return full(src, dst, len, src_offset) if len
|
51
|
+
rv = 0
|
52
|
+
while n = partial(src, dst, MAX_AT_ONCE, src_offset)
|
53
|
+
rv += n
|
54
|
+
src_offset += n if src_offset
|
58
55
|
end
|
59
56
|
else
|
60
57
|
r, w = tmp = IO.pipe
|
61
58
|
close.concat(tmp)
|
59
|
+
rv = 0
|
62
60
|
if len
|
63
61
|
while len != 0 && n = partial(src, w, len, src_offset)
|
64
62
|
src_offset += n if src_offset
|
63
|
+
rv += n
|
65
64
|
len -= full(r, dst, n, nil)
|
66
65
|
end
|
67
66
|
else
|
68
|
-
|
69
|
-
while n = partial(src, w, PIPE_CAPA, src_offset)
|
67
|
+
while n = partial(src, w, MAX_AT_ONCE, src_offset)
|
70
68
|
src_offset += n if src_offset
|
71
69
|
rv += full(r, dst, n, nil)
|
72
70
|
end
|
data/test/test_tcp_splice.rb
CHANGED
@@ -46,4 +46,21 @@ class TestTCPCopyStream < Test::Unit::TestCase
|
|
46
46
|
bytes = IO::Splice.copy_stream(@accept, "/dev/null", expect)
|
47
47
|
assert_equal expect, bytes
|
48
48
|
end
|
49
|
+
|
50
|
+
def test_mega_splice
|
51
|
+
nr = 2000
|
52
|
+
buf = '0123456789abcdef' * 1024
|
53
|
+
expect = buf.size * nr
|
54
|
+
thr = Thread.new do
|
55
|
+
nr.times { @client.write(buf) }
|
56
|
+
@client.close
|
57
|
+
end
|
58
|
+
size_t_max = if (1 << 30).kind_of?(Bignum)
|
59
|
+
0xffffffff
|
60
|
+
else
|
61
|
+
0xffffffffffffffff
|
62
|
+
end
|
63
|
+
bytes = IO::Splice.copy_stream(@accept, "/dev/null", size_t_max)
|
64
|
+
assert_equal expect, bytes
|
65
|
+
end
|
49
66
|
end
|
metadata
CHANGED
@@ -1,63 +1,75 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
2
|
-
name:
|
3
|
-
|
4
|
-
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: !binary |-
|
3
|
+
aW9fc3BsaWNl
|
4
|
+
version: !ruby/object:Gem::Version
|
5
|
+
version: 4.2.0
|
5
6
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 4
|
8
|
-
- 1
|
9
|
-
- 1
|
10
|
-
version: 4.1.1
|
11
7
|
platform: ruby
|
12
|
-
authors:
|
13
|
-
-
|
8
|
+
authors:
|
9
|
+
- !binary |-
|
10
|
+
UnVieSBpb19zcGxpY2UgaGFja2Vycw==
|
14
11
|
autorequire:
|
15
12
|
bindir: bin
|
16
13
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
14
|
+
date: 2013-01-19 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: !binary |-
|
18
|
+
d3Jvbmdkb2M=
|
19
|
+
requirement: !ruby/object:Gem::Requirement
|
24
20
|
none: false
|
25
|
-
requirements:
|
26
|
-
- -
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
- 5
|
32
|
-
version: "1.5"
|
21
|
+
requirements:
|
22
|
+
- - !binary |-
|
23
|
+
fj4=
|
24
|
+
- !ruby/object:Gem::Version
|
25
|
+
version: !binary |-
|
26
|
+
MS41
|
33
27
|
type: :development
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: rack
|
37
28
|
prerelease: false
|
38
|
-
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - !binary |-
|
33
|
+
fj4=
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: !binary |-
|
36
|
+
MS41
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: !binary |-
|
39
|
+
cmFjaw==
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
39
41
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
- 2
|
47
|
-
version: "1.2"
|
42
|
+
requirements:
|
43
|
+
- - !binary |-
|
44
|
+
fj4=
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: !binary |-
|
47
|
+
MS4y
|
48
48
|
type: :development
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - !binary |-
|
54
|
+
fj4=
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: !binary |-
|
57
|
+
MS4y
|
58
|
+
description: ! 'The splice family of Linux system calls can transfer data between
|
59
|
+
file
|
60
|
+
|
52
61
|
descriptors without the need to copy data into userspace. Instead of a
|
62
|
+
|
53
63
|
userspace buffer, they rely on an ordinary Unix pipe as a kernel-level
|
54
|
-
buffer.
|
55
|
-
email: ruby.io.splice@librelist.com
|
56
|
-
executables: []
|
57
64
|
|
58
|
-
|
59
|
-
|
60
|
-
|
65
|
+
buffer.'
|
66
|
+
email: !binary |-
|
67
|
+
cnVieS5pby5zcGxpY2VAbGlicmVsaXN0Lm9yZw==
|
68
|
+
executables: []
|
69
|
+
extensions:
|
70
|
+
- !binary |-
|
71
|
+
ZXh0L2lvX3NwbGljZS9leHRjb25mLnJi
|
72
|
+
extra_rdoc_files:
|
61
73
|
- README
|
62
74
|
- LICENSE
|
63
75
|
- NEWS
|
@@ -66,7 +78,7 @@ extra_rdoc_files:
|
|
66
78
|
- lib/io/splice/mri_18.rb
|
67
79
|
- ext/io_splice/io_splice_ext.c
|
68
80
|
- LATEST
|
69
|
-
files:
|
81
|
+
files:
|
70
82
|
- .document
|
71
83
|
- .gitignore
|
72
84
|
- .manifest
|
@@ -99,44 +111,43 @@ files:
|
|
99
111
|
- test/test_tcp_splice.rb
|
100
112
|
homepage: http://bogomips.org/ruby_io_splice/
|
101
113
|
licenses: []
|
102
|
-
|
103
114
|
post_install_message:
|
104
|
-
rdoc_options:
|
115
|
+
rdoc_options:
|
105
116
|
- -t
|
106
117
|
- io_splice - zero-copy pipe I/O for Linux and Ruby
|
107
118
|
- -W
|
108
119
|
- http://bogomips.org/ruby_io_splice.git/tree/%s
|
109
|
-
require_paths:
|
120
|
+
require_paths:
|
110
121
|
- lib
|
111
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
123
|
none: false
|
113
|
-
requirements:
|
114
|
-
- -
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
|
117
|
-
|
118
|
-
- 0
|
119
|
-
version: "0"
|
120
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
124
|
+
requirements:
|
125
|
+
- - ! '>='
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
version: '0'
|
128
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
129
|
none: false
|
122
|
-
requirements:
|
123
|
-
- -
|
124
|
-
- !ruby/object:Gem::Version
|
125
|
-
|
126
|
-
segments:
|
127
|
-
- 0
|
128
|
-
version: "0"
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
129
134
|
requirements: []
|
130
|
-
|
131
|
-
|
132
|
-
rubygems_version: 1.8.
|
135
|
+
rubyforge_project: !binary |-
|
136
|
+
cXJw
|
137
|
+
rubygems_version: 1.8.23
|
133
138
|
signing_key:
|
134
139
|
specification_version: 3
|
135
140
|
summary: zero-copy pipe I/O for Linux and Ruby
|
136
|
-
test_files:
|
137
|
-
-
|
138
|
-
|
139
|
-
-
|
140
|
-
|
141
|
-
-
|
142
|
-
|
141
|
+
test_files:
|
142
|
+
- !binary |-
|
143
|
+
dGVzdC90ZXN0X3JhY2tfZmlsZV9jb21wYXQucmI=
|
144
|
+
- !binary |-
|
145
|
+
dGVzdC90ZXN0X2lvX3NwbGljZV9pbl9mdWxsLnJi
|
146
|
+
- !binary |-
|
147
|
+
dGVzdC90ZXN0X3RjcF9zcGxpY2UucmI=
|
148
|
+
- !binary |-
|
149
|
+
dGVzdC90ZXN0X2lvX3NwbGljZS5yYg==
|
150
|
+
- !binary |-
|
151
|
+
dGVzdC90ZXN0X2NvcHlfc3RyZWFtLnJi
|
152
|
+
- !binary |-
|
153
|
+
dGVzdC90ZXN0X2lvX3NwbGljZV9laW50ci5yYg==
|