From 3107a78110309a203b0c2ef7cc4cd9d18d294a46 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 17 Jan 2011 03:05:42 +0000 Subject: fetch and delete may be passed destination buffer This allows apps to reduce GC thrashing by reusing a string buffer. --- ext/tdb/tdb.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) (limited to 'ext') diff --git a/ext/tdb/tdb.c b/ext/tdb/tdb.c index a502d3b..31f71c8 100644 --- a/ext/tdb/tdb.c +++ b/ext/tdb/tdb.c @@ -331,7 +331,9 @@ struct fetch_parse_args { struct tdb_context *tdb; union { TDB_DATA key; - TDB_DATA val; + long value_len; + char *value_ptr; + VALUE value; } as; VALUE value; }; @@ -341,11 +343,12 @@ static VALUE str_new_tdb_data(TDB_DATA *val) return rb_str_new((const char *)val->dptr, val->dsize); } -static void *gvl_str_new(void *data) +static void *gvl_str_resize(void *data) { struct fetch_parse_args *f = data; - f->value = str_new_tdb_data(&f->as.val); + rb_str_resize(f->value, f->as.value_len); + f->as.value_ptr = RSTRING_PTR(f->value); return NULL; } @@ -354,8 +357,10 @@ static int fetch_parse(TDB_DATA key, TDB_DATA val, void *data) { struct fetch_parse_args *f = data; - f->as.val = val; - (void)rb_thread_call_with_gvl(gvl_str_new, data); + f->as.value_len = val.dsize; + (void)rb_thread_call_with_gvl(gvl_str_resize, data); + memcpy(f->as.value_ptr, val.dptr, val.dsize); + f->as.value = f->value; return 0; } @@ -367,16 +372,24 @@ static VALUE nogvl_parse_record(void *ptr) if (tdb_parse_record(f->tdb, f->as.key, fetch_parse, ptr) == -1) return Qnil; - return f->value; + return f->value == f->as.value ? f->value : Qnil; } -static VALUE fetch(VALUE self, VALUE key) +static VALUE fetch(int argc, VALUE *argv, VALUE self) { struct fetch_parse_args f; + VALUE key; + + rb_scan_args(argc, argv, "11", &key, &f.value); + if (NIL_P(f.value)) { + f.value = rb_str_new(0, 0); + } else { + StringValue(f.value); + rb_str_set_len(f.value, 0); + } f.tdb = db(self, 1); TO_TDB_DATA(f.as.key, key); - f.value = Qnil; return my_tbr(nogvl_parse_record, &f); } @@ -549,12 +562,17 @@ static VALUE nuke(VALUE self, VALUE key) return my_tbr(nogvl_delete, &d); } -static VALUE delete(VALUE self, VALUE key) +static VALUE aref(VALUE self, VALUE key) +{ + return fetch(1, &key, self); +} + +static VALUE delete(int argc, VALUE *argv, VALUE self) { - VALUE rc = fetch(self, key); + VALUE rc = fetch(argc, argv, self); if (! NIL_P(rc)) - if (nuke(self, key) == Qfalse) + if (nuke(self, argv[0]) == Qfalse) return Qnil; return rc; } @@ -674,8 +692,8 @@ void Init_tdb_ext(void) rb_define_method(cTDB, "close", tdbclose, 0); rb_define_method(cTDB, "closed?", closed, 0); - rb_define_method(cTDB, "fetch", fetch, 1); - rb_define_method(cTDB, "[]", fetch, 1); + rb_define_method(cTDB, "fetch", fetch, -1); + rb_define_method(cTDB, "[]", aref, 1); rb_define_method(cTDB, "store", store, 2); rb_define_method(cTDB, "[]=", store, 2); rb_define_method(cTDB, "insert!", insert_bang, 2); @@ -689,7 +707,7 @@ void Init_tdb_ext(void) rb_define_method(cTDB, "member?", has_key, 1); rb_define_method(cTDB, "each", each, 0); rb_define_method(cTDB, "nuke!", nuke, 1); - rb_define_method(cTDB, "delete", delete, 1); + rb_define_method(cTDB, "delete", delete, -1); rb_define_method(cTDB, "lockall", lockall, 0); rb_define_method(cTDB, "trylockall", trylockall, 0); -- cgit v1.2.3-24-ge0c7