morita
morit****@razil*****
2008年 9月 13日 (土) 07:55:17 JST
森です。
ご提案ありがとうございます。どんな使い勝手が求められているのか
よく伝わりました!
えーと、、今の段階ではflagの値や約束事もまだ固まり切れていないので、
まずはそこをきっちりと作り込みたいと思っています。
その上でsen_table_create()等を今より扱いやすいシグネチャに改良することを
検討したいと思います。
Kouhei Sutou さんは書きました:
> 須藤です。
>
> 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 mailing list
> Senna****@lists*****
> http://lists.sourceforge.jp/mailman/listinfo/senna-dev
> バグ報告方法:http://qwik.jp/senna/bug_report.html
>