[#12164] patch for ext/gdbm — Koji Arai <JCA02266@...>

新井です。

24 messages 2001/02/04
[#12168] Re: patch for ext/gdbm — matz@... (Yukihiro Matsumoto) 2001/02/05

まつもと ゆきひろです

[#12176] Re: patch for ext/gdbm — Koji Arai <JCA02266@...> 2001/02/05

新井です。

[#12179] Re: patch for ext/gdbm — matz@... (Yukihiro Matsumoto) 2001/02/06

まつもと ゆきひろです

[#12219] Re: patch for ext/gdbm — Koji Arai <JCA02266@...> 2001/02/12

新井です。

[#12220] Re: patch for ext/gdbm — Koji Arai <JCA02266@...> 2001/02/12

新井です。

[#12256] set_trace_func — keiju@... (Keiju ISHITSUKA)

けいじゅ@日本ラショナルソフトウェアです.

15 messages 2001/02/17

[#12293] crash on proc without a block — Kenichi Komiya <kom@...1.accsnet.ne.jp>

15 messages 2001/02/25

[#12323] Re: [ruby-list:28364] class definition extension — "K.Kosako" <kosako@...>

ruby-listから移動しました。

13 messages 2001/02/28
[#12324] Re: [ruby-list:28364] class definition extension — matz@... (Yukihiro Matsumoto) 2001/02/28

まつもと ゆきひろです

[ruby-dev:12220] Re: patch for ext/gdbm

From: Koji Arai <JCA02266@...>
Date: 2001-02-12 21:57:27 UTC
List: ruby-dev #12220
新井です。

DBM にも同じ修正を加えました

> o GDBM.new と GDBM.open を最近のスタイルに
>   (open はブロック付きで呼び出せる. new は initialize() を呼ぶ)
>   したがって, open は nil を返すことがありますが,new は常にオブジェク
>   トを返します。

> o GDBM#fetch はキーがない場合に例外を出すように修正
> o GDBMError 例外クラスを追加。

# DBMError はいらなかったかな?

さらに、今気が付いたのですが GDBM はメモリリークしてますね。
# gdbm_fetch() 後はfree()しないといけない

例えば以下は,メモリを確保し続けます

  require 'gdbm'

  db = GDBM.new("/tmp/hoge2")
  db["foo"] = "x" * 1024 * 1024
  loop {
    db.index "foo"
    sleep 0.5
  }

この対処のパッチも付けます。(gdbm の dbmfetch.c が
こんなソースだったのでパクリました)

--
新井康司 (Koji Arai)


Index: dbm.c
===================================================================
RCS file: /src/ruby/ext/dbm/dbm.c,v
retrieving revision 1.13
diff -u -p -r1.13 dbm.c
--- dbm.c	2000/11/09 02:29:45	1.13
+++ dbm.c	2001/02/12 21:38:02
@@ -22,7 +22,7 @@
 #include <fcntl.h>
 #include <errno.h>
 
-VALUE cDBM;
+VALUE cDBM, rb_eDBMError;
 
 struct dbmdata {
     int  di_size;
@@ -37,6 +37,7 @@ closed_dbm()
 
 #define GetDBM(obj, dbmp) {\
     Data_Get_Struct(obj, struct dbmdata, dbmp);\
+    if (dbmp == 0) closed_dbm();\
     if (dbmp->di_dbm == 0) closed_dbm();\
 }
 
@@ -44,21 +45,35 @@ static void
 free_dbm(dbmp)
     struct dbmdata *dbmp;
 {
-    if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
-    free(dbmp);
+    if (dbmp) {
+	if (dbmp->di_dbm) dbm_close(dbmp->di_dbm);
+	free(dbmp);
+    }
 }
 
+static VALUE fdbm_close _((VALUE));
+
 static VALUE
-fdbm_s_open(argc, argv, klass)
+fdbm_s_new(argc, argv, klass)
     int argc;
     VALUE *argv;
     VALUE klass;
 {
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+    rb_obj_call_init(obj, argc, argv);
+    return obj;
+}
+
+static VALUE
+fdbm_initialize(argc, argv, obj)
+    int argc;
+    VALUE *argv;
+    VALUE obj;
+{
     VALUE file, vmode;
     DBM *dbm;
     struct dbmdata *dbmp;
     int mode;
-    VALUE obj;
 
     if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) {
 	mode = 0666;		/* default value */
@@ -87,7 +102,8 @@ fdbm_s_open(argc, argv, klass)
 	rb_sys_fail(RSTRING(file)->ptr);
     }
 
-    obj = Data_Make_Struct(klass,struct dbmdata,0,free_dbm,dbmp);
+    dbmp = ALLOC(struct dbmdata);
+    DATA_PTR(obj) = dbmp;
     dbmp->di_dbm = dbm;
     dbmp->di_size = -1;
 
@@ -95,6 +111,25 @@ fdbm_s_open(argc, argv, klass)
 }
 
 static VALUE
+fdbm_s_open(argc, argv, klass)
+    int argc;
+    VALUE *argv;
+    VALUE klass;
+{
+    VALUE obj = Data_Wrap_Struct(klass, 0, free_dbm, 0);
+
+    if (NIL_P(fdbm_initialize(argc, argv, obj))) {
+	return Qnil;
+    }
+
+    if (rb_block_given_p()) {
+        return rb_ensure(rb_yield, obj, fdbm_close, obj);
+    }
+
+    return obj;
+}
+
+static VALUE
 fdbm_close(obj)
     VALUE obj;
 {
@@ -143,10 +178,14 @@ fdbm_fetch_m(argc, argv, obj)
     VALUE *argv;
     VALUE obj;
 {
-    VALUE keystr, ifnone;
+    VALUE keystr, valstr, ifnone;
 
     rb_scan_args(argc, argv, "11", &keystr, &ifnone);
-    return fdbm_fetch(obj, keystr, ifnone);
+    valstr = fdbm_fetch(obj, keystr, ifnone);
+    if (argc == 1 && !rb_block_given_p() && NIL_P(valstr))
+	rb_raise(rb_eIndexError, "key not found");
+
+    return valstr;
 }
 
 static VALUE
@@ -166,8 +205,9 @@ fdbm_index(obj, valstr)
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
 	val = dbm_fetch(dbm, key);
 	if (val.dsize == RSTRING(valstr)->len &&
-	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
+	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) {
 	    return rb_tainted_str_new(key.dptr, key.dsize);
+	}
     }
     return Qnil;
 }
@@ -213,7 +253,7 @@ fdbm_delete(obj, keystr)
 
     if (dbm_delete(dbm, key)) {
 	dbmp->di_size = -1;
-	rb_raise(rb_eRuntimeError, "dbm_delete failed");
+	rb_raise(rb_eDBMError, "dbm_delete failed");
     }
     else if (dbmp->di_size >= 0) {
 	dbmp->di_size--;
@@ -262,7 +302,7 @@ fdbm_delete_if(obj)
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
 	if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) {
 	    if (dbm_delete(dbm, key)) {
-		rb_raise(rb_eRuntimeError, "dbm_delete failed");
+		rb_raise(rb_eDBMError, "dbm_delete failed");
 	    }
 	}
     }
@@ -283,7 +323,7 @@ fdbm_clear(obj)
     dbmp->di_size = -1;
     for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) {
 	if (dbm_delete(dbm, key)) {
-	    rb_raise(rb_eRuntimeError, "dbm_delete failed");
+	    rb_raise(rb_eDBMError, "dbm_delete failed");
 	}
     }
     return obj;
@@ -374,7 +414,7 @@ fdbm_store(obj, keystr, valstr)
 	dbm_clearerr(dbm);
 #endif
 	if (errno == EPERM) rb_sys_fail(0);
-	rb_raise(rb_eRuntimeError, "dbm_store failed");
+	rb_raise(rb_eDBMError, "dbm_store failed");
     }
 
     return valstr;
@@ -618,10 +658,13 @@ void
 Init_dbm()
 {
     cDBM = rb_define_class("DBM", rb_cObject);
+    rb_eDBMError = rb_define_class("DBMError", rb_eStandardError);
     rb_include_module(cDBM, rb_mEnumerable);
 
+    rb_define_singleton_method(cDBM, "new", fdbm_s_new, -1);
     rb_define_singleton_method(cDBM, "open", fdbm_s_open, -1);
-    rb_define_singleton_method(cDBM, "new", fdbm_s_open, -1);
+
+    rb_define_method(cDBM, "initialize", fdbm_initialize, -1);
     rb_define_method(cDBM, "close", fdbm_close, 0);
     rb_define_method(cDBM, "[]", fdbm_aref, 1);
     rb_define_method(cDBM, "fetch", fdbm_fetch_m, -1);


--- gdbm.c.old	Tue Feb 13 06:39:57 2001
+++ gdbm.c	Tue Feb 13 06:39:06 2001
@@ -147,6 +147,21 @@ fgdbm_close(obj)
     return Qnil;
 }
 
+datum
+gdbm_fetch_1(dbm, key)
+    GDBM_FILE dbm;
+    datum key;
+{
+    static char *ptr;
+    datum val;
+
+    val = gdbm_fetch(dbm, key);
+    if (ptr) free(ptr);
+    ptr = val.dptr;
+
+    return val;
+}
+
 static VALUE
 fgdbm_fetch(obj, keystr, ifnone)
     VALUE obj, keystr, ifnone;
@@ -161,7 +176,7 @@ fgdbm_fetch(obj, keystr, ifnone)
 
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
-    value = gdbm_fetch(dbm, key);
+    value = gdbm_fetch_1(dbm, key);
     if (value.dptr == 0) {
 	if (ifnone == Qnil && rb_block_given_p())
 	    return rb_yield(rb_tainted_str_new(key.dptr, key.dsize));
@@ -208,7 +223,7 @@ fgdbm_index(obj, valstr)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	if (val.dsize == RSTRING(valstr)->len &&
 	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
 	    return rb_tainted_str_new(key.dptr, key.dsize);
@@ -279,7 +294,7 @@ fgdbm_shift(obj)
 
     key = gdbm_firstkey(dbm); 
     if (!key.dptr) return Qnil;
-    val = gdbm_fetch(dbm, key);
+    val = gdbm_fetch_1(dbm, key);
     gdbm_delete(dbm, key);
 
     keystr = rb_tainted_str_new(key.dptr, key.dsize);
@@ -300,7 +315,7 @@ fgdbm_delete_if(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	keystr = rb_tainted_str_new(key.dptr, key.dsize);
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
 	if (RTEST(rb_yield(rb_assoc_new(keystr, valstr)))) {
@@ -346,7 +361,7 @@ fgdbm_invert(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	keystr = rb_tainted_str_new(key.dptr, key.dsize);
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
 	rb_hash_aset(hash, valstr, keystr);
@@ -477,7 +492,7 @@ fgdbm_each_value(obj)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	rb_yield(rb_tainted_str_new(val.dptr, val.dsize));
     }
     return obj;
@@ -512,7 +527,7 @@ fgdbm_each_pair(obj)
     dbm = dbmp->di_dbm;
 
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	keystr = rb_tainted_str_new(key.dptr, key.dsize);
 	valstr = rb_tainted_str_new(val.dptr, val.dsize);
 	rb_yield(rb_assoc_new(keystr, valstr));
@@ -555,7 +570,7 @@ fgdbm_values(obj)
 
     ary = rb_ary_new();
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	rb_ary_push(ary, rb_tainted_str_new(val.dptr, val.dsize));
     }
 
@@ -596,7 +611,7 @@ fgdbm_has_value(obj, valstr)
     GetDBM(obj, dbmp);
     dbm = dbmp->di_dbm;
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	if (val.dsize == RSTRING(valstr)->len &&
 	    memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0)
 	    return Qtrue;
@@ -618,7 +633,7 @@ fgdbm_to_a(obj)
 
     ary = rb_ary_new();
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	rb_ary_push(ary, rb_assoc_new(rb_tainted_str_new(key.dptr, key.dsize),
 				rb_tainted_str_new(val.dptr, val.dsize)));
     }
@@ -736,7 +751,7 @@ fgdbm_to_hash(obj)
 
     hash = rb_hash_new();
     for (key = gdbm_firstkey(dbm); key.dptr; key = gdbm_nextkey(dbm, key)) {
-	val = gdbm_fetch(dbm, key);
+	val = gdbm_fetch_1(dbm, key);
 	rb_hash_aset(hash, rb_tainted_str_new(key.dptr, key.dsize),
 		           rb_tainted_str_new(val.dptr, val.dsize));
     }

In This Thread