[Senna-dev 1023] sen_table_factory

Back to archive index

Kouhei Sutou kou****@cozmi*****
2008年 9月 12日 (金) 11:00:02 JST


須藤です。

sen_table_create()の中にはencodingなどいくつかデフォルト値があるものがあります。
また、pathを指定しているときはsen_obj_flagsにSEN_OBJ_PERSISTENTフラグを立て
ないとダメ、みたいなちょっとした約束事もあります。

デフォルト値は指定しなくても使える、ちょっとした約束はうまいことやってくれる、
などをやってsen_table_create()を便利に使えるようにするsen_table_factoryオブジェクト
を作るのはどうでしょうか?

で、気になるのは遅くなるんじゃないかということだと思いますが、大したことはない
ようです。最後にベンチマークを含むサンプル実装をつけてあります。ベンチマークでは
100回sen_table_create()をしています。ということで、sen_table_factoryオブジェクトを
導入しませんか?(プログラムはGLibを使っているので`pkg-config --cflags --libs glib-2.0`
付きでビルドしてください。)

結果:
--
 normal (persistent): (1.07456)
factory (persistent): (1.05743)
 normal (temporary) : (0.640719)
factory (temporary) : (0.684413)
--

/* -*- c-basic-offset: 2 -*- */

#include <errno.h>
#include <stdlib.h>
#include <string.h>

#include <glib.h>
#include <glib/gstdio.h>

#include <senna.h>
extern sen_ctx sen_gctx;

#define DEFAULT_FLAGS (SEN_OBJ_PERSISTENT | SEN_OBJ_TABLE_PAT_KEY)
#define DEFAULT_VALUE_SIZE (1024)

gboolean
bench_utils_remove_path (const char *path, GError **error)
{
    if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
        g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
                    "path doesn't exist: %s", path);
        return FALSE;
    }

    if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
        if (g_rmdir(path) == -1) {
            g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
                        "can't remove directory: %s", path);
            return FALSE;
        }
    } else {
        if (g_unlink(path) == -1) {
            g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
                        "can't remove path: %s", path);
            return FALSE;
        }
    }

    return TRUE;
}

gboolean
bench_utils_remove_path_recursive (const char *path, GError **error)
{
    if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
        GDir *dir;
        const gchar *name;

        dir = g_dir_open(path, 0, error);
        if (!dir)
            return FALSE;

        while ((name = g_dir_read_name(dir))) {
            const gchar *full_path;

            full_path = g_build_filename(path, name, NULL);
            if (!bench_utils_remove_path_recursive(full_path, error))
                return FALSE;
        }

        g_dir_close(dir);

        return bench_utils_remove_path(path, error);
    } else {
        return bench_utils_remove_path(path, error);
    }

    return TRUE;
}

void
bench_utils_remove_path_recursive_force (const gchar *path)
{
    bench_utils_remove_path_recursive(path, NULL);
}

typedef struct _BenchmarkData
{
  gchar *base_dir;
  gchar *space_path;

  sen_ctx *context;
  sen_obj *space;
  const char *name;
  unsigned name_size;
  char *path;
  sen_obj_flags flags;
  sen_obj *key_type;
  unsigned value_size;
  sen_encoding encoding;
} BenchmarkData;

typedef void (*BenchmarkSetupFunc) (gpointer user_data);
typedef void (*BenchmarkFunc) (gpointer user_data);
typedef void (*BenchmarkTeardownFunc) (gpointer user_data);

static void
bench_report(const gchar *label, gint n,
             BenchmarkSetupFunc benchmark_setup,
             BenchmarkFunc benchmark,
             BenchmarkTeardownFunc benchmark_teardown,
             gpointer data)
{
  GTimer *timer;
  gint i;

  g_print("%s: ", label);
  timer = g_timer_new();
  g_timer_stop(timer);
  g_timer_reset(timer);
  for (i = 0; i < n; i++) {
    benchmark_setup(data);
    g_timer_continue(timer);
    benchmark(data);
    g_timer_stop(timer);
    benchmark_teardown(data);
  }
  g_print("(%g)\n", g_timer_elapsed(timer, NULL));
}

static void
bench_normal(gpointer user_data)
{
  BenchmarkData *data = user_data;
  sen_obj *table;

  table = sen_table_create(data->context, data->space,
                           data->name, data->name_size,
                           data->path, data->flags,
                           data->key_type, data->value_size,
                           data->encoding);
  sen_obj_close(data->context, table);
}

static void
bench_normal_temporary(gpointer user_data)
{
  BenchmarkData *data = user_data;
  sen_obj *table;

  table = sen_table_create(data->context, data->space,
                           data->name, data->name_size,
                           NULL, data->flags & ~SEN_OBJ_PERSISTENT,
                           data->key_type, data->value_size,
                           data->encoding);
  sen_obj_close(data->context, table);
}

typedef struct _sen_table_factory
{
  sen_ctx *context;
  sen_obj *space;
  char *name;
  unsigned name_size;
  char *path;
  sen_obj_flags flags;
  sen_obj *key_type;
  unsigned value_size;
  sen_encoding encoding;
} sen_table_factory;

