methodmissing-vio 0.1.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/README +37 -0
- data/Rakefile +68 -0
- data/ext/vio/extconf.rb +13 -0
- data/ext/vio/vio.c +116 -0
- data/vio.gemspec +22 -0
- metadata +59 -0
data/README
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
Vectored I/O for Ruby MRI
|
2
|
+
(c) 2009 Lourens Naudé (methodmissing)
|
3
|
+
|
4
|
+
http://github.com/methodmissing/vio
|
5
|
+
|
6
|
+
Vectored I/O ?
|
7
|
+
|
8
|
+
POSIX 1003.1-2001 introduces reading or writing data into multiple buffers with a single procedure call.See http://en.wikipedia.org/wiki/Vectored_I/O for an overview.
|
9
|
+
|
10
|
+
Use cases :
|
11
|
+
|
12
|
+
* Write non-sequentially placed data in memory to disk with a single write operation.This fits very well with custom database/record formats for writing out indexes and data at once.
|
13
|
+
* Reducing syscall overheads
|
14
|
+
* Reading structured data (protocol dumps,db records) into distinct buffers
|
15
|
+
|
16
|
+
Examples :
|
17
|
+
|
18
|
+
8=FIX.4.49=4535=049=TW56=ISLD34=352=20000426-12:05:0610=220
|
19
|
+
|
20
|
+
>>io = File.open('/path/to/fix.txt'))
|
21
|
+
=> #<File://path/to/fix.txt>
|
22
|
+
>>io.read([9, 5, 5, 6, 8, 26, 8])
|
23
|
+
=> ["8=FIX.4.4","\x019=45", "\x0135=0", "\x0149=TW", "\x0156=ISLD",
|
24
|
+
"\x0134=3\x0152=20000426-12:05:06", "\x0110=220\x01"]
|
25
|
+
|
26
|
+
Todo :
|
27
|
+
|
28
|
+
* Error handling for rewind
|
29
|
+
* An API that doesn't impose array arguments
|
30
|
+
|
31
|
+
To run the test suite:
|
32
|
+
|
33
|
+
rake
|
34
|
+
|
35
|
+
To run the benchmarks:
|
36
|
+
|
37
|
+
rake bench
|
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/clean'
|
4
|
+
$:.unshift(File.expand_path('lib'))
|
5
|
+
VIO_ROOT = 'ext/vio'
|
6
|
+
|
7
|
+
desc 'Default: test'
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
desc 'Run VIO tests.'
|
11
|
+
Rake::TestTask.new(:test) do |t|
|
12
|
+
t.libs = [VIO_ROOT]
|
13
|
+
t.pattern = 'test/test_*.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
task :test => :build
|
17
|
+
|
18
|
+
namespace :build do
|
19
|
+
file "#{VIO_ROOT}/vio.c"
|
20
|
+
file "#{VIO_ROOT}/extconf.rb"
|
21
|
+
file "#{VIO_ROOT}/Makefile" => %W(#{VIO_ROOT}/vio.c #{VIO_ROOT}/extconf.rb) do
|
22
|
+
Dir.chdir(VIO_ROOT) do
|
23
|
+
ruby 'extconf.rb'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "generate makefile"
|
28
|
+
task :makefile => %W(#{VIO_ROOT}/Makefile #{VIO_ROOT}/vio.c)
|
29
|
+
|
30
|
+
dlext = Config::CONFIG['DLEXT']
|
31
|
+
file "#{VIO_ROOT}/vio.#{dlext}" => %W(#{VIO_ROOT}/Makefile #{VIO_ROOT}/vio.c) do
|
32
|
+
Dir.chdir(VIO_ROOT) do
|
33
|
+
sh 'make' # TODO - is there a config for which make somewhere?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "compile vio extension"
|
38
|
+
task :compile => "#{VIO_ROOT}/vio.#{dlext}"
|
39
|
+
|
40
|
+
task :clean do
|
41
|
+
Dir.chdir(VIO_ROOT) do
|
42
|
+
sh 'make clean'
|
43
|
+
end if File.exists?("#{VIO_ROOT}/Makefile")
|
44
|
+
end
|
45
|
+
|
46
|
+
CLEAN.include("#{VIO_ROOT}/Makefile")
|
47
|
+
CLEAN.include("#{VIO_ROOT}/vio.#{dlext}")
|
48
|
+
end
|
49
|
+
|
50
|
+
task :clean => %w(build:clean)
|
51
|
+
|
52
|
+
desc "compile"
|
53
|
+
task :build => %w(build:compile)
|
54
|
+
|
55
|
+
task :install do |t|
|
56
|
+
Dir.chdir(VIO_ROOT) do
|
57
|
+
sh 'sudo make install'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
desc "clean build install"
|
62
|
+
task :setup => %w(clean build install)
|
63
|
+
|
64
|
+
desc "run benchmarks"
|
65
|
+
task :bench do |t|
|
66
|
+
ruby "bench/read.rb"
|
67
|
+
end
|
68
|
+
task :bench => :build
|
data/ext/vio/extconf.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
def add_define(name)
|
4
|
+
$defs.push("-D#{name}")
|
5
|
+
end
|
6
|
+
|
7
|
+
dir_config('vio')
|
8
|
+
add_define 'RUBY19' if have_func('rb_thread_blocking_region') and have_macro('RUBY_UBF_IO', 'ruby.h')
|
9
|
+
add_define 'RUBY18' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
|
10
|
+
|
11
|
+
$defs.push("-pedantic")
|
12
|
+
|
13
|
+
create_makefile('vio')
|
data/ext/vio/vio.c
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <sys/types.h>
|
3
|
+
#include <sys/uio.h>
|
4
|
+
#include <unistd.h>
|
5
|
+
|
6
|
+
#ifndef RSTRING_PTR
|
7
|
+
#define RSTRING_PTR(obj) RSTRING(obj)->ptr
|
8
|
+
#endif
|
9
|
+
|
10
|
+
#ifndef RSTRING_LEN
|
11
|
+
#define RSTRING_LEN(obj) RSTRING(obj)->len
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#ifndef RARRAY_PTR
|
15
|
+
#define RARRAY_PTR(obj) RARRAY(obj)->ptr
|
16
|
+
#endif
|
17
|
+
|
18
|
+
#ifndef RARRAY_LEN
|
19
|
+
#define RARRAY_LEN(obj) RARRAY(obj)->len
|
20
|
+
#endif
|
21
|
+
|
22
|
+
#ifdef RUBY19
|
23
|
+
#include "ruby/io.h"
|
24
|
+
#define TRAP_BEG
|
25
|
+
#define TRAP_END
|
26
|
+
#else
|
27
|
+
#include "rubysig.h"
|
28
|
+
#include "rubyio.h"
|
29
|
+
#endif
|
30
|
+
|
31
|
+
static VALUE
|
32
|
+
vio_read(VALUE io, VALUE iov)
|
33
|
+
{
|
34
|
+
Check_Type(iov, T_ARRAY);
|
35
|
+
int fd;
|
36
|
+
#ifdef RUBY19
|
37
|
+
rb_io_t *fptr;
|
38
|
+
#else
|
39
|
+
OpenFile *fptr;
|
40
|
+
#endif
|
41
|
+
if (RARRAY_LEN(iov) == 0) rb_raise(rb_eIOError, "No buffer offsets given");
|
42
|
+
GetOpenFile(io, fptr);
|
43
|
+
rb_io_check_readable(fptr);
|
44
|
+
#ifdef RUBY19
|
45
|
+
fd = fptr->fd;
|
46
|
+
#else
|
47
|
+
fd = fileno(fptr->f);
|
48
|
+
#endif
|
49
|
+
/* XXX Todo: Error handling */
|
50
|
+
lseek(fd, 0L, SEEK_SET);
|
51
|
+
fptr->lineno = 0;
|
52
|
+
struct iovec iovs[IOV_MAX];
|
53
|
+
int i, size, bytes_read;
|
54
|
+
int expected = 0;
|
55
|
+
int cnt = RARRAY_LEN(iov);
|
56
|
+
VALUE results = rb_ary_new2(cnt);
|
57
|
+
for (i=0; i < cnt; i++) {
|
58
|
+
size = FIX2INT(RARRAY_PTR(iov)[i]);
|
59
|
+
expected = expected + size;
|
60
|
+
iovs[i].iov_len = size;
|
61
|
+
iovs[i].iov_base = malloc(size);
|
62
|
+
}
|
63
|
+
bytes_read = readv(fd,iovs,cnt);
|
64
|
+
if (bytes_read < expected) rb_raise(rb_eIOError, "Vectored I/O read failure!");
|
65
|
+
for (i=0; i < cnt; i++) {
|
66
|
+
rb_ary_push(results, rb_tainted_str_new((char *)iovs[i].iov_base, iovs[i].iov_len));
|
67
|
+
}
|
68
|
+
return results;
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE
|
72
|
+
vio_write(VALUE io, VALUE iov)
|
73
|
+
{
|
74
|
+
Check_Type(iov, T_ARRAY);
|
75
|
+
int fd;
|
76
|
+
#ifdef RUBY19
|
77
|
+
rb_io_t *fptr;
|
78
|
+
#else
|
79
|
+
OpenFile *fptr;
|
80
|
+
#endif
|
81
|
+
if (RARRAY_LEN(iov) == 0) rb_raise(rb_eIOError, "No buffers to write given");
|
82
|
+
GetOpenFile(io, fptr);
|
83
|
+
rb_io_check_writable(fptr);
|
84
|
+
#ifdef RUBY19
|
85
|
+
fd = fptr->fd;
|
86
|
+
#else
|
87
|
+
fd = fileno(fptr->f);
|
88
|
+
#endif
|
89
|
+
/* XXX Todo: Error handling */
|
90
|
+
lseek(fd, 0L, SEEK_SET);
|
91
|
+
fptr->lineno = 0;
|
92
|
+
struct iovec iovs[IOV_MAX];
|
93
|
+
int i, size, bytes_written;
|
94
|
+
int expected = 0;
|
95
|
+
int cnt = RARRAY_LEN(iov);
|
96
|
+
VALUE results = rb_ary_new2(cnt);
|
97
|
+
for (i=0; i < cnt; i++) {
|
98
|
+
VALUE str = RARRAY_PTR(iov)[i];
|
99
|
+
size = RSTRING_LEN(str);
|
100
|
+
expected = expected + size;
|
101
|
+
iovs[i].iov_len = size;
|
102
|
+
iovs[i].iov_base = RSTRING_PTR(str);
|
103
|
+
}
|
104
|
+
bytes_written = writev(fd,iovs,cnt);
|
105
|
+
if (bytes_written < expected) rb_raise(rb_eIOError, "Vectored I/O write failure!");
|
106
|
+
for (i=0; i < cnt; i++) {
|
107
|
+
rb_ary_push(results, INT2FIX(iovs[i].iov_len));
|
108
|
+
}
|
109
|
+
return results;
|
110
|
+
}
|
111
|
+
|
112
|
+
void Init_vio()
|
113
|
+
{
|
114
|
+
rb_define_method(rb_cIO, "readv", vio_read, 1);
|
115
|
+
rb_define_method(rb_cIO, "writev", vio_write, 1);
|
116
|
+
}
|
data/vio.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "vio"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = "2009-09-19"
|
5
|
+
s.summary = "Vectored I/O extension for Ruby"
|
6
|
+
s.email = "lourens@methodmissing.com"
|
7
|
+
s.homepage = "http://github.com/methodmissing/vio"
|
8
|
+
s.description = "Vectored I/O extension for Ruby MRI (1.8.{6,7} and 1.9.2)"
|
9
|
+
s.has_rdoc = true
|
10
|
+
s.authors = ["Lourens Naudé (methodmissing)"]
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.files = %w[
|
13
|
+
README
|
14
|
+
Rakefile
|
15
|
+
ext/vio/extconf.rb
|
16
|
+
ext/vio/vio.c
|
17
|
+
vio.gemspec
|
18
|
+
] + Dir.glob('test/*')
|
19
|
+
s.rdoc_options = ["--main", "README"]
|
20
|
+
s.extra_rdoc_files = ["README"]
|
21
|
+
s.extensions << "ext/vio/extconf.rb"
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: methodmissing-vio
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Lourens Naud\xC3\xA9 (methodmissing)"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-19 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Vectored I/O extension for Ruby MRI (1.8.{6,7} and 1.9.2)
|
17
|
+
email: lourens@methodmissing.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- ext/vio/extconf.rb
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- Rakefile
|
27
|
+
- ext/vio/extconf.rb
|
28
|
+
- ext/vio/vio.c
|
29
|
+
- vio.gemspec
|
30
|
+
has_rdoc: true
|
31
|
+
homepage: http://github.com/methodmissing/vio
|
32
|
+
licenses:
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options:
|
35
|
+
- --main
|
36
|
+
- README
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.3.5
|
55
|
+
signing_key:
|
56
|
+
specification_version: 2
|
57
|
+
summary: Vectored I/O extension for Ruby
|
58
|
+
test_files: []
|
59
|
+
|