fdatasync()でデータベースの性能を向上させる

データベースの更新(追加・更新・削除)性能は、コミットの性能に大きく依存するといって過言ではありません。これはdb4oも例外ではありません。というのも、今日のコンピューターでは、いろんな層でバッファリングされていますが、コミット時にだけ、確実にハードディスクにアクセスしなければならないタイミングがあるからです。(どうしてハードディスクへのアクセスがそんなに問題かはこちらのコラムを参照)

抜本的にデータベースの性能をアップするのは大変な作業ですが、データベースをそのままで、このコミット性能を向上させる方法があります。

POSIX互換のOSでは、fsync()だけでなく、fdatasync()も提供されています。これは、ファイルの更新日時などのメタデータを書き込まないようになっています。通常デフォルトではデータベースからの呼び出しはfsync()になるので、それをこのfdatasync()に変えるだけで、通常10-20%程度の性能向上が得られます。

このテクニックはdb4oにも応用可能です。db4oはIoAdapterというアダプターでI/O操作を抽象化していますので、ここからJNIでPOSIXのfdatasync()を呼び出せばいいのです。

以下は簡単なサンプルです。IoAdapterについてはこちらにチュートリアルがあります。

Code:

#include <jni.h>
#include "LinuxIoAdapter.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
/*
* Class:     LinuxIoAdapter
* Method:    openFile
* Signature: (Ljava/lang/String;ZJ)J
*/
JNIEXPORT jint JNICALL Java_LinuxIoAdapter_openFile
  (JNIEnv *env, jclass jc, jstring path, jboolean lockfile, jlong initiallength)
{
    printf("openFile\n");
    const jbyte *filename = (*env)->GetStringUTFChars(env, path, NULL);
 
    if(filename == NULL){
        return 0; // OutOfMemoryError or NULL value
    }
 
    int fd = open(filename, O_RDWR|O_CREAT, 0644);
 
    if(fd < 0){
        printf("open failed\n");
    }
 
    (*env)->ReleaseStringChars(env, path, NULL);
 
    return fd;
 
}
 
/*
* Class:     LinuxIoAdapter
* Method:    closeFile
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_LinuxIoAdapter_closeFile
  (JNIEnv * env, jclass jc, jint handle)
{
    printf("closeFile\n");
    if(close(handle) < 0){
        printf("close failed\n");
    }
 
}
 
/*
* Class:     LinuxIoAdapter
* Method:    getLength
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_LinuxIoAdapter_getLength
  (JNIEnv *env, jclass jc, jint handle)
{
    struct stat st;
    fstat(handle, &st);
    return st.st_size;
}
 
/*
* Class:     LinuxIoAdapter
* Method:    read
* Signature: (J[BI)I
*/
JNIEXPORT jint JNICALL Java_LinuxIoAdapter_read
  (JNIEnv *env, jclass jc, jint handle, jbyteArray bytes, jint length)
{
    
    jbyte buf[length];
 
    ssize_t n = read(handle, &buf, length);
 
    if(n != length)
        printf("read failed: %i->%i", length, n);
 
    (*env)->SetByteArrayRegion(env, bytes, 0, length, buf);
 
    return n;
}
 
/*
* Class:     LinuxIoAdapter
* Method:    seek
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_LinuxIoAdapter_seek
  (JNIEnv *env, jclass jc, jint handle, jlong pos)
{
 
    lseek(handle, pos, SEEK_SET);
}
 
/*
* Class:     LinuxIoAdapter
* Method:    sync
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_LinuxIoAdapter_sync
  (JNIEnv *env, jclass jc, jint handle)
{
    fdatasync(handle);
    //fsync(handle);
}
 
/*
* Class:     LinuxIoAdapter
* Method:    write
* Signature: (J[BI)V
*/
JNIEXPORT void JNICALL Java_LinuxIoAdapter_write
  (JNIEnv *env, jclass jc, jint handle, jbyteArray bytes, jint length)
{
    jbyte buf[length];
 
    (*env)->GetByteArrayRegion(env, bytes, 0, length, buf);
 
    ssize_t n = write(handle, &buf, length);
 
    if(n != length)
        printf("read failed: %i->%i", length, n);
}
Free Blog Themes and Free Blog Templates