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;
}