1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* io.c (rb_io_advise): New API. IO#advise() allows to tell the

ruby runtime how it expects to use a file handle. This feature
          can be improved a performance some situations.
          Note: This feature is mainly developed by Run Paint Run Run.
          Thank you! [ruby-core:33110] [Ruby 1.9-Feature#4038]

        * io.c (do_io_advise): Helper function.
        * io.c (io_advise_sym_to_const): ditto.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30229 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
kosaki 2010-12-16 15:01:55 +00:00
parent e46e5d2438
commit cc9b886691
4 changed files with 207 additions and 1 deletions

View file

@ -1,3 +1,14 @@
Fri Dec 17 00:05:40 2010 KOSAKI Motohiro <kosaki.motohiro@gmail.com>
* io.c (rb_io_advise): New API. IO#advise() allows to tell the
ruby runtime how it expects to use a file handle. This feature
can be improved a performance some situations.
Note: This feature is mainly developed by Run Paint Run Run.
Thank you! [ruby-core:33110] [Ruby 1.9-Feature#4038]
* io.c (do_io_advise): Helper function.
* io.c (io_advise_sym_to_const): ditto.
Thu Dec 16 23:29:20 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* tool/rbinstall.rb (bin-comm): use transformed name.

View file

@ -1291,7 +1291,7 @@ else
fi
AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot getcwd eaccess\
truncate ftruncate chsize times utimes utimensat fcntl lockf lstat\
link symlink readlink readdir_r fsync fdatasync fchown\
link symlink readlink readdir_r fsync fdatasync fchown posix_fadvise\
setitimer setruid seteuid setreuid setresuid setproctitle socketpair\
setrgid setegid setregid setresgid issetugid pause lchown lchmod\
getpgrp setpgrp getpgid setpgid initgroups getgroups setgroups\

161
io.c
View file

@ -1,3 +1,4 @@
/**********************************************************************
io.c -
@ -7389,6 +7390,157 @@ select_end(VALUE arg)
}
#endif
#ifdef HAVE_POSIX_FADVISE
static VALUE sym_normal, sym_sequential, sym_random,
sym_willneed, sym_dontneed, sym_noreuse;
struct io_advise_struct {
int fd;
off_t offset;
off_t len;
int advice;
};
static VALUE
io_advise_internal(void *arg)
{
struct io_advise_struct *ptr = arg;
return posix_fadvise(ptr->fd, ptr->offset, ptr->len, ptr->advice);
}
static VALUE io_advise_sym_to_const(VALUE sym)
{
#ifdef POSIX_FADV_NORMAL
if (sym == sym_normal)
return INT2NUM(POSIX_FADV_NORMAL);
#endif
#ifdef POSIX_FADV_RANDOM
if (sym == sym_random)
return INT2NUM(POSIX_FADV_RANDOM);
#endif
#ifdef POSIX_FADV_SEQUENTIAL
if (sym == sym_sequential)
return INT2NUM(POSIX_FADV_SEQUENTIAL);
#endif
#ifdef POSIX_FADV_WILLNEED
if (sym == sym_willneed)
return INT2NUM(POSIX_FADV_WILLNEED);
#endif
#ifdef POSIX_FADV_DONTNEED
if (sym == sym_dontneed)
return INT2NUM(POSIX_FADV_DONTNEED);
#endif
#ifdef POSIX_FADV_NOREUSE
if (sym == sym_noreuse)
return INT2NUM(POSIX_FADV_NOREUSE);
#endif
return Qnil;
}
static VALUE
do_io_advise(rb_io_t *fptr, VALUE advice, off_t offset, off_t len)
{
int rv;
struct io_advise_struct ias;
VALUE num_adv;
num_adv = io_advise_sym_to_const(advice);
/*
* The platform doesn't support this hint. We don't raise exception, instead
* silently ignore it. Because IO::advise is only hint.
*/
if (num_adv == Qnil)
return Qnil;
ias.fd = fptr->fd;
ias.advice = NUM2INT(num_adv);
ias.offset = offset;
ias.len = len;
if (rv = (int)rb_thread_blocking_region(io_advise_internal, &ias, RUBY_UBF_IO, 0))
/* posix_fadvise(2) doesn't set errno. On success it returns 0; otherwise
it returns the error code. */
rb_syserr_fail(rv, RSTRING_PTR(fptr->pathv));
return Qnil;
}
#endif /* HAVE_POSIX_FADVISE */
/*
* call-seq:
* ios.advise(advice, offset=0, len=0) -> nil
*
* Announce an intention to access data from the current file in a
* specific pattern. On platforms that do not support the
* <em>posix_fadvise(2)</em> system call, this method is a no-op.
*
* _advice_ is one of the following symbols:
*
* * :normal - No advice to give; the default assumption for an open file.
* * :sequential - The data will be accessed sequentially:
* with lower offsets read before higher ones.
* * :random - The data will be accessed in random order.
* * :willneed - The data will be accessed in the near future.
* * :dontneed - The data will not be accessed in the near future.
* * :noreuse - The data will only be accessed once.
*
* The semantics of a piece of advice are platform-dependent. See
* <em>man 2 posix_fadvise</em> for details.
*
* "data" means the region of the current file that begins at
* _offset_ and extends for _len_ bytes. If _len_ is 0, the region
* ends at the last byte of the file. By default, both _offset_ and
* _len_ are 0, meaning that the advice applies to the entire file.
*
* If an error occurs, one of the following exceptions will be raised:
*
* * <code>IOError</code> - The <code>IO</code> stream is closed.
* * <code>Errno::EBADF</code> - The file descriptor of the current file is
invalid.
* * <code>Errno::EINVAL</code> - An invalid value for _advice_ was given.
* * <code>Errno::ESPIPE</code> - The file descriptor of the current
* * file refers to a FIFO or pipe. (Linux raises <code>Errno::EINVAL</code>
* * in this case).
* * <code>TypeError</code> - Either _advice_ was not a Symbol, or one of the
other arguments was not an <code>Integer</code>.
* * <code>RangeError</code> - One of the arguments given was too big/small.
*
* This list is not exhaustive; other Errno:: exceptions are also possible.
*/
static VALUE
rb_io_advise(int argc, VALUE *argv, VALUE io)
{
int rv;
VALUE advice, offset, len;
off_t off, l;
rb_io_t *fptr;
rb_scan_args(argc, argv, "12", &advice, &offset, &len);
if (TYPE(advice) != T_SYMBOL)
rb_raise(rb_eTypeError, "advice must be a Symbol");
io = GetWriteIO(io);
GetOpenFile(io, fptr);
off = NIL_P(offset) ? 0 : NUM2OFFT(offset);
l = NIL_P(len) ? 0 : NUM2OFFT(len);
#ifdef HAVE_POSIX_FADVISE
return do_io_advise(fptr, advice, off, l);
#else
/* Ignore all hint */
return Qnil;
#endif
}
/*
* call-seq:
* IO.select(read_array
@ -10191,6 +10343,7 @@ Init_IO(void)
rb_define_method(rb_cIO, "binmode", rb_io_binmode_m, 0);
rb_define_method(rb_cIO, "binmode?", rb_io_binmode_p, 0);
rb_define_method(rb_cIO, "sysseek", rb_io_sysseek, -1);
rb_define_method(rb_cIO, "advise", rb_io_advise, -1);
rb_define_method(rb_cIO, "ioctl", rb_io_ioctl, -1);
rb_define_method(rb_cIO, "fcntl", rb_io_fcntl, -1);
@ -10367,4 +10520,12 @@ Init_IO(void)
sym_textmode = ID2SYM(rb_intern("textmode"));
sym_binmode = ID2SYM(rb_intern("binmode"));
sym_autoclose = ID2SYM(rb_intern("autoclose"));
#ifdef HAVE_POSIX_FADVISE
sym_normal = ID2SYM(rb_intern("normal"));
sym_sequential = ID2SYM(rb_intern("sequential"));
sym_random = ID2SYM(rb_intern("random"));
sym_willneed = ID2SYM(rb_intern("willneed"));
sym_dontneed = ID2SYM(rb_intern("dontneed"));
sym_noreuse = ID2SYM(rb_intern("noreuse"));
#endif
}

View file

@ -1737,4 +1737,38 @@ End
end
end
end
def test_advise
t = make_tempfile
assert_raise(ArgumentError, "no arguments") { t.advise }
%w{normal random sequential willneed dontneed noreuse}.map(&:to_sym).each do |adv|
[[0,0], [0, 20], [400, 2]].each do |offset, len|
open(make_tempfile.path) do |t|
assert_equal(t.advise(adv, offset, len), nil)
assert_raise(ArgumentError, "superfluous arguments") do
t.advise(adv, offset, len, offset)
end
assert_raise(TypeError, "wrong type for first argument") do
t.advise(adv.to_s, offset, len)
end
assert_raise(TypeError, "wrong type for last argument") do
t.advise(adv, offset, Array(len))
end
assert_raise(RangeError, "last argument too big") do
t.advise(adv, offset, 9999e99)
end
end
assert_raise(IOError, "closed file") do
make_tempfile.advise(adv.to_sym, offset, len)
end
end
end
%w{Normal rand glark will_need zzzzzzzzzzzz \u2609}.map(&:to_sym).each do |adv|
[[0,0], [0, 20], [400, 2]].each do |offset, len|
open(make_tempfile.path) do |t|
assert_equal(t.advise(adv, offset, len), nil)
end
end
end
end
end