[前][次][番号順一覧][スレッド一覧]

ruby-changes:18209

From: kosaki <ko1@a...>
Date: Fri, 17 Dec 2010 00:10:34 +0900 (JST)
Subject: [ruby-changes:18209] Ruby:r30229 (trunk): * io.c (rb_io_advise): New API. IO#advise() allows to tell the

kosaki	2010-12-17 00:01:55 +0900 (Fri, 17 Dec 2010)

  New Revision: 30229

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30229

  Log:
    * 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.

  Modified files:
    trunk/ChangeLog
    trunk/configure.in
    trunk/io.c
    trunk/test/ruby/test_io.rb

Index: configure.in
===================================================================
--- configure.in	(revision 30228)
+++ configure.in	(revision 30229)
@@ -1291,7 +1291,7 @@
 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\
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 30228)
+++ ChangeLog	(revision 30229)
@@ -1,3 +1,14 @@
+Fri Dec 17 00:05:40 2010  KOSAKI Motohiro  <kosaki.motohiro@g...>
+
+	* 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@r...>
 
 	* tool/rbinstall.rb (bin-comm): use transformed name.
Index: io.c
===================================================================
--- io.c	(revision 30228)
+++ io.c	(revision 30229)
@@ -1,3 +1,4 @@
+
 /**********************************************************************
 
   io.c -
@@ -7389,8 +7390,159 @@
 }
 #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
  *               [, write_array
  *               [, error_array
@@ -10191,6 +10343,7 @@
     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 @@
     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
 }
Index: test/ruby/test_io.rb
===================================================================
--- test/ruby/test_io.rb	(revision 30228)
+++ test/ruby/test_io.rb	(revision 30229)
@@ -1737,4 +1737,38 @@
       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

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]