about summary refs log tree commit homepage
path: root/ext
diff options
context:
space:
mode:
authorEric Wong <e@yhbt.net>2011-01-17 03:05:42 +0000
committerEric Wong <normalperson@yhbt.net>2011-01-17 08:28:47 +0000
commit3107a78110309a203b0c2ef7cc4cd9d18d294a46 (patch)
tree470795dcd99d3f90af83d83549f1796e5a4fc019 /ext
parent069d047d3dcb0eefe59babbd295cfee922aa1476 (diff)
downloadruby-tdb-3107a78110309a203b0c2ef7cc4cd9d18d294a46.tar.gz
This allows apps to reduce GC thrashing by reusing
a string buffer.
Diffstat (limited to 'ext')
-rw-r--r--ext/tdb/tdb.c46
1 files changed, 32 insertions, 14 deletions
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);