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.
Files changed (6) hide show
  1. data/README +37 -0
  2. data/Rakefile +68 -0
  3. data/ext/vio/extconf.rb +13 -0
  4. data/ext/vio/vio.c +116 -0
  5. data/vio.gemspec +22 -0
  6. 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
@@ -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
@@ -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')
@@ -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
+ }
@@ -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
+