自己紹介

太田一樹。
東京の大学の情報科学科に通う大学生。moratorium満喫中。

お勧め書籍 [全部見る]

飾り

Search


Category Archives

Recent Entries

  1. 論文
  2. JJUG CCCでプレゼンします
  3. kzk's bookshelf
  4. En Google by Gulfweed
  5. PNUTS
  6. コメントスパム対策
  7. Hadoop + Luceneで分散インデクシング
  8. Hadoopの解析資料
  9. Cluster 2008
  10. SWoPP 2008

2007年05月18日

splice(2)

Linux 2.6.17より導入された新しいシステムコールである「splice(2)」を使ったファイルコピープログラムを作ってみました。

参考: C言語: UNIX最速ファイルコピー
参考: splice(2) - splice data to/from a pipe

試した環境は以下の通りです。

core2% uname -a
Linux core2 2.6.20-15-generic #2 SMP Sun Apr 15 06:17:24 UTC 2007 x86_64 GNU/Linux

gcc: Ubuntu 4.1.2-0ubuntu4
glibc version: 2.5-0ubuntu14

「splice」という単語は「つなぎ合わせる」とかいう意味です。このシステムコールも、ファイルディスクリプタとパイプをつなぎ合わせてデータを転送するような操作を行う事ができます。

調べていると、何故かWikipediaにコードが有ったのですが、何箇所か気になる所が有ったので直しながら書いてみました。

#include <sys/types.h>
#include <asm/unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <stdio.h>
#include <unistd.h>

#define __USE_GNU
#include <fcntl.h>
#undef __USE_GNU

static int
splice_copy(int srcfd, size_t size, int destfd)
{
  int r;

  int pipedes[2];
  r = pipe(pipedes);
  assert(r >= 0);

  int pipe_r = pipedes[0];
  int pipe_w = pipedes[1];

  size_t written;

  written = 0;
  while (written < size) {
    loff_t off_in = written;
    ssize_t nbytes = splice(srcfd, &off_in, pipe_w, NULL, size - written,
                           SPLICE_F_MORE | SPLICE_F_MOVE);
    assert(nbytes >= 0);
    written += nbytes;
  }

  written = 0;
  while (written < size) {
    loff_t off_out = written;
    ssize_t nbytes = splice(pipe_r, NULL, destfd, &off_out, size - written,
                           SPLICE_F_MORE | SPLICE_F_MOVE);
    assert(nbytes >= 0);
    written += nbytes;
  }

  close(pipe_r);
  close(pipe_w);
  return 0;
}

int
main(int argc, char **argv)
{
  int r;
  struct stat st_buf;

  if (argc < 3) {
    fprintf(stderr, "usage: %s src out\n", argv[0]);
    return 0;
  }

  char *src  = argv[1];
  char *dest = argv[2];
  assert(strcmp(src, dest) != 0);

  int srcfd = open(src, O_RDONLY, 0644);
  assert(srcfd >= 0);

#if USE_FADVISE
  posix_fadvise(srcfd, 0, 0, POSIX_FADV_SEQUENTIAL);
  posix_fadvise(srcfd, 0, 0, POSIX_FADV_NOREUSE);
#endif

  /* get permission */
  r = fstat(srcfd, &st_buf);
  assert(r >= 0);

  int destfd = open(dest, O_WRONLY | O_CREAT, st_buf.st_mode);
  assert(destfd >= 0);

  r = splice_copy(srcfd, st_buf.st_size, destfd);
  assert(r == 0);
  fsync(destfd);

  close(destfd);
  close(srcfd);

  return 0;
}

コードを眺めていると、ファイルディスクリプタがカーネルバッファーへのポインタの様に思えてきます。つまりsplice(2)はカーネルバッファーに対するread(2)やwrite(2)の様なものと説明すると分かりやすいのかな。

sendfile(2)も似たようなものなのですが、sendfile(2)はoutにsocketしか取れないという点が異なっていますね。

カーネルの方の確認 & 速度検証をしたらUNIX最速ファイルコピーの方のデータも更新します。


trackbacks

trackbackURL:

『splice(2)』の関連記事

comments

assertのなかに副作用コードを書くのはあぶなくない?

  • nya
  • 2007年05月18日 11:04

あーそうだね。直すー。どもども。

  • kzk
  • 2007年05月18日 11:50
comment form
comment form