io_splice 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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==
|