static sen_table_factory *
sen_table_factory_create(void)
{
  sen_table_factory *factory;

  factory = g_new0(sen_table_factory, 1);

  factory->context = &sen_gctx;
  factory->space = NULL;
  factory->name = NULL;
  factory->name_size = 0;
  factory->path = NULL;
  factory->flags = DEFAULT_FLAGS;
  factory->key_type = NULL;
  factory->value_size = DEFAULT_VALUE_SIZE;
  factory->encoding = sen_enc_default;

  return factory;
}

static void
sen_table_factory_set_context(sen_table_factory *factory, sen_ctx *context)
{
  factory->context = context;
}

static void
sen_table_factory_set_space(sen_table_factory *factory, sen_obj *space)
{
  factory->space = space;
}

static void
sen_table_factory_set_name(sen_table_factory *factory, const char *name)
{
  factory->name = g_strdup(name);
  factory->name_size = strlen(name);
}

static void
sen_table_factory_set_path(sen_table_factory *factory, const char *path)
{
  factory->path = g_strdup(path);
  if (path)
    factory->flags |= SEN_OBJ_PERSISTENT;
  else
    factory->flags &= ~SEN_OBJ_PERSISTENT;
}

static void
sen_table_factory_set_key_type(sen_table_factory *factory, sen_obj *key_type)
{
  factory->key_type = key_type;
}

static sen_obj *
sen_table_factory_make(sen_table_factory *factory)
{
  return sen_table_create(factory->context, factory->space,
                          factory->name, factory->name_size,
                          factory->path, factory->flags,
                          factory->key_type, factory->value_size,
                          factory->encoding);
}

static void
sen_table_factory_close(sen_table_factory *factory)
{
  g_free(factory->name);
  g_free(factory->path);
  g_free(factory);
}

static void
bench_factory(gpointer user_data)
{
  BenchmarkData *data = user_data;
  sen_table_factory *factory;
  sen_obj *table;

  factory = sen_table_factory_create();
  sen_table_factory_set_context(factory, data->context);
  sen_table_factory_set_space(factory, data->space);
  sen_table_factory_set_name(factory, data->name);
  sen_table_factory_set_path(factory, data->path);
  sen_table_factory_set_key_type(factory, data->key_type);

  table = sen_table_factory_make(factory);
  sen_obj_close(data->context, table);

  sen_table_factory_close(factory);
}

static void
bench_factory_temporary(gpointer user_data)
{
  BenchmarkData *data = user_data;
  sen_table_factory *factory;
  sen_obj *table;

  factory = sen_table_factory_create();
  sen_table_factory_set_context(factory, data->context);
  sen_table_factory_set_space(factory, data->space);
  sen_table_factory_set_name(factory, data->name);
  sen_table_factory_set_key_type(factory, data->key_type);

  table = sen_table_factory_make(factory);
  sen_obj_close(data->context, table);

  sen_table_factory_close(factory);
}

static void
bench_setup(gpointer user_data)
{
  BenchmarkData *data = user_data;
  const gchar *type_name;

  bench_utils_remove_path_recursive_force(data->base_dir);
  g_mkdir_with_parents(data->base_dir, 0755);

  data->context = sen_ctx_open(NULL, SEN_CTX_USEQL);
  data->space = sen_space_create(data->context, NULL,
                                 data->space_path, sen_enc_default);

  type_name = "name";
  data->key_type = sen_type_create(data->context, data->space,
                                   type_name, strlen(type_name),
                                   SEN_OBJ_FIXED_SIZE, sizeof(sen_id));

}

static void
bench_teardown(gpointer user_data)
{
  BenchmarkData *data = user_data;

  sen_obj_close(data->context, data->key_type);
  sen_obj_close(data->context, data->space);
  sen_ctx_close(data->context);
  bench_utils_remove_path_recursive_force(data->base_dir);
}

int
main(int argc, gchar **argv)
{
  BenchmarkData data;

  sen_init();

  data.base_dir = g_build_filename(g_get_tmp_dir(), "senna-bench", NULL);
  data.space_path = g_build_filename(data.base_dir, "space", NULL);
  data.name = "table";
  data.name_size = strlen(data.name);
  data.path = g_build_filename(data.base_dir, "table", NULL);
  data.flags = DEFAULT_FLAGS;
  data.key_type = NULL;
  data.value_size = DEFAULT_VALUE_SIZE;
  data.encoding = sen_enc_default;

  bench_report(" normal (persistent)", 100,
               bench_setup, bench_normal, bench_teardown, &data);
  bench_report("factory (persistent)",
               100, bench_setup, bench_factory, bench_teardown, &data);
  bench_report(" normal (temporary) ", 100,
               bench_setup, bench_normal_temporary, bench_teardown, &data);
  bench_report("factory (temporary) ",
               100, bench_setup, bench_factory_temporary,
bench_teardown, &data);

  bench_utils_remove_path_recursive_force(data.base_dir);

  g_free(data.path);
  g_free(data.space_path);
  g_free(data.base_dir);

  sen_fin();

  return 0;
}




Senna-dev メーリングリストの案内
Back to archive index