[DRE-commits] r2142 - in packages: . libdb4.3-ruby libdb4.3-ruby/branches libdb4.3-ruby/branches/upstream libdb4.3-ruby/branches/upstream/current libdb4.3-ruby/branches/upstream/current/src
lucas at alioth.debian.org
lucas at alioth.debian.org
Sat Dec 8 12:00:49 UTC 2007
Author: lucas
Date: 2007-12-08 12:00:45 +0000 (Sat, 08 Dec 2007)
New Revision: 2142
Added:
packages/libdb4.3-ruby/
packages/libdb4.3-ruby/branches/
packages/libdb4.3-ruby/branches/upstream/
packages/libdb4.3-ruby/branches/upstream/current/
packages/libdb4.3-ruby/branches/upstream/current/src/
packages/libdb4.3-ruby/branches/upstream/current/src/common.c
packages/libdb4.3-ruby/branches/upstream/current/src/env.c
packages/libdb4.3-ruby/branches/upstream/current/src/lock.c
packages/libdb4.3-ruby/branches/upstream/current/src/log.c
packages/libdb4.3-ruby/branches/upstream/current/src/recnum.c
packages/libdb4.3-ruby/branches/upstream/current/src/sequence.c
Log:
[svn-inject] Installing original source of libdb4.3-ruby
Added: packages/libdb4.3-ruby/branches/upstream/current/src/common.c
===================================================================
--- packages/libdb4.3-ruby/branches/upstream/current/src/common.c (rev 0)
+++ packages/libdb4.3-ruby/branches/upstream/current/src/common.c 2007-12-08 12:00:45 UTC (rev 2142)
@@ -0,0 +1,4230 @@
+#include "bdb.h"
+
+static ID id_bt_compare, id_bt_prefix, id_dup_compare, id_h_hash;
+#if BDB_VERSION >= 40100
+static ID id_append_recno;
+#endif
+
+#if BDB_VERSION >= 30000
+static ID id_feedback;
+#endif
+
+static void bdb_mark _((bdb_DB *));
+
+#define GetIdDb(obj, dbst) do { \
+ (obj) = rb_thread_local_aref(rb_thread_current(), bdb_id_current_db); \
+ if (TYPE(obj) != T_DATA || \
+ RDATA(obj)->dmark != (RUBY_DATA_FUNC)bdb_mark) { \
+ rb_raise(bdb_eFatal, "BUG : current_db not set"); \
+ } \
+ Data_Get_Struct(obj, bdb_DB, dbst); \
+} while (0)
+
+void
+bdb_ary_push(struct ary_st *db_ary, VALUE obj)
+{
+ if (db_ary->mark) {
+ rb_warning("db_ary in mark phase");
+ return;
+ }
+ if (db_ary->len == db_ary->total) {
+ if (db_ary->total) {
+ REALLOC_N(db_ary->ptr, VALUE, db_ary->total + 5);
+ }
+ else {
+ db_ary->ptr = ALLOC_N(VALUE, 5);
+ }
+ db_ary->total += 5;
+ }
+ db_ary->ptr[db_ary->len] = obj;
+ db_ary->len++;
+}
+
+void
+bdb_ary_unshift(struct ary_st *db_ary, VALUE obj)
+{
+ if (db_ary->mark) {
+ rb_warning("db_ary in mark phase");
+ return;
+ }
+ if (db_ary->len == db_ary->total) {
+ if (db_ary->total) {
+ REALLOC_N(db_ary->ptr, VALUE, db_ary->total + 5);
+ }
+ else {
+ db_ary->ptr = ALLOC_N(VALUE, 5);
+ }
+ db_ary->total += 5;
+ }
+ if (db_ary->len) {
+ MEMMOVE(db_ary->ptr + 1, db_ary->ptr, VALUE, db_ary->len);
+ }
+ db_ary->len++;
+ db_ary->ptr[0] = obj;
+}
+
+VALUE
+bdb_ary_delete(struct ary_st *db_ary, VALUE val)
+{
+ int i, pos;
+
+ if (!db_ary->ptr || db_ary->mark) return Qfalse;
+ for (pos = 0; pos < db_ary->len; pos++) {
+ if (db_ary->ptr[pos] == val) {
+ for (i = pos + 1; i < db_ary->len; i++, pos++) {
+ db_ary->ptr[pos] = db_ary->ptr[i];
+ }
+ db_ary->len = pos;
+ return Qtrue;
+ }
+ }
+ return Qfalse;
+}
+
+void
+bdb_ary_mark(struct ary_st *db_ary)
+{
+ int i;
+
+ for (i = 0; i < db_ary->len; i++) {
+ rb_gc_mark(db_ary->ptr[i]);
+ }
+}
+
+VALUE
+bdb_test_dump(VALUE obj, DBT *key, VALUE a, int type_kv)
+{
+ bdb_DB *dbst;
+ int is_nil = 0;
+ VALUE tmp = a;
+
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (dbst->filter[type_kv]) {
+ if (FIXNUM_P(dbst->filter[type_kv])) {
+ tmp = rb_funcall(obj, NUM2INT(dbst->filter[type_kv]), 1, a);
+ }
+ else {
+ tmp = rb_funcall(dbst->filter[type_kv], bdb_id_call, 1, a);
+ }
+ }
+ if (dbst->marshal) {
+ if (rb_obj_is_kind_of(tmp, bdb_cDelegate)) {
+ tmp = bdb_deleg_to_orig(tmp);
+ }
+ tmp = rb_funcall(dbst->marshal, bdb_id_dump, 1, tmp);
+ if (TYPE(tmp) != T_STRING) {
+ rb_raise(rb_eTypeError, "dump() must return String");
+ }
+ }
+ else {
+ tmp = rb_obj_as_string(tmp);
+ if ((dbst->options & BDB_NIL) && a == Qnil) {
+ is_nil = 1;
+ }
+ }
+ key->data = StringValuePtr(tmp);
+ key->flags &= ~DB_DBT_MALLOC;
+ key->size = RSTRING(tmp)->len + is_nil;
+ return tmp;
+}
+
+VALUE
+bdb_test_ret(VALUE obj, VALUE tmp, VALUE a, int type_kv)
+{
+ bdb_DB *dbst;
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (dbst->marshal || a == Qnil) {
+ return a;
+ }
+ else {
+ if (dbst->filter[type_kv]) {
+ return rb_obj_as_string(a);
+ }
+ else {
+ return tmp;
+ }
+ }
+}
+
+VALUE
+bdb_test_recno(VALUE obj, DBT *key, db_recno_t *recno, VALUE a)
+{
+ bdb_DB *dbst;
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (RECNUM_TYPE(dbst)) {
+ *recno = NUM2INT(a) + dbst->array_base;
+ key->data = recno;
+ key->size = sizeof(db_recno_t);
+ return a;
+ }
+ else {
+ return bdb_test_dump(obj, key, a, FILTER_KEY);
+ }
+}
+
+VALUE
+bdb_test_load(VALUE obj, DBT *a, int type_kv)
+{
+ VALUE res;
+ int i, posi;
+ bdb_DB *dbst;
+
+ posi = type_kv & ~FILTER_FREE;
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (dbst->marshal) {
+ res = rb_str_new(a->data, a->size);
+ if (dbst->filter[2 + posi]) {
+ if (FIXNUM_P(dbst->filter[2 + posi])) {
+ res = rb_funcall(obj,
+ NUM2INT(dbst->filter[2 + posi]), 1, res);
+ }
+ else {
+ res = rb_funcall(dbst->filter[2 + posi], bdb_id_call, 1, res);
+ }
+ }
+ res = rb_funcall(dbst->marshal, bdb_id_load, 1, res);
+ }
+ else {
+#if BDB_VERSION >= 30000
+ if (dbst->type == DB_QUEUE) {
+ for (i = a->size - 1; i >= 0; i--) {
+ if (((char *)a->data)[i] != dbst->re_pad)
+ break;
+ }
+ a->size = i + 1;
+ }
+#endif
+ if ((dbst->options & BDB_NIL) &&
+ a->size == 1 && ((char *)a->data)[0] == '\000') {
+ res = Qnil;
+ }
+ else {
+ if (a->size == 0 && !(dbst->options & BDB_NIL)) {
+ res = Qnil;
+ }
+ else {
+ res = rb_tainted_str_new(a->data, a->size);
+ if (dbst->filter[2 + posi]) {
+ if (FIXNUM_P(dbst->filter[2 + posi])) {
+ res = rb_funcall(obj, NUM2INT(dbst->filter[2 + posi]),
+ 1, res);
+ }
+ else {
+ res = rb_funcall(dbst->filter[2 + posi],
+ bdb_id_call, 1, res);
+ }
+ }
+ }
+ }
+ }
+ if ((a->flags & DB_DBT_MALLOC) && !(type_kv & FILTER_FREE)) {
+ free(a->data);
+ a->flags &= ~DB_DBT_MALLOC;
+ }
+ return res;
+}
+
+static VALUE
+test_load_dyna1(VALUE obj, DBT *key, DBT *val)
+{
+ bdb_DB *dbst;
+ VALUE del, res, tmp;
+ struct deleg_class *delegst;
+
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ res = bdb_test_load(obj, val, FILTER_VALUE);
+ if (dbst->marshal && !SPECIAL_CONST_P(res)) {
+ del = Data_Make_Struct(bdb_cDelegate, struct deleg_class,
+ bdb_deleg_mark, free, delegst);
+ delegst->db = obj;
+ if (RECNUM_TYPE(dbst)) {
+ tmp = INT2NUM((*(db_recno_t *)key->data) - dbst->array_base);
+ }
+ else {
+ tmp = rb_str_new(key->data, key->size);
+ if (dbst->filter[2 + FILTER_VALUE]) {
+ if (FIXNUM_P(dbst->filter[2 + FILTER_VALUE])) {
+ tmp = rb_funcall(obj,
+ NUM2INT(dbst->filter[2 + FILTER_VALUE]),
+ 1, tmp);
+ }
+ else {
+ tmp = rb_funcall(dbst->filter[2 + FILTER_VALUE],
+ bdb_id_call, 1, tmp);
+ }
+ }
+ tmp = rb_funcall(dbst->marshal, bdb_id_load, 1, tmp);
+ }
+ delegst->key = tmp;
+ delegst->obj = res;
+ res = del;
+ }
+ return res;
+}
+
+static VALUE
+test_load_dyna(VALUE obj, DBT *key, DBT *val)
+{
+ VALUE res = test_load_dyna1(obj, key, val);
+ if (key->flags & DB_DBT_MALLOC) {
+ free(key->data);
+ key->flags &= ~DB_DBT_MALLOC;
+ }
+ return res;
+}
+
+static int
+#if BDB_VERSION >= 30200
+bdb_bt_compare(DB *dbbd, const DBT *a, const DBT *b)
+#else
+bdb_bt_compare(const DBT *a, const DBT *b)
+#endif
+{
+ VALUE obj, av, bv, res;
+ bdb_DB *dbst;
+
+ GetIdDb(obj, dbst);
+ av = bdb_test_load(obj, (DBT *)a, FILTER_VALUE|FILTER_FREE);
+ bv = bdb_test_load(obj, (DBT *)b, FILTER_VALUE|FILTER_FREE);
+ if (dbst->bt_compare == 0)
+ res = rb_funcall(obj, id_bt_compare, 2, av, bv);
+ else
+ res = rb_funcall(dbst->bt_compare, bdb_id_call, 2, av, bv);
+ return NUM2INT(res);
+}
+
+static size_t
+#if BDB_VERSION >= 30200
+bdb_bt_prefix(DB *dbbd, const DBT *a, const DBT *b)
+#else
+bdb_bt_prefix(const DBT *a, const DBT *b)
+#endif
+{
+ VALUE obj, av, bv, res;
+ bdb_DB *dbst;
+
+ GetIdDb(obj, dbst);
+ av = bdb_test_load(obj, (DBT *)a, FILTER_VALUE|FILTER_FREE);
+ bv = bdb_test_load(obj, (DBT *)b, FILTER_VALUE|FILTER_FREE);
+ if (dbst->bt_prefix == 0)
+ res = rb_funcall(obj, id_bt_prefix, 2, av, bv);
+ else
+ res = rb_funcall(dbst->bt_prefix, bdb_id_call, 2, av, bv);
+ return NUM2INT(res);
+}
+
+static int
+#if BDB_VERSION >= 30200
+bdb_dup_compare(DB *dbbd, const DBT *a, const DBT *b)
+#else
+bdb_dup_compare(const DBT *a, const DBT *b)
+#endif
+{
+ VALUE obj, av, bv, res;
+ bdb_DB *dbst;
+
+ GetIdDb(obj, dbst);
+ av = bdb_test_load(obj, (DBT *)a, FILTER_VALUE|FILTER_FREE);
+ bv = bdb_test_load(obj, (DBT *)b, FILTER_VALUE|FILTER_FREE);
+ if (dbst->dup_compare == 0)
+ res = rb_funcall(obj, id_dup_compare, 2, av, bv);
+ else
+ res = rb_funcall(dbst->dup_compare, bdb_id_call, 2, av, bv);
+ return NUM2INT(res);
+}
+
+static u_int32_t
+#if BDB_VERSION >= 30200
+bdb_h_hash(DB *dbbd, const void *bytes, u_int32_t length)
+#else
+bdb_h_hash(const void *bytes, u_int32_t length)
+#endif
+{
+ VALUE obj, st, res;
+ bdb_DB *dbst;
+
+ GetIdDb(obj, dbst);
+ st = rb_tainted_str_new((char *)bytes, length);
+ if (dbst->h_hash == 0)
+ res = rb_funcall(obj, id_h_hash, 1, st);
+ else
+ res = rb_funcall(dbst->h_hash, bdb_id_call, 1, st);
+ return NUM2UINT(res);
+}
+
+#if BDB_VERSION >= 40100
+
+static int
+bdb_append_recno(DB *dbp, DBT *data, db_recno_t recno)
+{
+ VALUE res, obj, av, rec;
+ bdb_DB *dbst;
+
+ GetIdDb(obj, dbst);
+ av = bdb_test_load(obj, data, FILTER_VALUE|FILTER_FREE);
+ rec = INT2NUM(recno - dbst->array_base);
+ if (dbst->append_recno == 0)
+ res = rb_funcall(obj, id_append_recno, 2, rec, av);
+ else
+ res = rb_funcall(dbst->append_recno, bdb_id_call, 2, rec, av);
+ if (!NIL_P(res)) {
+ bdb_test_dump(obj, data, res, FILTER_VALUE);
+ }
+ return 0;
+}
+
+#endif
+
+#if BDB_VERSION >= 30000
+
+static void
+bdb_feedback(DB *dbp, int opcode, int pct)
+{
+ VALUE obj;
+ bdb_DB *dbst;
+
+ GetIdDb(obj, dbst);
+ if (NIL_P(dbst->feedback)) {
+ return;
+ }
+ if (dbst->feedback == 0) {
+ rb_funcall(obj, id_feedback, 2, INT2NUM(opcode), INT2NUM(pct));
+ }
+ else {
+ rb_funcall(dbst->feedback, bdb_id_call, 2, INT2NUM(opcode), INT2NUM(pct));
+ }
+}
+
+#endif
+
+static VALUE
+bdb_i_options(VALUE obj, VALUE dbstobj)
+{
+ VALUE key, value;
+ char *options, *str;
+ DB *dbp;
+ bdb_DB *dbst;
+
+ Data_Get_Struct(dbstobj, bdb_DB, dbst);
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ dbp = dbst->dbp;
+ key = rb_obj_as_string(key);
+ options = StringValuePtr(key);
+ if (strcmp(options, "set_bt_minkey") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->bt_minkey = NUM2INT(value);
+#else
+ bdb_test_error(dbp->set_bt_minkey(dbp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_bt_compare") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->options |= BDB_BT_COMPARE;
+ dbst->bt_compare = value;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->bt_compare = bdb_bt_compare;
+#else
+ bdb_test_error(dbp->set_bt_compare(dbp, bdb_bt_compare));
+#endif
+ }
+ else if (strcmp(options, "set_bt_prefix") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->options |= BDB_BT_PREFIX;
+ dbst->bt_prefix = value;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->bt_prefix = bdb_bt_prefix;
+#else
+ bdb_test_error(dbp->set_bt_prefix(dbp, bdb_bt_prefix));
+#endif
+ }
+ else if (strcmp(options, "set_dup_compare") == 0) {
+#ifdef DB_DUPSORT
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->options |= BDB_DUP_COMPARE;
+ dbst->dup_compare = value;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->dup_compare = bdb_dup_compare;
+#else
+ bdb_test_error(dbp->set_dup_compare(dbp, bdb_dup_compare));
+#endif
+#else
+ rb_warning("dup_compare need db >= 2.5.9");
+#endif
+ }
+ else if (strcmp(options, "set_h_hash") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->options |= BDB_H_HASH;
+ dbst->h_hash = value;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->h_hash = bdb_h_hash;
+#else
+ bdb_test_error(dbp->set_h_hash(dbp, bdb_h_hash));
+#endif
+ }
+#if BDB_VERSION >= 40100
+ else if (strcmp(options, "set_append_recno") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->options |= BDB_APPEND_RECNO;
+ dbst->append_recno = value;
+ bdb_test_error(dbp->set_append_recno(dbp, bdb_append_recno));
+ }
+#endif
+ else if (strcmp(options, "set_cachesize") == 0) {
+ switch (TYPE(value)) {
+ case T_FIXNUM:
+ case T_FLOAT:
+ case T_BIGNUM:
+#if BDB_VERSION < 30000
+ dbst->dbinfo->db_cachesize = NUM2INT(value);
+#else
+ bdb_test_error(dbp->set_cachesize(dbp, 0, NUM2UINT(value), 0));
+#endif
+ break;
+ default:
+ Check_Type(value, T_ARRAY);
+ if (RARRAY(value)->len < 3) {
+ rb_raise(bdb_eFatal, "expected 3 values for cachesize");
+ }
+#if BDB_VERSION < 30000
+ dbst->dbinfo->db_cachesize = NUM2INT(RARRAY(value)->ptr[1]);
+#else
+ bdb_test_error(dbp->set_cachesize(dbp,
+ NUM2INT(RARRAY(value)->ptr[0]),
+ NUM2INT(RARRAY(value)->ptr[1]),
+ NUM2INT(RARRAY(value)->ptr[2])));
+#endif
+ break;
+ }
+ }
+ else if (strcmp(options, "set_flags") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->flags = NUM2UINT(value);
+#else
+ bdb_test_error(dbp->set_flags(dbp, NUM2UINT(value)));
+#endif
+ dbst->flags |= NUM2UINT(value);
+ }
+ else if (strcmp(options, "set_h_ffactor") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->h_ffactor = NUM2INT(value);
+#else
+ bdb_test_error(dbp->set_h_ffactor(dbp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_h_nelem") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->h_nelem = NUM2INT(value);
+#else
+ bdb_test_error(dbp->set_h_nelem(dbp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_lorder") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->db_lorder = NUM2INT(value);
+#else
+ bdb_test_error(dbp->set_lorder(dbp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_pagesize") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->db_pagesize = NUM2INT(value);
+#else
+ bdb_test_error(dbp->set_pagesize(dbp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_re_delim") == 0) {
+ int ch;
+ if (TYPE(value) == T_STRING) {
+ str = StringValuePtr(value);
+ ch = str[0];
+ }
+ else {
+ ch = NUM2INT(value);
+ }
+#if BDB_VERSION < 30000
+ dbst->dbinfo->re_delim = ch;
+ dbst->dbinfo->flags |= DB_DELIMITER;
+#else
+ bdb_test_error(dbp->set_re_delim(dbp, ch));
+#endif
+ }
+ else if (strcmp(options, "set_re_len") == 0) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->re_len = NUM2INT(value);
+ dbst->dbinfo->flags |= DB_FIXEDLEN;
+#else
+ bdb_test_error(dbp->set_re_len(dbp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_re_pad") == 0) {
+ int ch;
+ if (TYPE(value) == T_STRING) {
+ str = StringValuePtr(value);
+ ch = str[0];
+ }
+ else {
+ ch = NUM2INT(value);
+ }
+#if BDB_VERSION < 30000
+ dbst->dbinfo->re_pad = ch;
+ dbst->dbinfo->flags |= DB_PAD;
+#else
+ bdb_test_error(dbp->set_re_pad(dbp, ch));
+#endif
+ }
+ else if (strcmp(options, "set_re_source") == 0) {
+ if (TYPE(value) != T_STRING)
+ rb_raise(bdb_eFatal, "re_source must be a filename");
+#if BDB_VERSION < 30000
+ dbst->dbinfo->re_source = StringValuePtr(value);
+#else
+ bdb_test_error(dbp->set_re_source(dbp, StringValuePtr(value)));
+#endif
+ dbst->options |= BDB_RE_SOURCE;
+ }
+#if BDB_VERSION >= 30200
+ else if (strcmp(options, "set_q_extentsize") == 0) {
+ bdb_test_error(dbp->set_q_extentsize(dbp, NUM2INT(value)));
+ }
+#endif
+ else if (strcmp(options, "marshal") == 0) {
+ switch (value) {
+ case Qtrue:
+ dbst->marshal = bdb_mMarshal;
+ dbst->options |= BDB_MARSHAL;
+ break;
+ case Qfalse:
+ dbst->marshal = Qfalse;
+ dbst->options &= ~BDB_MARSHAL;
+ break;
+ default:
+ if (!rb_respond_to(value, bdb_id_load) ||
+ !rb_respond_to(value, bdb_id_dump)) {
+ rb_raise(bdb_eFatal, "marshal value must be true or false");
+ }
+ dbst->marshal = value;
+ dbst->options |= BDB_MARSHAL;
+ break;
+ }
+ }
+ else if (strcmp(options, "set_array_base") == 0 ||
+ strcmp(options, "array_base") == 0) {
+ int ary_base = NUM2INT(value);
+ switch (ary_base) {
+ case 0: dbst->array_base = 1; break;
+ case 1: dbst->array_base = 0; break;
+ default: rb_raise(bdb_eFatal, "array base must be 0 or 1");
+ }
+ }
+ else if (strcmp(options, "thread") == 0) {
+ if (RTEST(value)) {
+ dbst->options &= ~BDB_NO_THREAD;
+ }
+ else {
+ dbst->options |= BDB_NO_THREAD;
+ }
+ }
+ else if (strcmp(options, "set_store_key") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->filter[FILTER_KEY] = value;
+ }
+ else if (strcmp(options, "set_fetch_key") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->filter[2 + FILTER_KEY] = value;
+ }
+ else if (strcmp(options, "set_store_value") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->filter[FILTER_VALUE] = value;
+ }
+ else if (strcmp(options, "set_fetch_value") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->filter[2 + FILTER_VALUE] = value;
+ }
+#if BDB_VERSION >= 40100
+ else if (strcmp(options, "set_encrypt") == 0) {
+ char *passwd;
+ int flags = DB_ENCRYPT_AES;
+ if (TYPE(value) == T_ARRAY) {
+ if (RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "Expected an Array with 2 values");
+ }
+ passwd = StringValuePtr(RARRAY(value)->ptr[0]);
+ flags = NUM2INT(RARRAY(value)->ptr[1]);
+ }
+ else {
+ passwd = StringValuePtr(value);
+ }
+ bdb_test_error(dbp->set_encrypt(dbp, passwd, flags));
+ }
+#endif
+#if BDB_VERSION >= 30000
+ else if (strcmp(options, "set_feedback") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->options |= BDB_FEEDBACK;
+ dbst->feedback = value;
+ dbp->set_feedback(dbp, bdb_feedback);
+ }
+#endif
+ else if (strcmp(options, "store_nil_as_null") == 0) {
+ if (RTEST(value)) {
+ dbst->options |= BDB_NIL;
+ }
+ else {
+ dbst->options &= ~BDB_NIL;
+ }
+ }
+ return Qnil;
+}
+
+struct bdb_eiv {
+ VALUE bdb;
+ bdb_DB *dbst;
+};
+
+static void
+bdb_i_close(bdb_DB *dbst, int flags)
+{
+ bdb_ENV *envst;
+
+ if (dbst->dbp) {
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+ int opened = 0;
+
+ Data_Get_Struct(dbst->txn, bdb_TXN, txnst);
+ opened = bdb_ary_delete(&txnst->db_ary, dbst->ori_val);
+ if (!opened) {
+ opened = bdb_ary_delete(&txnst->db_assoc, dbst->ori_val);
+ }
+ if (opened) {
+ if (txnst->options & BDB_TXN_COMMIT) {
+ rb_funcall2(dbst->txn, rb_intern("commit"), 0, 0);
+ }
+ else {
+ rb_funcall2(dbst->txn, rb_intern("abort"), 0, 0);
+ }
+ }
+ }
+ else {
+ if (dbst->env) {
+ Data_Get_Struct(dbst->env, bdb_ENV, envst);
+ bdb_ary_delete(&envst->db_ary, dbst->ori_val);
+ }
+ if (!(dbst->options & BDB_NOT_OPEN)) {
+ bdb_test_error(dbst->dbp->close(dbst->dbp, flags));
+ }
+ }
+ }
+ dbst->dbp = NULL;
+}
+
+VALUE
+bdb_local_aref()
+{
+ bdb_DB *dbst;
+ VALUE obj;
+
+ GetIdDb(obj, dbst);
+ return obj;
+}
+
+static VALUE
+i_close(bdb_DB *dbst)
+{
+ bdb_i_close(dbst, 0);
+ return Qnil;
+}
+
+static VALUE
+bdb_final_aref(bdb_DB *dbst)
+{
+ VALUE obj;
+
+ obj = rb_thread_local_aref(rb_thread_current(), bdb_id_current_db);
+ if (!NIL_P(obj) && RDATA(obj)->dmark == (RUBY_DATA_FUNC)bdb_mark &&
+ DATA_PTR(obj) == dbst) {
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_db, Qnil);
+ }
+ return Qnil;
+}
+
+static void
+bdb_free(bdb_DB *dbst)
+{
+ if (dbst->dbp && !(dbst->options & BDB_NOT_OPEN)) {
+ rb_protect((VALUE (*)(ANYARGS))i_close, (VALUE)dbst, 0);
+ rb_protect((VALUE (*)(ANYARGS))bdb_final_aref, (VALUE)dbst, 0);
+ }
+ free(dbst);
+}
+
+static void
+bdb_mark(bdb_DB *dbst)
+{
+ int i;
+ rb_gc_mark(dbst->marshal);
+ rb_gc_mark(dbst->env);
+ rb_gc_mark(dbst->txn);
+ rb_gc_mark(dbst->orig);
+ rb_gc_mark(dbst->secondary);
+ rb_gc_mark(dbst->bt_compare);
+ rb_gc_mark(dbst->bt_prefix);
+ rb_gc_mark(dbst->dup_compare);
+ for (i = 0; i < 4; i++) {
+ rb_gc_mark(dbst->filter[i]);
+ }
+ rb_gc_mark(dbst->h_hash);
+ rb_gc_mark(dbst->filename);
+ rb_gc_mark(dbst->database);
+#if BDB_VERSION >= 40100
+ rb_gc_mark(dbst->append_recno);
+#endif
+#if BDB_VERSION >= 30000
+ rb_gc_mark(dbst->feedback);
+#endif
+}
+
+static VALUE
+bdb_env(VALUE obj)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (RTEST(dbst->env)) {
+ return dbst->env;
+ }
+ return Qnil;
+}
+
+VALUE
+bdb_env_p(VALUE obj)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ return (RTEST(dbst->env)?Qtrue:Qfalse);
+}
+
+static VALUE
+bdb_txn(VALUE obj)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (RTEST(dbst->txn)) {
+ return dbst->txn;
+ }
+ return Qnil;
+}
+
+VALUE
+bdb_txn_p(VALUE obj)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ return (RTEST(dbst->txn)?Qtrue:Qfalse);
+}
+
+static VALUE
+bdb_close(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE opt;
+ bdb_DB *dbst;
+ int flags = 0;
+
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) {
+ rb_raise(rb_eSecurityError, "Insecure: can't close the database");
+ }
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (dbst->dbp != NULL) {
+ if (rb_scan_args(argc, argv, "01", &opt)) {
+ flags = NUM2INT(opt);
+ }
+ bdb_i_close(dbst, flags);
+ }
+ dbst->options |= BDB_NOT_OPEN;
+ rb_protect((VALUE (*)(ANYARGS))bdb_final_aref, (VALUE)dbst, 0);
+ RDATA(obj)->dfree = free;
+ return Qnil;
+}
+
+#if BDB_VERSION < 30100
+static long
+bdb_hard_count(dbp)
+ DB *dbp;
+{
+ DBC *dbcp;
+ DBT key, data;
+ db_recno_t recno;
+ long count = 0;
+ int ret;
+
+ MEMZERO(&key, DBT, 1);
+ key.data = &recno;
+ key.size = sizeof(db_recno_t);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+#if BDB_VERSION < 20600
+ key.flags |= DB_DBT_MALLOC;
+ bdb_test_error(dbp->cursor(dbp, 0, &dbcp));
+#else
+ bdb_test_error(dbp->cursor(dbp, 0, &dbcp, 0));
+#endif
+ do {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_NEXT),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return count;
+ }
+ if (ret == DB_KEYEMPTY) {
+ dbcp->c_close(dbcp);
+ return -1;
+ }
+ free(data.data);
+ count++;
+ } while (1);
+ return count;
+}
+#endif
+
+static long
+bdb_is_recnum(dbp)
+ DB *dbp;
+{
+ DB_BTREE_STAT *bdb_stat;
+ long count;
+#if BDB_VERSION < 30100
+ long hard;
+#endif
+
+#if BDB_VERSION >= 30100
+#if BDB_VERSION >= 30300
+#if BDB_VERSION >= 40300
+ bdb_test_error(dbp->stat(dbp, NULL, &bdb_stat, 0));
+#else
+ bdb_test_error(dbp->stat(dbp, &bdb_stat, 0));
+#endif
+#else
+ bdb_test_error(dbp->stat(dbp, &bdb_stat, 0, 0));
+#endif
+ count = (bdb_stat->bt_nkeys == bdb_stat->bt_ndata)?bdb_stat->bt_nkeys:-1;
+ free(bdb_stat);
+#else
+ bdb_test_error(dbp->stat(dbp, &bdb_stat, 0, DB_RECORDCOUNT));
+ count = bdb_stat->bt_nrecs;
+ free(bdb_stat);
+ hard = bdb_hard_count(dbp);
+ count = (count == hard)?count:-1;
+#endif
+ return count;
+}
+
+static VALUE
+bdb_recno_length(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ DB_BTREE_STAT *bdb_stat;
+ VALUE hash;
+#if BDB_VERSION >= 40300
+ DB_TXN *txnid = NULL;
+#endif
+
+ GetDB(obj, dbst);
+#if BDB_VERSION >= 40000
+#if BDB_VERSION >= 40300
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, txnid, &bdb_stat, DB_FAST_STAT));
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, DB_FAST_STAT));
+#endif
+#else
+#if BDB_VERSION >= 30300
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, DB_RECORDCOUNT));
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, 0, DB_RECORDCOUNT));
+#endif
+#endif
+#if BDB_VERSION >= 30100
+ hash = INT2NUM(bdb_stat->bt_nkeys);
+#else
+ hash = INT2NUM(bdb_stat->bt_nrecs);
+#endif
+ free(bdb_stat);
+ return hash;
+}
+
+static VALUE
+bdb_s_new(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE res;
+ bdb_TXN *txnst = NULL;
+ bdb_ENV *envst = NULL;
+ bdb_DB *dbst;
+ DB_ENV *envp = 0;
+
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ res = rb_obj_alloc(obj);
+#else
+ res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
+#endif
+ Data_Get_Struct(res, bdb_DB, dbst);
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ VALUE v, f = argv[argc - 1];
+
+ if ((v = rb_hash_aref(f, rb_str_new2("txn"))) != RHASH(f)->ifnone) {
+ if (!rb_obj_is_kind_of(v, bdb_cTxn)) {
+ rb_raise(bdb_eFatal, "argument of txn must be a transaction");
+ }
+ Data_Get_Struct(v, bdb_TXN, txnst);
+ dbst->txn = v;
+ dbst->env = txnst->env;
+ Data_Get_Struct(txnst->env, bdb_ENV, envst);
+ envp = envst->envp;
+ dbst->options |= envst->options & BDB_NO_THREAD;
+ dbst->marshal = txnst->marshal;
+ }
+ else if ((v = rb_hash_aref(f, rb_str_new2("env"))) != RHASH(f)->ifnone) {
+ if (!rb_obj_is_kind_of(v, bdb_cEnv)) {
+ rb_raise(bdb_eFatal, "argument of env must be an environnement");
+ }
+ Data_Get_Struct(v, bdb_ENV, envst);
+ dbst->env = v;
+ envp = envst->envp;
+ dbst->options |= envst->options & BDB_NO_THREAD;
+ dbst->marshal = envst->marshal;
+ }
+#ifdef DB_ENCRYPT
+ if (envst && (envst->options & BDB_ENV_ENCRYPT)) {
+ VALUE tmp = rb_str_new2("set_flags");
+ if ((v = rb_hash_aref(f, rb_intern("set_flags"))) != RHASH(f)->ifnone) {
+ rb_hash_aset(f, rb_intern("set_flags"),
+ INT2NUM(NUM2INT(v) | DB_ENCRYPT));
+ }
+ else if ((v = rb_hash_aref(f, tmp)) != RHASH(f)->ifnone) {
+ rb_hash_aset(f, tmp, INT2NUM(NUM2INT(v) | DB_ENCRYPT));
+ }
+ else {
+ rb_hash_aset(f, tmp, INT2NUM(DB_ENCRYPT));
+ }
+ }
+#endif
+ }
+#if BDB_VERSION >= 30000
+ bdb_test_error(db_create(&(dbst->dbp), envp, 0));
+ dbst->dbp->set_errpfx(dbst->dbp, "BDB::");
+ dbst->dbp->set_errcall(dbst->dbp, bdb_env_errcall);
+#endif
+ if (rb_respond_to(obj, bdb_id_load) == Qtrue &&
+ rb_respond_to(obj, bdb_id_dump) == Qtrue) {
+ dbst->marshal = obj;
+ dbst->options |= BDB_MARSHAL;
+ }
+ if (rb_method_boundp(obj, rb_intern("bdb_store_key"), 0) == Qtrue) {
+ dbst->filter[FILTER_KEY] = INT2FIX(rb_intern("bdb_store_key"));
+ }
+ if (rb_method_boundp(obj, rb_intern("bdb_fetch_key"), 0) == Qtrue) {
+ dbst->filter[2 + FILTER_KEY] = INT2FIX(rb_intern("bdb_fetch_key"));
+ }
+ if (rb_method_boundp(obj, rb_intern("bdb_store_value"), 0) == Qtrue) {
+ dbst->filter[FILTER_VALUE] = INT2FIX(rb_intern("bdb_store_value"));
+ }
+ if (rb_method_boundp(obj, rb_intern("bdb_fetch_value"), 0) == Qtrue) {
+ dbst->filter[2 + FILTER_VALUE] = INT2FIX(rb_intern("bdb_fetch_value"));
+ }
+ rb_obj_call_init(res, argc, argv);
+ if (txnst) {
+ bdb_ary_push(&txnst->db_ary, res);
+ }
+ else if (envst) {
+ bdb_ary_push(&envst->db_ary, res);
+ }
+ return res;
+}
+
+VALUE
+bdb_init(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ DB *dbp;
+ int flags, mode, ret, nb;
+ char *name, *subname;
+ VALUE a, b, d, e;
+ VALUE hash_arg = Qnil;
+#if BDB_VERSION < 30000
+ DB_INFO dbinfo;
+
+ MEMZERO(&dbinfo, DB_INFO, 1);
+#endif
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ dbp = dbst->dbp;
+#if BDB_VERSION < 30000
+ dbst->dbinfo = &dbinfo;
+#endif
+#if BDB_VERSION >= 40100
+ if (rb_const_defined(CLASS_OF(obj), rb_intern("BDB_ENCRYPT"))) {
+ char *passwd;
+ int flags = DB_ENCRYPT_AES;
+ VALUE value = rb_const_get(CLASS_OF(obj), rb_intern("BDB_ENCRYPT"));
+ if (TYPE(value) == T_ARRAY) {
+ if (RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "Expected an Array with 2 values");
+ }
+ passwd = StringValuePtr(RARRAY(value)->ptr[0]);
+ flags = NUM2INT(RARRAY(value)->ptr[1]);
+ }
+ else {
+ passwd = StringValuePtr(value);
+ }
+ bdb_test_error(dbp->set_encrypt(dbp, passwd, flags));
+ }
+#endif
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ hash_arg = argv[argc - 1];
+ rb_iterate(rb_each, argv[argc - 1], bdb_i_options, obj);
+ argc--;
+ }
+ mode = flags = 0;
+ if (argc) {
+ flags = DB_RDONLY;
+ }
+ a = b = d = e = Qnil;
+ switch(nb = rb_scan_args(argc, argv, "04", &a, &b, &d, &e)) {
+ case 4:
+ mode = NUM2INT(e);
+ case 3:
+ if (TYPE(d) == T_STRING) {
+ if (strcmp(StringValuePtr(d), "r") == 0)
+ flags = DB_RDONLY;
+ else if (strcmp(StringValuePtr(d), "r+") == 0)
+ flags = 0;
+ else if (strcmp(StringValuePtr(d), "w") == 0 ||
+ strcmp(StringValuePtr(d), "w+") == 0)
+ flags = DB_CREATE | DB_TRUNCATE;
+ else if (strcmp(StringValuePtr(d), "a") == 0 ||
+ strcmp(StringValuePtr(d), "a+") == 0)
+ flags = DB_CREATE;
+ else {
+ rb_raise(bdb_eFatal, "flags must be r, r+, w, w+, a or a+");
+ }
+ }
+ else if (d == Qnil)
+ flags = DB_RDONLY;
+ else
+ flags = NUM2INT(d);
+ }
+ name = subname = NULL;
+ if (!NIL_P(a)) {
+ SafeStringValue(a);
+ name = StringValuePtr(a);
+ }
+ if (!NIL_P(b)) {
+ SafeStringValue(b);
+ subname = StringValuePtr(b);
+ }
+ if (dbst->bt_compare == 0 && rb_respond_to(obj, id_bt_compare) == Qtrue) {
+ dbst->options |= BDB_BT_COMPARE;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->bt_compare = bdb_bt_compare;
+#else
+ bdb_test_error(dbp->set_bt_compare(dbp, bdb_bt_compare));
+#endif
+ }
+ if (dbst->bt_prefix == 0 && rb_respond_to(obj, id_bt_prefix) == Qtrue) {
+ dbst->options |= BDB_BT_PREFIX;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->bt_prefix = bdb_bt_prefix;
+#else
+ bdb_test_error(dbp->set_bt_prefix(dbp, bdb_bt_prefix));
+#endif
+ }
+#ifdef DB_DUPSORT
+ if (dbst->dup_compare == 0 && rb_respond_to(obj, id_dup_compare) == Qtrue) {
+ dbst->options |= BDB_DUP_COMPARE;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->dup_compare = bdb_dup_compare;
+#else
+ bdb_test_error(dbp->set_dup_compare(dbp, bdb_dup_compare));
+#endif
+ }
+#endif
+ if (dbst->h_hash == 0 && rb_respond_to(obj, id_h_hash) == Qtrue) {
+ dbst->options |= BDB_H_HASH;
+#if BDB_VERSION < 30000
+ dbst->dbinfo->h_hash = bdb_h_hash;
+#else
+ bdb_test_error(dbp->set_h_hash(dbp, bdb_h_hash));
+#endif
+ }
+#if BDB_VERSION >= 40100
+ if (dbst->append_recno == 0 && rb_respond_to(obj, id_append_recno) == Qtrue) {
+ dbst->options |= BDB_APPEND_RECNO;
+ bdb_test_error(dbp->set_append_recno(dbp, bdb_append_recno));
+ }
+#endif
+#if BDB_VERSION >= 30000
+ if (dbst->feedback == 0 && rb_respond_to(obj, id_feedback) == Qtrue) {
+ dbp->set_feedback(dbp, bdb_feedback);
+ dbst->options |= BDB_FEEDBACK;
+ }
+#endif
+ if (flags & DB_TRUNCATE) {
+ rb_secure(2);
+ }
+ if (flags & DB_CREATE) {
+ rb_secure(4);
+ }
+ if (rb_safe_level() >= 4) {
+ flags |= DB_RDONLY;
+ }
+#ifdef DB_DUPSORT
+ if (dbst->options & BDB_DUP_COMPARE) {
+#if BDB_VERSION < 30000
+ dbst->dbinfo->flags = DB_DUP | DB_DUPSORT;
+#else
+ bdb_test_error(dbp->set_flags(dbp, DB_DUP | DB_DUPSORT));
+#endif
+ }
+#endif
+#ifndef BDB_NO_THREAD_COMPILE
+ if (!(dbst->options & (BDB_RE_SOURCE | BDB_NO_THREAD))) {
+ flags |= DB_THREAD;
+ }
+#endif
+ if (dbst->options & BDB_NEED_CURRENT) {
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_db, obj);
+ }
+
+#if BDB_VERSION < 30000
+ {
+ bdb_ENV *envst;
+ DB_ENV *envp = NULL;
+ if (dbst->env) {
+ Data_Get_Struct(dbst->env, bdb_ENV, envst);
+ envp = envst->envp;
+ }
+
+ if (name == NULL && (flags & DB_RDONLY)) {
+ flags &= ~DB_RDONLY;
+ }
+
+ if ((ret = db_open(name, dbst->type, flags, mode, envp,
+ dbst->dbinfo, &dbp)) != 0) {
+ if (bdb_errcall) {
+ bdb_errcall = 0;
+ rb_raise(bdb_eFatal, "%s -- %s", StringValuePtr(bdb_errstr), db_strerror(ret));
+ }
+ else
+ rb_raise(bdb_eFatal, "%s", db_strerror(ret));
+ }
+ dbst->dbp = dbp;
+ }
+#else
+ {
+ DB_TXN *txnid = NULL;
+
+ if (name == NULL && subname == NULL) {
+ if (flags & DB_RDONLY) {
+ flags &= ~DB_RDONLY;
+ }
+#if BDB_VERSION >= 40416
+ flags |= DB_CREATE;
+#endif
+ }
+#if BDB_VERSION >= 40100
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ else if (RTEST(dbst->env)) {
+ bdb_ENV *envst;
+
+ GetEnvDB(dbst->env, envst);
+ if (envst->options & BDB_AUTO_COMMIT) {
+ flags |= DB_AUTO_COMMIT;
+ dbst->options |= BDB_AUTO_COMMIT;
+ }
+ }
+ ret = dbp->open(dbp, txnid, name, subname, dbst->type, flags, mode);
+#else
+ ret = dbp->open(dbp, name, subname, dbst->type, flags, mode);
+#endif
+ if (ret != 0) {
+ dbp->close(dbp, 0);
+ if (bdb_errcall) {
+ bdb_errcall = 0;
+ rb_raise(bdb_eFatal, "%s -- %s", StringValuePtr(bdb_errstr), db_strerror(ret));
+ }
+ else {
+ rb_raise(bdb_eFatal, "%s", db_strerror(ret));
+ }
+ }
+ }
+#endif
+ dbst->options &= ~BDB_NOT_OPEN;
+ if (dbst->env) {
+ bdb_ENV *envst;
+ Data_Get_Struct(dbst->env, bdb_ENV, envst);
+ dbst->options |= envst->options & BDB_INIT_LOCK;
+ }
+ dbst->filename = dbst->database = Qnil;
+ if (name) {
+ dbst->filename = rb_tainted_str_new2(name);
+ OBJ_FREEZE(dbst->filename);
+ }
+#if BDB_VERSION >= 30000
+ if (subname) {
+ dbst->database = rb_tainted_str_new2(subname);
+ OBJ_FREEZE(dbst->database);
+ }
+#endif
+ dbst->len = -2;
+ if (dbst->type == DB_UNKNOWN) {
+#if BDB_VERSION < 30000
+ dbst->type = dbst->dbp->type;
+#else
+#if BDB_VERSION >= 30300
+ {
+ DBTYPE new_type;
+ bdb_test_error(dbst->dbp->get_type(dbst->dbp, &new_type));
+ dbst->type = (int)new_type;
+ }
+#else
+ dbst->type = dbst->dbp->get_type(dbst->dbp);
+#endif
+#endif
+ switch(dbst->type) {
+ case DB_BTREE:
+ RBASIC(obj)->klass = bdb_cBtree;
+ break;
+ case DB_HASH:
+ RBASIC(obj)->klass = bdb_cHash;
+ break;
+ case DB_RECNO:
+ {
+ long count;
+
+ rb_warning("It's hard to distinguish Recnum with Recno for all versions of Berkeley DB");
+ if ((count = bdb_is_recnum(dbst->dbp)) != -1) {
+ RBASIC(obj)->klass = bdb_cRecnum;
+ dbst->len = count;
+ }
+ else {
+ RBASIC(obj)->klass = bdb_cRecno;
+ }
+ break;
+ }
+#if BDB_VERSION >= 30000
+ case DB_QUEUE:
+ RBASIC(obj)->klass = bdb_cQueue;
+ break;
+#endif
+ default:
+ dbst->dbp->close(dbst->dbp, 0);
+ dbst->dbp = NULL;
+ rb_raise(bdb_eFatal, "Unknown DB type");
+ }
+ }
+ if (dbst->len == -2 && rb_obj_is_kind_of(obj, bdb_cRecnum)) {
+ long count;
+
+ if ((count = bdb_is_recnum(dbst->dbp)) != -1) {
+ VALUE len = bdb_recno_length(obj);
+ dbst->len = NUM2LONG(len);
+ }
+ else {
+ if (flags & DB_TRUNCATE) {
+ dbst->len = 0;
+ }
+ else {
+ dbst->dbp->close(dbst->dbp, 0);
+ dbst->dbp = NULL;
+ rb_raise(bdb_eFatal, "database is not a Recnum");
+ }
+ }
+ }
+ return obj;
+}
+
+static VALUE
+bdb_s_alloc(obj)
+ VALUE obj;
+{
+ VALUE res, cl;
+ bdb_DB *dbst;
+
+ res = Data_Make_Struct(obj, bdb_DB, bdb_mark, bdb_free, dbst);
+ dbst->options = BDB_NOT_OPEN;
+ cl = obj;
+ while (cl) {
+ if (cl == bdb_cBtree || RCLASS(cl)->m_tbl == RCLASS(bdb_cBtree)->m_tbl) {
+ dbst->type = DB_BTREE;
+ break;
+ }
+ if (cl == bdb_cRecnum || RCLASS(cl)->m_tbl == RCLASS(bdb_cRecnum)->m_tbl) {
+ dbst->type = DB_RECNO;
+ break;
+ }
+ else if (cl == bdb_cHash || RCLASS(cl)->m_tbl == RCLASS(bdb_cHash)->m_tbl) {
+ dbst->type = DB_HASH;
+ break;
+ }
+ else if (cl == bdb_cRecno || RCLASS(cl)->m_tbl == RCLASS(bdb_cRecno)->m_tbl) {
+ dbst->type = DB_RECNO;
+ break;
+ }
+#if BDB_VERSION >= 30000
+ else if (cl == bdb_cQueue || RCLASS(cl)->m_tbl == RCLASS(bdb_cQueue)->m_tbl) {
+ dbst->type = DB_QUEUE;
+ break;
+ }
+#endif
+ else if (cl == bdb_cUnknown || RCLASS(cl)->m_tbl == RCLASS(bdb_cUnknown)->m_tbl) {
+ dbst->type = DB_UNKNOWN;
+ break;
+ }
+ cl = RCLASS(cl)->super;
+ }
+ if (!cl) {
+ rb_raise(bdb_eFatal, "unknown database type");
+ }
+ dbst->ori_val = res;
+ return res;
+}
+
+static VALUE
+bdb_i_s_create(obj, db)
+ VALUE obj, db;
+{
+ VALUE tmp[2];
+ tmp[0] = rb_ary_entry(obj, 0);
+ tmp[1] = rb_ary_entry(obj, 1);
+ bdb_put(2, tmp, db);
+ return Qnil;
+}
+
+static VALUE
+bdb_s_create(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE res;
+ int i;
+
+ res = rb_funcall2(obj, rb_intern("new"), 0, 0);
+ if (argc == 1 && TYPE(argv[0]) == T_HASH) {
+ rb_iterate(rb_each, argv[0], bdb_i_s_create, res);
+ return res;
+ }
+ if (argc % 2 != 0) {
+ rb_raise(rb_eArgError, "odd number args for %s", rb_class2name(obj));
+ }
+ for (i = 0; i < argc; i += 2) {
+ bdb_put(2, argv + i, res);
+ }
+ return res;
+}
+
+static VALUE
+bdb_s_open(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE res = rb_funcall2(obj, rb_intern("new"), argc, argv);
+ if (rb_block_given_p()) {
+ return rb_ensure(rb_yield, res, bdb_protect_close, res);
+ }
+ return res;
+}
+
+#if BDB_VERSION >= 30000
+
+struct re {
+ int re_len, re_pad;
+};
+
+static VALUE
+bdb_queue_i_search_re_len(obj, restobj)
+ VALUE obj, restobj;
+{
+ VALUE key, value;
+ char *str;
+ struct re *rest;
+
+ Data_Get_Struct(restobj, struct re, rest);
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ key = rb_obj_as_string(key);
+ if (strcmp(StringValuePtr(key), "set_re_len") == 0) {
+ rest->re_len = NUM2INT(value);
+ }
+ else if (strcmp(StringValuePtr(key), "set_re_pad") == 0) {
+ int ch;
+ if (TYPE(value) == T_STRING) {
+ str = StringValuePtr(value);
+ ch = str[0];
+ }
+ else {
+ ch = NUM2INT(value);
+ }
+ rest->re_pad = ch;
+ }
+ return Qnil;
+}
+
+#define DEFAULT_RECORD_LENGTH 132
+#define DEFAULT_RECORD_PAD 0x20
+
+static VALUE
+bdb_queue_s_new(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE *nargv, ret, restobj;
+ struct re *rest;
+ bdb_DB *dbst;
+
+ restobj = Data_Make_Struct(obj, struct re, 0, free, rest);
+ rest->re_len = -1;
+ rest->re_pad = -1;
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ rb_iterate(rb_each, argv[argc - 1], bdb_queue_i_search_re_len, restobj);
+ if (rest->re_len <= 0) {
+ rest->re_len = DEFAULT_RECORD_LENGTH;
+ rb_hash_aset(argv[argc - 1], rb_tainted_str_new2("set_re_len"), INT2NUM(rest->re_len));
+ }
+ if (rest->re_pad < 0) {
+ rest->re_pad = DEFAULT_RECORD_PAD;
+ rb_hash_aset(argv[argc - 1], rb_tainted_str_new2("set_re_pad"), INT2NUM(rest->re_pad));
+ }
+ nargv = argv;
+ }
+ else {
+ nargv = ALLOCA_N(VALUE, argc + 1);
+ MEMCPY(nargv, argv, VALUE, argc);
+ nargv[argc] = rb_hash_new();
+ rest->re_len = DEFAULT_RECORD_LENGTH;
+ rest->re_pad = DEFAULT_RECORD_PAD;
+ rb_hash_aset(nargv[argc], rb_tainted_str_new2("set_re_len"), INT2NUM(DEFAULT_RECORD_LENGTH));
+ rb_hash_aset(nargv[argc], rb_tainted_str_new2("set_re_pad"), INT2NUM(DEFAULT_RECORD_PAD));
+ argc += 1;
+ }
+ ret = bdb_s_new(argc, nargv, obj);
+ Data_Get_Struct(ret, bdb_DB, dbst);
+ dbst->re_len = rest->re_len;
+ dbst->re_pad = rest->re_pad;
+ return ret;
+}
+#endif
+
+static VALUE
+bdb_append_internal(argc, argv, obj, flag, retval)
+ int argc, flag;
+ VALUE *argv, obj;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key, data;
+ db_recno_t recno;
+ int i;
+ VALUE *a, ary = Qnil;
+ volatile VALUE res = Qnil;
+
+ rb_secure(4);
+ if (argc < 1)
+ return obj;
+ INIT_TXN(txnid, obj, dbst);
+ if (txnid == NULL && (dbst->options & BDB_AUTO_COMMIT)) {
+ flag |= DB_AUTO_COMMIT;
+ }
+ MEMZERO(&key, DBT, 1);
+ recno = 1;
+ key.data = &recno;
+ key.size = sizeof(db_recno_t);
+#if BDB_VERSION >= 40100
+ if (flag & DB_APPEND) {
+ key.flags |= DB_DBT_MALLOC;
+ }
+#endif
+ if (retval) {
+ ary = rb_ary_new();
+ }
+ for (i = 0, a = argv; i < argc; i++, a++) {
+ MEMZERO(&data, DBT, 1);
+ res = bdb_test_dump(obj, &data, *a, FILTER_VALUE);
+ SET_PARTIAL(dbst, data);
+#if BDB_VERSION >= 30000
+ if (dbst->type == DB_QUEUE && dbst->re_len < data.size) {
+ rb_raise(bdb_eFatal, "size > re_len for Queue");
+ }
+#endif
+ bdb_test_error(dbst->dbp->put(dbst->dbp, txnid, &key, &data, flag));
+ if (retval) {
+ rb_ary_push(ary, INT2NUM(*(db_recno_t *)key.data));
+ }
+ }
+ if (retval) {
+ return ary;
+ }
+ return obj;
+}
+
+static VALUE
+bdb_append_m(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_append_internal(argc, argv, obj, DB_APPEND, Qtrue);
+}
+
+static VALUE
+bdb_append(obj, val)
+ VALUE val, obj;
+{
+ return bdb_append_internal(1, &val, obj, DB_APPEND, Qfalse);
+}
+
+static VALUE
+bdb_unshift(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ int flag;
+
+ INIT_TXN(txnid, obj, dbst);
+ if (dbst->flags & DB_RENUMBER) {
+ flag = 0;
+ }
+ else {
+ flag = DB_NOOVERWRITE;
+ }
+ return bdb_append_internal(argc, argv, obj, flag, Qtrue);
+}
+
+VALUE
+bdb_put(int argc, VALUE *argv, VALUE obj)
+{
+ volatile VALUE a0 = Qnil;
+ volatile VALUE b0 = Qnil;
+ VALUE a, b, c;
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key, data;
+ int ret, flags;
+ db_recno_t recno;
+
+ rb_secure(4);
+ INIT_TXN(txnid, obj, dbst);
+ flags = 0;
+ a = b = c = Qnil;
+ MEMZERO(&key, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ if (rb_scan_args(argc, argv, "21", &a, &b, &c) == 3) {
+ flags = NUM2INT(c);
+ }
+ a0 = bdb_test_recno(obj, &key, &recno, a);
+ b0 = bdb_test_dump(obj, &data, b, FILTER_VALUE);
+ SET_PARTIAL(dbst, data);
+#if BDB_VERSION >= 30000
+ if (dbst->type == DB_QUEUE && dbst->re_len < data.size) {
+ rb_raise(bdb_eFatal, "size > re_len for Queue");
+ }
+#endif
+ if (txnid == NULL && (dbst->options & BDB_AUTO_COMMIT)) {
+ flags |= DB_AUTO_COMMIT;
+ }
+ ret = bdb_test_error(dbst->dbp->put(dbst->dbp, txnid, &key, &data, flags));
+ if (ret == DB_KEYEXIST)
+ return Qfalse;
+ else {
+ if (dbst->partial) {
+ if (flags & DB_APPEND) {
+ a = INT2NUM((long)key.data);
+ }
+ return bdb_get(1, &a, obj);
+ }
+ else {
+ return bdb_test_ret(obj, b0, b, FILTER_VALUE);
+ }
+ }
+}
+
+static VALUE
+bdb_aset(obj, a, b)
+ VALUE obj, a, b;
+{
+ VALUE tmp[2];
+ tmp[0] = a;
+ tmp[1] = b;
+ bdb_put(2, tmp, obj);
+ return b;
+}
+
+VALUE
+bdb_test_load_key(obj, key)
+ VALUE obj;
+ DBT *key;
+{
+ bdb_DB *dbst;
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (RECNUM_TYPE(dbst))
+ return INT2NUM((*(db_recno_t *)key->data) - dbst->array_base);
+ return bdb_test_load(obj, key, FILTER_KEY);
+}
+
+VALUE
+bdb_assoc(obj, key, data)
+ VALUE obj;
+ DBT *key, *data;
+{
+ return rb_assoc_new(bdb_test_load_key(obj, key),
+ bdb_test_load(obj, data, FILTER_VALUE));
+}
+
+VALUE
+bdb_assoc_dyna(obj, key, data)
+ VALUE obj;
+ DBT *key, *data;
+{
+ VALUE k, v;
+ int to_free = key->flags & DB_DBT_MALLOC;
+
+ key->flags &= ~DB_DBT_MALLOC;
+ k = bdb_test_load_key(obj, key);
+ v = test_load_dyna1(obj, key, data);
+ if (to_free) {
+ free(key->data);
+ }
+ return rb_assoc_new(k, v);
+}
+
+static VALUE
+bdb_assoc2(obj, skey, pkey, data)
+ VALUE obj;
+ DBT *skey, *pkey, *data;
+{
+ return rb_assoc_new(
+ rb_assoc_new(bdb_test_load_key(obj, skey), bdb_test_load_key(obj, pkey)),
+ bdb_test_load(obj, data, FILTER_VALUE));
+}
+
+VALUE
+bdb_assoc3(obj, skey, pkey, data)
+ VALUE obj;
+ DBT *skey, *pkey, *data;
+{
+ return rb_ary_new3(3, bdb_test_load_key(obj, skey),
+ bdb_test_load_key(obj, pkey),
+ bdb_test_load(obj, data, FILTER_VALUE));
+}
+
+static VALUE bdb_has_both _((VALUE, VALUE, VALUE));
+static VALUE bdb_has_both_internal _((VALUE, VALUE, VALUE, VALUE));
+
+static VALUE
+bdb_get_internal(argc, argv, obj, notfound, dyna)
+ int argc;
+ VALUE *argv;
+ VALUE obj;
+ VALUE notfound;
+ int dyna;
+{
+ VALUE a = Qnil;
+ VALUE b = Qnil;
+ VALUE c;
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key, data;
+#if BDB_VERSION < 20600
+#define DB_GET_BOTH 9
+#endif
+ int flagss;
+ int ret, flags;
+ db_recno_t recno;
+
+ INIT_TXN(txnid, obj, dbst);
+ flagss = flags = 0;
+ MEMZERO(&key, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ switch(rb_scan_args(argc, argv, "12", &a, &b, &c)) {
+ case 3:
+ flags = NUM2INT(c);
+ if ((flags & ~DB_RMW) == DB_GET_BOTH) {
+#if BDB_VERSION < 20600
+ return bdb_has_both_internal(obj, a, b, Qtrue);
+#else
+ b = bdb_test_dump(obj, &data, b, FILTER_VALUE);
+ data.flags |= DB_DBT_MALLOC;
+#endif
+ }
+ break;
+ case 2:
+ flagss = flags = NUM2INT(b);
+ break;
+ }
+ a = bdb_test_recno(obj, &key, &recno, a);
+ SET_PARTIAL(dbst, data);
+ flags |= TEST_INIT_LOCK(dbst);
+ ret = bdb_test_error(dbst->dbp->get(dbst->dbp, txnid, &key, &data, flags));
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
+ return notfound;
+ if (((flags & ~DB_RMW) == DB_GET_BOTH) ||
+ ((flags & ~DB_RMW) == DB_SET_RECNO)) {
+ return bdb_assoc(obj, &key, &data);
+ }
+ if (dyna) {
+ return test_load_dyna(obj, &key, &data);
+ }
+ else {
+ return bdb_test_load(obj, &data, FILTER_VALUE);
+ }
+}
+
+VALUE
+bdb_get(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_get_internal(argc, argv, obj, Qnil, 0);
+}
+
+static VALUE
+bdb_get_dyna(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_get_internal(argc, argv, obj, Qnil, 1);
+}
+
+static VALUE
+bdb_fetch(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE key, if_none;
+ VALUE val;
+
+ rb_scan_args(argc, argv, "11", &key, &if_none);
+ val = bdb_get_internal(1, argv, obj, Qundef, 1);
+ if (val == Qundef) {
+ if (rb_block_given_p()) {
+ if (argc > 1) {
+ rb_raise(rb_eArgError, "wrong # of arguments", argc);
+ }
+ return rb_yield(key);
+ }
+ if (argc == 1) {
+ rb_raise(rb_eIndexError, "key not found");
+ }
+ return if_none;
+ }
+ return val;
+}
+
+#if BDB_VERSION >= 30300
+
+static VALUE
+bdb_pget(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE a = Qnil;
+ VALUE b = Qnil;
+ VALUE c;
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT pkey, data, skey;
+ int flagss;
+ int ret, flags;
+ db_recno_t srecno;
+
+ INIT_TXN(txnid, obj, dbst);
+ flagss = flags = 0;
+ MEMZERO(&skey, DBT, 1);
+ MEMZERO(&pkey, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ pkey.flags |= DB_DBT_MALLOC;
+ switch(rb_scan_args(argc, argv, "12", &a, &b, &c)) {
+ case 3:
+ flags = NUM2INT(c);
+ if ((flags & ~DB_RMW) == DB_GET_BOTH) {
+ b = bdb_test_dump(obj, &data, b, FILTER_VALUE);
+ data.flags |= DB_DBT_MALLOC;
+ }
+ break;
+ case 2:
+ flagss = flags = NUM2INT(b);
+ break;
+ }
+ a = bdb_test_recno(obj, &skey, &srecno, a);
+ SET_PARTIAL(dbst, data);
+ flags |= TEST_INIT_LOCK(dbst);
+ ret = bdb_test_error(dbst->dbp->pget(dbst->dbp, txnid, &skey, &pkey, &data, flags));
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
+ return Qnil;
+ if (((flags & ~DB_RMW) == DB_GET_BOTH) ||
+ ((flags & ~DB_RMW) == DB_SET_RECNO)) {
+ return bdb_assoc2(obj, &skey, &pkey, &data);
+ }
+ return bdb_assoc(obj, &pkey, &data);
+}
+
+#endif
+
+#if BDB_VERSION >= 30100
+
+static VALUE
+bdb_btree_key_range(obj, a)
+ VALUE obj, a;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key;
+ db_recno_t recno;
+ DB_KEY_RANGE key_range;
+ volatile VALUE b = Qnil;
+
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ b = bdb_test_recno(obj, &key, &recno, a);
+ bdb_test_error(dbst->dbp->key_range(dbst->dbp, txnid, &key, &key_range, 0));
+ return rb_struct_new(bdb_sKeyrange,
+ rb_float_new(key_range.less),
+ rb_float_new(key_range.equal),
+ rb_float_new(key_range.greater));
+}
+#endif
+
+#if BDB_VERSION >= 40416
+
+
+struct data_flags {
+ DB_COMPACT *cdata;
+ int flags;
+};
+
+static VALUE
+bdb_compact_i(obj, dataobj)
+ VALUE obj, dataobj;
+{
+ VALUE key, value;
+ char *str;
+ struct data_flags *dtf;
+
+ Data_Get_Struct(dataobj, struct data_flags, dtf);
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ key = rb_obj_as_string(key);
+ str = StringValuePtr(key);
+ if (strcmp(str, "compact_timeout") == 0) {
+ dtf->cdata->compact_timeout = NUM2LONG(value);
+ }
+ else if (strcmp(str, "compact_fillpercent") == 0) {
+ dtf->cdata->compact_fillpercent = NUM2INT(value);
+ }
+ else if (strcmp(str, "flags") == 0) {
+ dtf->flags = NUM2INT(value);
+ }
+ else {
+ rb_warning("Unknown option %s", str);
+ }
+ return Qnil;
+}
+
+static VALUE
+bdb_treerec_compact(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT start, stop, end;
+ DBT *pstart, *pstop;
+ DB_COMPACT cdata;
+ db_recno_t recno_start, recno_stop;
+ int flags;
+ VALUE a, b, c, result;
+
+ pstop = pstart = NULL;
+ MEMZERO(&cdata, DB_COMPACT, 1);
+ flags = 0;
+ INIT_TXN(txnid, obj, dbst);
+ switch (rb_scan_args(argc, argv, "03", &a, &b, &c)) {
+ case 3:
+ if (FIXNUM_P(c)) {
+ flags = NUM2INT(c);
+ }
+ else {
+ struct data_flags *dtf;
+ VALUE dtobj;
+
+ dtobj = Data_Make_Struct(rb_cData, struct data_flags, 0, free, dtf);
+ dtf->cdata = &cdata;
+ dtf->flags = 0;
+ rb_iterate(rb_each, c, bdb_compact_i, dtobj);
+ flags = dtf->flags;
+ }
+ /* ... */
+ case 2:
+ if (!NIL_P(b)) {
+ MEMZERO(&stop, DBT, 1);
+ b = bdb_test_recno(obj, &start, &recno_stop, b);
+ pstop = &stop;
+ }
+ /* ... */
+ case 1:
+ if (!NIL_P(a)) {
+ MEMZERO(&start, DBT, 1);
+ a = bdb_test_recno(obj, &start, &recno_start, a);
+ pstart = &start;
+ }
+ }
+ MEMZERO(&end, DBT, 1);
+ bdb_test_error(dbst->dbp->compact(dbst->dbp, txnid, pstart, pstop, &cdata,
+ flags, &end));
+ result = rb_hash_new();
+ rb_hash_aset(result, rb_tainted_str_new2("end"), bdb_test_load_key(obj, &end));
+ rb_hash_aset(result, rb_tainted_str_new2("compact_deadlock"),
+ INT2NUM(cdata.compact_deadlock));
+ rb_hash_aset(result, rb_tainted_str_new2("compact_levels"),
+ INT2NUM(cdata.compact_levels));
+ rb_hash_aset(result, rb_tainted_str_new2("compact_pages_free"),
+ INT2NUM(cdata.compact_pages_free));
+ rb_hash_aset(result, rb_tainted_str_new2("compact_pages_examine"),
+ INT2NUM(cdata.compact_pages_examine));
+ rb_hash_aset(result, rb_tainted_str_new2("compact_pages_truncated"),
+ INT2NUM(cdata.compact_pages_truncated));
+ return result;
+}
+
+#endif
+
+
+#if BDB_VERSION >= 20600
+
+static VALUE
+bdb_count(obj, a)
+ VALUE obj, a;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int ret, flags27;
+ db_recno_t recno;
+ db_recno_t count;
+ volatile VALUE b = Qnil;
+
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ b = bdb_test_recno(obj, &key, &recno, a);
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ SET_PARTIAL(dbst, data);
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+ flags27 = TEST_INIT_LOCK(dbst);
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_SET | flags27),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return INT2NUM(0);
+ }
+#if BDB_VERSION >= 30100
+ bdb_cache_error(dbcp->c_count(dbcp, &count, 0), dbcp->c_close(dbcp), ret);
+ dbcp->c_close(dbcp);
+ return INT2NUM(count);
+#else
+ count = 1;
+ while (1) {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_NEXT_DUP | flags27),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return INT2NUM(count);
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ FREE_KEY(dbst, key);
+ if (data.flags & DB_DBT_MALLOC)
+ free(data.data);
+ count++;
+ }
+ return INT2NUM(-1);
+#endif
+}
+
+#endif
+
+#if BDB_VERSION >= 30000
+
+static VALUE
+bdb_consume(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key, data;
+ DBC *dbcp;
+ int ret;
+ db_recno_t recno;
+
+ rb_secure(4);
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ recno = 1;
+ key.data = &recno;
+ key.size = sizeof(db_recno_t);
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_CONSUME),
+ dbcp->c_close(dbcp), ret);
+ dbcp->c_close(dbcp);
+ if (ret == DB_NOTFOUND) {
+ return Qnil;
+ }
+ return bdb_assoc(obj, &key, &data);
+}
+
+#endif
+
+static VALUE
+bdb_has_key(obj, key)
+ VALUE obj, key;
+{
+ return (bdb_get_internal(1, &key, obj, Qundef, 0) == Qundef)?Qfalse:Qtrue;
+}
+
+static VALUE
+bdb_has_both_internal(obj, a, b, flag)
+ VALUE obj, a, b, flag;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ DBT datas;
+ int flagss;
+ int ret, flags;
+ db_recno_t recno;
+ volatile VALUE c = Qnil;
+ volatile VALUE d = Qnil;
+
+ INIT_TXN(txnid, obj, dbst);
+ flagss = flags = 0;
+ MEMZERO(&key, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ MEMZERO(&datas, DBT, 1);
+ c = bdb_test_recno(obj, &key, &recno, a);
+ d = bdb_test_dump(obj, &datas, b, FILTER_VALUE);
+ data.flags |= DB_DBT_MALLOC;
+ SET_PARTIAL(dbst, data);
+ flags |= TEST_INIT_LOCK(dbst);
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_SET),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY) {
+ dbcp->c_close(dbcp);
+ return (flag == Qtrue)?Qnil:Qfalse;
+ }
+ if (datas.size == data.size &&
+ memcmp(datas.data, data.data, data.size) == 0) {
+ dbcp->c_close(dbcp);
+ if (flag == Qtrue) {
+ return bdb_assoc(obj, &key, &data);
+ }
+ else {
+ FREE_KEY(dbst, key);
+ free(data.data);
+ return Qtrue;
+ }
+ }
+#if BDB_VERSION < 20600
+#define DB_NEXT_DUP 0
+ FREE_KEY(dbst, key);
+ free(data.data);
+ dbcp->c_close(dbcp);
+ return (flag == Qtrue)?Qnil:Qfalse;
+#endif
+#if BDB_VERSION < 30100
+ if (RECNUM_TYPE(dbst)) {
+ free(data.data);
+ dbcp->c_close(dbcp);
+ return Qfalse;
+ }
+#endif
+ while (1) {
+ FREE_KEY(dbst, key);
+ free(data.data);
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_NEXT_DUP),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY) {
+ dbcp->c_close(dbcp);
+ return Qfalse;
+ }
+ if (datas.size == data.size &&
+ memcmp(datas.data, data.data, data.size) == 0) {
+ FREE_KEY(dbst, key);
+ free(data.data);
+ dbcp->c_close(dbcp);
+ return Qtrue;
+ }
+ }
+ return Qfalse;
+}
+
+static VALUE
+bdb_has_both(obj, a, b)
+ VALUE obj, a, b;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key, data;
+ int ret, flags;
+ db_recno_t recno;
+ volatile VALUE c = Qnil;
+ volatile VALUE d = Qnil;
+
+#if BDB_VERSION < 20600
+ return bdb_has_both_internal(obj, a, b, Qfalse);
+#else
+ INIT_TXN(txnid, obj, dbst);
+#if BDB_VERSION < 30100
+ if (RECNUM_TYPE(dbst)) {
+ return bdb_has_both_internal(obj, a, b, Qfalse);
+ }
+#endif
+ MEMZERO(&key, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ c = bdb_test_recno(obj, &key, &recno, a);
+ d = bdb_test_dump(obj, &data, b, FILTER_VALUE);
+ data.flags |= DB_DBT_MALLOC;
+ SET_PARTIAL(dbst, data);
+ flags = DB_GET_BOTH | TEST_INIT_LOCK(dbst);
+ ret = bdb_test_error(dbst->dbp->get(dbst->dbp, txnid, &key, &data, flags));
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
+ return Qfalse;
+ free(data.data);
+ return Qtrue;
+#endif
+}
+
+VALUE
+bdb_del(obj, a)
+ VALUE a, obj;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ int flag = 0;
+ DBT key;
+ int ret;
+ db_recno_t recno;
+ volatile VALUE b = Qnil;
+
+ rb_secure(4);
+ INIT_TXN(txnid, obj, dbst);
+ if (txnid == NULL && (dbst->options & BDB_AUTO_COMMIT)) {
+ flag |= DB_AUTO_COMMIT;
+ }
+ MEMZERO(&key, DBT, 1);
+ b = bdb_test_recno(obj, &key, &recno, a);
+ ret = bdb_test_error(dbst->dbp->del(dbst->dbp, txnid, &key, flag));
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
+ return Qnil;
+ else
+ return obj;
+}
+
+static VALUE
+bdb_empty(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int ret, flags;
+ db_recno_t recno;
+
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ SET_PARTIAL(dbst, data);
+ flags = TEST_INIT_LOCK(dbst);
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_FIRST | flags),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return Qtrue;
+ }
+ FREE_KEY(dbst, key);
+ free(data.data);
+ dbcp->c_close(dbcp);
+ return Qfalse;
+}
+
+static VALUE
+bdb_lgth_intern(obj, delete)
+ VALUE obj, delete;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int ret, value, flags;
+ db_recno_t recno;
+
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+ value = 0;
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ SET_PARTIAL(dbst, data);
+ flags = TEST_INIT_LOCK(dbst);
+ do {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, DB_NEXT | flags),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return INT2NUM(value);
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ FREE_KEY(dbst, key);
+ free(data.data);
+ value++;
+ if (delete == Qtrue) {
+ bdb_test_error(dbcp->c_del(dbcp, 0));
+ }
+ } while (1);
+ return INT2NUM(-1);
+}
+
+static VALUE
+bdb_length(obj)
+ VALUE obj;
+{
+ return bdb_lgth_intern(obj, Qfalse);
+}
+
+typedef struct {
+ int sens;
+ VALUE replace;
+ VALUE db;
+ VALUE set;
+ DBC *dbcp;
+#if BDB_VERSION >= 30300
+ void *data;
+ int len;
+#endif
+ int primary;
+ int type;
+} eachst;
+
+static VALUE
+bdb_each_ensure(st)
+ eachst *st;
+{
+#if BDB_VERSION >= 30300
+ if (st->len && st->data) {
+ free(st->data);
+ }
+#endif
+ st->dbcp->c_close(st->dbcp);
+ return Qnil;
+}
+
+static void
+bdb_treat(st, pkey, key, data)
+ eachst *st;
+ DBT *pkey, *key, *data;
+{
+ bdb_DB *dbst;
+ DBC *dbcp;
+ VALUE res = Qnil;
+
+ GetDB(st->db, dbst);
+ dbcp = st->dbcp;
+ switch (st->type) {
+ case BDB_ST_DUPU:
+ FREE_KEY(dbst, *key);
+ res = bdb_test_load(st->db, data, FILTER_VALUE);
+ if (TYPE(st->replace) == T_ARRAY) {
+ rb_ary_push(st->replace, res);
+ }
+ else {
+ rb_yield(res);
+ }
+ break;
+ case BDB_ST_DUPKV:
+ rb_yield(bdb_assoc_dyna(st->db, key, data));
+ break;
+ case BDB_ST_DUPVAL:
+ res = test_load_dyna(st->db, key, data);
+ if (TYPE(st->replace) == T_ARRAY) {
+ rb_ary_push(st->replace, res);
+ }
+ else {
+ rb_yield(res);
+ }
+ break;
+ case BDB_ST_KEY:
+ if (data->flags & DB_DBT_MALLOC) {
+ free(data->data);
+ data->flags &= ~DB_DBT_MALLOC;
+ }
+ rb_yield(bdb_test_load_key(st->db, key));
+ break;
+
+ case BDB_ST_VALUE:
+ FREE_KEY(dbst, *key);
+ res = rb_yield(bdb_test_load(st->db, data, FILTER_VALUE));
+ if (st->replace == Qtrue) {
+ MEMZERO(data, DBT, 1);
+ res = bdb_test_dump(st->db, data, res, FILTER_VALUE);
+ SET_PARTIAL(dbst, *data);
+ bdb_test_error(dbcp->c_put(dbcp, key, data, DB_CURRENT));
+ }
+ else if (st->replace != Qfalse) {
+ rb_ary_push(st->replace, res);
+ }
+ break;
+ case BDB_ST_SELECT:
+ res = bdb_assoc(st->db, key, data);
+ if (RTEST(rb_yield(res))) {
+ rb_ary_push(st->replace, res);
+ }
+ break;
+ case BDB_ST_KV:
+ if (st->primary) {
+ rb_yield(bdb_assoc3(st->db, key, pkey, data));
+ }
+ else {
+ rb_yield(bdb_assoc_dyna(st->db, key, data));
+ }
+ break;
+ case BDB_ST_REJECT:
+ {
+ VALUE ary = bdb_assoc(st->db, key, data);
+ if (!RTEST(rb_yield(ary))) {
+ rb_hash_aset(st->replace, RARRAY(ary)->ptr[0], RARRAY(ary)->ptr[1]);
+ }
+ break;
+ }
+ case BDB_ST_DELETE:
+ if (RTEST(rb_yield(bdb_assoc(st->db, key, data)))) {
+ bdb_test_error(dbcp->c_del(dbcp, 0));
+ }
+ break;
+ }
+}
+
+static VALUE
+bdb_i_each_kv(st)
+ eachst *st;
+{
+ bdb_DB *dbst;
+ DBC *dbcp;
+ DBT pkey, key, data, orig;
+ int ret, init = Qfalse, prefix = Qfalse;
+ db_recno_t recno;
+ volatile VALUE res = Qnil;
+
+ prefix = st->type & BDB_ST_PREFIX;
+ st->type &= ~BDB_ST_PREFIX;
+ GetDB(st->db, dbst);
+ dbcp = st->dbcp;
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&orig, DBT, 1);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+ SET_PARTIAL(dbst, data);
+ MEMZERO(&pkey, DBT, 1);
+ pkey.flags = DB_DBT_MALLOC;
+ if (!NIL_P(st->set)) {
+ res = bdb_test_recno(st->db, &key, &recno, st->set);
+ if (prefix) {
+ init = Qtrue;
+ orig.size = key.size;
+ orig.data = ALLOCA_N(char, key.size);
+ MEMCPY(orig.data, key.data, char, key.size);
+ }
+#if BDB_VERSION >= 30300
+ if (st->type == BDB_ST_KV && st->primary) {
+ ret = bdb_test_error(dbcp->c_pget(dbcp, &key, &pkey, &data,
+ (st->type & BDB_ST_DUP)?DB_SET:
+ DB_SET_RANGE));
+ }
+ else
+#endif
+ {
+#if BDB_VERSION < 20600
+ key.flags |= DB_DBT_MALLOC;
+#endif
+ ret = bdb_test_error(dbcp->c_get(dbcp, &key, &data,
+ (st->type & BDB_ST_DUP)?DB_SET:
+ DB_SET_RANGE));
+#if BDB_VERSION < 20600
+ key.flags &= ~DB_DBT_MALLOC;
+#endif
+ }
+ if (ret == DB_NOTFOUND) {
+ return Qfalse;
+ }
+ bdb_treat(st, &pkey, &key, &data);
+ }
+ do {
+#if BDB_VERSION >= 30300
+ if (st->type == BDB_ST_KV && st->primary) {
+ ret = bdb_test_error(dbcp->c_pget(dbcp, &key, &pkey, &data, st->sens));
+ }
+ else
+#endif
+ {
+#if BDB_VERSION < 20600
+ key.flags |= DB_DBT_MALLOC;
+#endif
+ ret = bdb_test_error(dbcp->c_get(dbcp, &key, &data, st->sens));
+#if BDB_VERSION < 20600
+ key.flags &= ~DB_DBT_MALLOC;
+#endif
+ }
+ if (ret == DB_NOTFOUND) {
+ return Qnil;
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ if (prefix) {
+ if (!init) {
+ init = Qtrue;
+ orig.size = key.size;
+ orig.data = ALLOCA_N(char, key.size);
+ MEMCPY(orig.data, key.data, char, key.size);
+ }
+ if (key.size >= orig.size &&
+ !memcmp(key.data, orig.data, orig.size)) {
+ bdb_treat(st, &pkey, &key, &data);
+ }
+ }
+ else {
+ bdb_treat(st, &pkey, &key, &data);
+ }
+ } while (1);
+ return Qnil;
+}
+
+#if BDB_VERSION >= 30300
+
+static VALUE
+bdb_i_each_kv_bulk(st)
+ eachst *st;
+{
+ bdb_DB *dbst;
+ DBC *dbcp;
+ DBT key, data;
+ DBT rkey, rdata;
+ DBT pkey;
+ int ret, init;
+ db_recno_t recno;
+ void *p;
+ volatile VALUE res = Qnil;
+
+ GetDB(st->db, dbst);
+ dbcp = st->dbcp;
+ MEMZERO(&key, DBT, 1);
+ MEMZERO(&pkey, DBT, 1);
+ MEMZERO(&rkey, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ MEMZERO(&rdata, DBT, 1);
+ st->data = data.data = (void *)ALLOC_N(char, st->len);
+ data.ulen = st->len;
+ data.flags = DB_DBT_USERMEM;
+ SET_PARTIAL(dbst, data);
+ SET_PARTIAL(dbst, rdata);
+ init = 1;
+ do {
+ if (init && !NIL_P(st->set)) {
+ res = bdb_test_recno(st->db, &key, &recno, st->set);
+ ret = bdb_test_error(dbcp->c_get(dbcp, &key, &data,
+ ((st->type & BDB_ST_DUP)?DB_SET:
+ DB_SET_RANGE)|DB_MULTIPLE_KEY));
+ init = 0;
+ }
+ else {
+ ret = bdb_test_error(dbcp->c_get(dbcp, &key, &data, st->sens | DB_MULTIPLE_KEY));
+ }
+ if (ret == DB_NOTFOUND) {
+ return Qnil;
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ for (DB_MULTIPLE_INIT(p, &data);;) {
+ if (RECNUM_TYPE(dbst)) {
+ DB_MULTIPLE_RECNO_NEXT(p, &data, recno,
+ rdata.data, rdata.size);
+ }
+ else {
+ DB_MULTIPLE_KEY_NEXT(p, &data, rkey.data, rkey.size,
+ rdata.data, rdata.size);
+ }
+ if (p == NULL) break;
+ bdb_treat(st, 0, &rkey, &rdata);
+ }
+ } while (1);
+ return Qnil;
+}
+
+#endif
+
+VALUE
+bdb_each_kvc(argc, argv, obj, sens, replace, type)
+ VALUE obj, *argv;
+ int argc, sens;
+ VALUE replace;
+ int type;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ eachst st;
+ int flags = 0;
+
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ VALUE g, f = argv[argc - 1];
+ if ((g = rb_hash_aref(f, rb_intern("flags"))) != RHASH(f)->ifnone ||
+ (g = rb_hash_aref(f, rb_str_new2("flags"))) != RHASH(f)->ifnone) {
+ flags = NUM2INT(g);
+ }
+ argc--;
+ }
+
+ MEMZERO(&st, eachst, 1);
+
+#if BDB_VERSION >= 30300
+ {
+ VALUE bulkv = Qnil;
+
+ st.set = Qnil;
+ if (type & BDB_ST_ONE) {
+ rb_scan_args(argc, argv, "01", &st.set);
+ }
+ else {
+ if (type & BDB_ST_DUP) {
+ rb_scan_args(argc, argv, "11", &st.set, &bulkv);
+ }
+ else {
+ if (rb_scan_args(argc, argv, "02", &st.set, &bulkv) == 2) {
+ if (bulkv == Qtrue || bulkv == Qfalse) {
+ st.primary = RTEST(bulkv);
+ bulkv = Qnil;
+ }
+ }
+ }
+ }
+ if (!NIL_P(bulkv)) {
+ st.len = 1024 * NUM2INT(bulkv);
+ if (st.len < 0) {
+ rb_raise(bdb_eFatal, "negative value for bulk retrieval");
+ }
+ }
+ }
+#else
+ if (type & BDB_ST_DUP) {
+ if (argc != 1) {
+ rb_raise(bdb_eFatal, "invalid number of arguments (%d for 1)", argc);
+ }
+ st.set = argv[0];
+ }
+ else {
+ rb_scan_args(argc, argv, "01", &st.set);
+ }
+#endif
+ type &= ~BDB_ST_ONE;
+ if ((type & ~BDB_ST_PREFIX) == BDB_ST_DELETE) {
+ rb_secure(4);
+ }
+ INIT_TXN(txnid, obj, dbst);
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, flags));
+#endif
+ st.db = obj;
+ st.dbcp = dbcp;
+ st.sens = sens | TEST_INIT_LOCK(dbst);
+ st.replace = replace;
+ st.type = type & ~BDB_ST_ONE;
+#if BDB_VERSION >= 30300
+ if (st.len) {
+ rb_ensure(bdb_i_each_kv_bulk, (VALUE)&st, bdb_each_ensure, (VALUE)&st);
+ }
+ else
+#endif
+ {
+ rb_ensure(bdb_i_each_kv, (VALUE)&st, bdb_each_ensure, (VALUE)&st);
+ }
+ if (replace == Qtrue || replace == Qfalse) {
+ return obj;
+ }
+ else {
+ return st.replace;
+ }
+}
+
+#if BDB_VERSION >= 20600
+
+static VALUE
+bdb_get_dup(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE result = Qfalse;
+ if (!rb_block_given_p()) {
+ result = rb_ary_new();
+ }
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT_DUP, result, BDB_ST_DUPU);
+}
+
+static VALUE
+bdb_common_each_dup(int argc, VALUE *argv, VALUE obj)
+{
+ if (!rb_block_given_p()) {
+ rb_raise(bdb_eFatal, "each_dup called out of an iterator");
+ }
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT_DUP, Qfalse, BDB_ST_DUPKV);
+}
+
+static VALUE
+bdb_common_each_dup_val(int argc, VALUE *argv, VALUE obj)
+{
+ if (!rb_block_given_p()) {
+ rb_raise(bdb_eFatal, "each_dup called out of an iterator");
+ }
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT_DUP, Qfalse, BDB_ST_DUPVAL);
+}
+
+static VALUE
+bdb_common_dups(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE result = rb_ary_new();
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT_DUP, result, BDB_ST_DUPVAL);
+}
+
+#endif
+
+static VALUE
+bdb_delete_if(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, Qfalse, BDB_ST_DELETE | BDB_ST_ONE);
+}
+
+static VALUE
+bdb_reject(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, rb_hash_new(), BDB_ST_REJECT);
+}
+
+VALUE
+bdb_each_value(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, Qfalse, BDB_ST_VALUE);
+}
+
+VALUE
+bdb_each_eulav(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_PREV, Qfalse, BDB_ST_VALUE | BDB_ST_ONE);
+}
+
+VALUE
+bdb_each_key(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, Qfalse, BDB_ST_KEY);
+}
+
+static VALUE
+bdb_each_yek(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_PREV, Qfalse, BDB_ST_KEY | BDB_ST_ONE);
+}
+
+static VALUE
+bdb_each_pair(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, Qfalse, BDB_ST_KV);
+}
+
+static VALUE
+bdb_each_prefix(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, Qfalse, BDB_ST_KV | BDB_ST_PREFIX);
+}
+
+static VALUE
+bdb_each_riap(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_PREV, Qfalse, BDB_ST_KV | BDB_ST_ONE);
+}
+
+static VALUE
+bdb_each_xiferp(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_PREV, Qfalse,
+ BDB_ST_KV | BDB_ST_ONE | BDB_ST_PREFIX);
+}
+
+static VALUE
+bdb_each_pair_prim(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE tmp[2] = {Qnil, Qtrue};
+ rb_scan_args(argc, argv, "01", tmp);
+ return bdb_each_kvc(2, tmp, obj, DB_NEXT, Qfalse, BDB_ST_KV);
+}
+
+static VALUE
+bdb_each_riap_prim(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE tmp[2] = {Qnil, Qtrue};
+ rb_scan_args(argc, argv, "01", tmp);
+ return bdb_each_kvc(2, tmp, obj, DB_PREV, Qfalse, BDB_ST_KV);
+}
+
+VALUE
+bdb_to_type(obj, result, flag)
+ VALUE obj, result, flag;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int ret, flags;
+ db_recno_t recno;
+
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ SET_PARTIAL(dbst, data);
+ flags = ((flag == Qnil)?DB_PREV:DB_NEXT) | TEST_INIT_LOCK(dbst);
+ do {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, flags),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return result;
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ switch (TYPE(result)) {
+ case T_ARRAY:
+ if (flag == Qtrue) {
+ rb_ary_push(result, bdb_assoc(obj, &key, &data));
+ }
+ else {
+ rb_ary_push(result, bdb_test_load(obj, &data, FILTER_VALUE));
+ }
+ break;
+ case T_HASH:
+ if (flag == Qtrue) {
+ rb_hash_aset(result, bdb_test_load_key(obj, &key),
+ bdb_test_load(obj, &data, FILTER_VALUE));
+ }
+ else {
+ rb_hash_aset(result, bdb_test_load(obj, &data, FILTER_VALUE),
+ bdb_test_load_key(obj, &key));
+ }
+ }
+
+ } while (1);
+ return result;
+}
+
+static VALUE
+bdb_to_a(obj)
+ VALUE obj;
+{
+ return bdb_to_type(obj, rb_ary_new(), Qtrue);
+}
+
+static VALUE
+each_pair(obj)
+ VALUE obj;
+{
+ return rb_funcall(obj, rb_intern("each_pair"), 0, 0);
+}
+
+static VALUE
+bdb_update_i(pair, obj)
+ VALUE pair, obj;
+{
+ Check_Type(pair, T_ARRAY);
+ if (RARRAY(pair)->len < 2) {
+ rb_raise(rb_eArgError, "pair must be [key, value]");
+ }
+ bdb_put(2, RARRAY(pair)->ptr, obj);
+ return Qnil;
+}
+
+static VALUE
+bdb_update(obj, other)
+ VALUE obj, other;
+{
+ rb_iterate(each_pair, other, bdb_update_i, obj);
+ return obj;
+}
+
+VALUE
+bdb_clear(int argc, VALUE *argv, VALUE obj)
+{
+#if BDB_VERSION >= 30300
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ unsigned int count = 0;
+#endif
+ int flags = 0;
+
+ rb_secure(4);
+#if BDB_VERSION >= 30300
+ INIT_TXN(txnid, obj, dbst);
+ if (txnid == NULL && (dbst->options & BDB_AUTO_COMMIT)) {
+ flags |= DB_AUTO_COMMIT;
+ }
+ bdb_test_error(dbst->dbp->truncate(dbst->dbp, txnid, &count, flags));
+ return INT2NUM(count);
+#else
+ flags = 0;
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ VALUE g, f = argv[argc - 1];
+ if ((g = rb_hash_aref(f, rb_intern("flags"))) != RHASH(f)->ifnone ||
+ (g = rb_hash_aref(f, rb_str_new2("flags"))) != RHASH(f)->ifnone) {
+ flags = NUM2INT(g);
+ }
+ argc--;
+ }
+ if (argc) {
+ flags = NUM2INT(argv[0]);
+ }
+ return bdb_lgth_intern(obj, Qtrue, flags);
+#endif
+}
+
+static VALUE
+bdb_replace(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE g;
+ int flags;
+
+ if (argc == 0 || argc > 2) {
+ rb_raise(rb_eArgError, "invalid number of arguments (0 for 1)");
+ }
+ flags = 0;
+ if (TYPE(argv[argc - 1]) == T_HASH) {
+ VALUE f = argv[argc - 1];
+ if ((g = rb_hash_aref(f, rb_intern("flags"))) != RHASH(f)->ifnone ||
+ (g = rb_hash_aref(f, rb_str_new2("flags"))) != RHASH(f)->ifnone) {
+ flags = NUM2INT(g);
+ }
+ argc--;
+ }
+ if (argc == 2) {
+ flags = NUM2INT(argv[1]);
+ }
+ g = INT2FIX(flags);
+ bdb_clear(1, &g, obj);
+ rb_iterate(each_pair, argv[0], bdb_update_i, obj);
+ return obj;
+}
+
+static VALUE
+bdb_invert(obj)
+ VALUE obj;
+{
+ return bdb_to_type(obj, rb_hash_new(), Qfalse);
+}
+
+static VALUE
+bdb_to_hash(obj)
+ VALUE obj;
+{
+ return bdb_to_type(obj, rb_hash_new(), Qtrue);
+}
+
+static VALUE
+bdb_kv(obj, type)
+ VALUE obj;
+ int type;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int ret, flags;
+ db_recno_t recno;
+ VALUE ary;
+
+ ary = rb_ary_new();
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ SET_PARTIAL(dbst, data);
+ flags = DB_NEXT | TEST_INIT_LOCK(dbst);
+ do {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, flags),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return ary;
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ switch (type) {
+ case BDB_ST_VALUE:
+ FREE_KEY(dbst, key);
+ rb_ary_push(ary, bdb_test_load(obj, &data, FILTER_VALUE));
+ break;
+ case BDB_ST_KEY:
+ free(data.data);
+ rb_ary_push(ary, bdb_test_load_key(obj, &key));
+ break;
+ }
+ } while (1);
+ return ary;
+}
+
+static VALUE
+bdb_values(obj)
+ VALUE obj;
+{
+ return bdb_kv(obj, BDB_ST_VALUE);
+}
+
+static VALUE
+bdb_keys(obj)
+ VALUE obj;
+{
+ return bdb_kv(obj, BDB_ST_KEY);
+}
+
+VALUE
+bdb_internal_value(obj, a, b, sens)
+ VALUE obj, a, b;
+ int sens;
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int ret, flags;
+ db_recno_t recno;
+
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ SET_PARTIAL(dbst, data);
+ flags = sens | TEST_INIT_LOCK(dbst);
+ do {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, flags),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) {
+ dbcp->c_close(dbcp);
+ return (b == Qfalse)?Qfalse:Qnil;
+ }
+ if (ret == DB_KEYEMPTY) continue;
+ if (rb_equal(a, bdb_test_load(obj, &data, FILTER_VALUE)) == Qtrue) {
+ VALUE d;
+
+ dbcp->c_close(dbcp);
+ if (b == Qfalse) {
+ d = Qtrue;
+ FREE_KEY(dbst, key);
+ }
+ else {
+ d = bdb_test_load_key(obj, &key);
+ }
+ return d;
+ }
+ FREE_KEY(dbst, key);
+ } while (1);
+ return (b == Qfalse)?Qfalse:Qnil;
+}
+
+VALUE
+bdb_index(obj, a)
+ VALUE obj, a;
+{
+ return bdb_internal_value(obj, a, Qtrue, DB_NEXT);
+}
+
+static VALUE
+bdb_indexes(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE indexes;
+ int i;
+
+#if RUBY_VERSION_CODE >= 172
+ rb_warn("Common#%s is deprecated; use Common#values_at",
+ rb_id2name(rb_frame_last_func()));
+#endif
+ indexes = rb_ary_new2(argc);
+ for (i = 0; i < argc; i++) {
+ RARRAY(indexes)->ptr[i] = bdb_get(1, &argv[i], obj);
+ }
+ RARRAY(indexes)->len = i;
+ return indexes;
+}
+
+static VALUE
+bdb_values_at(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE result = rb_ary_new2(argc);
+ long i;
+
+ for (i = 0; i < argc; i++) {
+ rb_ary_push(result, bdb_get(1, &argv[i], obj));
+ }
+ return result;
+}
+
+static VALUE
+bdb_select(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE result = rb_ary_new();
+
+ if (rb_block_given_p()) {
+ if (argc > 0) {
+ rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc);
+ }
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, result, BDB_ST_SELECT);
+ }
+ rb_warn("Common#select(index..) is deprecated; use Common#values_at");
+ return bdb_values_at(argc, argv, obj);
+}
+
+VALUE
+bdb_has_value(obj, a)
+ VALUE obj, a;
+{
+ return bdb_internal_value(obj, a, Qfalse, DB_NEXT);
+}
+
+static VALUE
+bdb_sync(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+ rb_raise(rb_eSecurityError, "Insecure: can't sync the database");
+ GetDB(obj, dbst);
+ bdb_test_error(dbst->dbp->sync(dbst->dbp, 0));
+ return Qtrue;
+}
+
+#if BDB_VERSION >= 30000
+static VALUE
+bdb_hash_stat(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ DB_HASH_STAT *bdb_stat;
+ VALUE hash, flagv;
+ int flags = 0;
+#if BDB_VERSION >= 4030
+ DB_TXN *txnid = NULL;
+#endif
+
+ if (rb_scan_args(argc, argv, "01", &flagv) == 1) {
+ flags = NUM2INT(flagv);
+ }
+ GetDB(obj, dbst);
+#if BDB_VERSION < 30300
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, 0, flags));
+#else
+#if BDB_VERSION >= 40300
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, txnid, &bdb_stat, flags));
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, flags));
+#endif
+#endif
+ hash = rb_hash_new();
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_magic"), INT2NUM(bdb_stat->hash_magic));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_version"), INT2NUM(bdb_stat->hash_version));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_pagesize"), INT2NUM(bdb_stat->hash_pagesize));
+#if BDB_VERSION >= 30114
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_nkeys"), INT2NUM(bdb_stat->hash_nkeys));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_nrecs"), INT2NUM(bdb_stat->hash_nkeys));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_ndata"), INT2NUM(bdb_stat->hash_ndata));
+#else
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_nrecs"), INT2NUM(bdb_stat->hash_nrecs));
+#endif
+#if BDB_VERSION < 40100
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_nelem"), INT2NUM(bdb_stat->hash_nelem));
+#endif
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_ffactor"), INT2NUM(bdb_stat->hash_ffactor));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_buckets"), INT2NUM(bdb_stat->hash_buckets));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_free"), INT2NUM(bdb_stat->hash_free));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_bfree"), INT2NUM(bdb_stat->hash_bfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_bigpages"), INT2NUM(bdb_stat->hash_bigpages));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_big_bfree"), INT2NUM(bdb_stat->hash_big_bfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_overflows"), INT2NUM(bdb_stat->hash_overflows));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_ovfl_free"), INT2NUM(bdb_stat->hash_ovfl_free));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_dup"), INT2NUM(bdb_stat->hash_dup));
+ rb_hash_aset(hash, rb_tainted_str_new2("hash_dup_free"), INT2NUM(bdb_stat->hash_dup_free));
+ free(bdb_stat);
+ return hash;
+}
+#endif
+
+VALUE
+bdb_tree_stat(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ DB_BTREE_STAT *bdb_stat;
+ VALUE hash, flagv;
+ char pad;
+ int flags = 0;
+#if BDB_VERSION >= 40300
+ DB_TXN *txnid = NULL;
+#endif
+
+ if (rb_scan_args(argc, argv, "01", &flagv) == 1) {
+ flags = NUM2INT(flagv);
+ }
+ GetDB(obj, dbst);
+#if BDB_VERSION >= 30300
+#if BDB_VERSION >= 40300
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, txnid, &bdb_stat, flags));
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, flags));
+#endif
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, 0, flags));
+#endif
+ hash = rb_hash_new();
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_magic"), INT2NUM(bdb_stat->bt_magic));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_version"), INT2NUM(bdb_stat->bt_version));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_dup_pg"), INT2NUM(bdb_stat->bt_dup_pg));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_dup_pgfree"), INT2NUM(bdb_stat->bt_dup_pgfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_free"), INT2NUM(bdb_stat->bt_free));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_int_pg"), INT2NUM(bdb_stat->bt_int_pg));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_int_pgfree"), INT2NUM(bdb_stat->bt_int_pgfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_leaf_pg"), INT2NUM(bdb_stat->bt_leaf_pg));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_leaf_pgfree"), INT2NUM(bdb_stat->bt_leaf_pgfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_levels"), INT2NUM(bdb_stat->bt_levels));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_minkey"), INT2NUM(bdb_stat->bt_minkey));
+#if BDB_VERSION >= 30100
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_nrecs"), INT2NUM(bdb_stat->bt_nkeys));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_nkeys"), INT2NUM(bdb_stat->bt_nkeys));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_ndata"), INT2NUM(bdb_stat->bt_ndata));
+#else
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_nrecs"), INT2NUM(bdb_stat->bt_nrecs));
+#endif
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_over_pg"), INT2NUM(bdb_stat->bt_over_pg));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_over_pgfree"), INT2NUM(bdb_stat->bt_over_pgfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_pagesize"), INT2NUM(bdb_stat->bt_pagesize));
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_re_len"), INT2NUM(bdb_stat->bt_re_len));
+ pad = (char)bdb_stat->bt_re_pad;
+ rb_hash_aset(hash, rb_tainted_str_new2("bt_re_pad"), rb_tainted_str_new(&pad, 1));
+ free(bdb_stat);
+ return hash;
+}
+
+#if BDB_VERSION >= 30000
+static VALUE
+bdb_queue_stat(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ DB_QUEUE_STAT *bdb_stat;
+ VALUE hash, flagv;
+ char pad;
+ int flags = 0;
+#if BDB_VERSION >= 40300
+ DB_TXN *txnid = NULL;
+#endif
+
+ if (rb_scan_args(argc, argv, "01", &flagv) == 1) {
+ flags = NUM2INT(flagv);
+ }
+ GetDB(obj, dbst);
+#if BDB_VERSION < 30300
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, 0, flags));
+#else
+#if BDB_VERSION >= 40300
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, txnid, &bdb_stat, flags));
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, flags));
+#endif
+#endif
+ hash = rb_hash_new();
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_magic"), INT2NUM(bdb_stat->qs_magic));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_version"), INT2NUM(bdb_stat->qs_version));
+#if BDB_VERSION >= 30114
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_nrecs"), INT2NUM(bdb_stat->qs_nkeys));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_nkeys"), INT2NUM(bdb_stat->qs_nkeys));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_ndata"), INT2NUM(bdb_stat->qs_ndata));
+#else
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_nrecs"), INT2NUM(bdb_stat->qs_nrecs));
+#endif
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_pages"), INT2NUM(bdb_stat->qs_pages));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_pagesize"), INT2NUM(bdb_stat->qs_pagesize));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_pgfree"), INT2NUM(bdb_stat->qs_pgfree));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_re_len"), INT2NUM(bdb_stat->qs_re_len));
+ pad = (char)bdb_stat->qs_re_pad;
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_re_pad"), rb_tainted_str_new(&pad, 1));
+#if BDB_VERSION < 30200
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_start"), INT2NUM(bdb_stat->qs_start));
+#endif
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_first_recno"), INT2NUM(bdb_stat->qs_first_recno));
+ rb_hash_aset(hash, rb_tainted_str_new2("qs_cur_recno"), INT2NUM(bdb_stat->qs_cur_recno));
+ free(bdb_stat);
+ return hash;
+}
+
+static VALUE
+bdb_queue_padlen(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ DB_QUEUE_STAT *bdb_stat;
+ VALUE hash;
+ char pad;
+#if BDB_VERSION >= 40300
+ DB_TXN *txnid = NULL;
+#endif
+
+ GetDB(obj, dbst);
+#if BDB_VERSION < 30300
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, 0, 0));
+#else
+#if BDB_VERSION >= 40300
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, txnid, &bdb_stat, 0));
+#else
+ bdb_test_error(dbst->dbp->stat(dbst->dbp, &bdb_stat, 0));
+#endif
+#endif
+ pad = (char)bdb_stat->qs_re_pad;
+ hash = rb_assoc_new(rb_tainted_str_new(&pad, 1), INT2NUM(bdb_stat->qs_re_len));
+ free(bdb_stat);
+ return hash;
+}
+#endif
+
+static VALUE
+bdb_set_partial(obj, a, b)
+ VALUE obj, a, b;
+{
+ bdb_DB *dbst;
+ VALUE ret;
+
+ GetDB(obj, dbst);
+ if (dbst->marshal) {
+ rb_raise(bdb_eFatal, "set_partial is not implemented with Marshal");
+ }
+ ret = rb_ary_new2(3);
+ rb_ary_push(ret, (dbst->partial == DB_DBT_PARTIAL)?Qtrue:Qfalse);
+ rb_ary_push(ret, INT2NUM(dbst->doff));
+ rb_ary_push(ret, INT2NUM(dbst->dlen));
+ dbst->doff = NUM2UINT(a);
+ dbst->dlen = NUM2UINT(b);
+ dbst->partial = DB_DBT_PARTIAL;
+ return ret;
+}
+
+static VALUE
+bdb_clear_partial(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ VALUE ret;
+
+ GetDB(obj, dbst);
+ if (dbst->marshal) {
+ rb_raise(bdb_eFatal, "set_partial is not implemented with Marshal");
+ }
+ ret = rb_ary_new2(3);
+ rb_ary_push(ret, (dbst->partial == DB_DBT_PARTIAL)?Qtrue:Qfalse);
+ rb_ary_push(ret, INT2NUM(dbst->doff));
+ rb_ary_push(ret, INT2NUM(dbst->dlen));
+ dbst->doff = dbst->dlen = dbst->partial = 0;
+ return ret;
+}
+
+#if BDB_VERSION >= 30000
+static VALUE
+bdb_i_create(obj)
+ VALUE obj;
+{
+ DB *dbp;
+ bdb_ENV *envst = 0;
+ DB_ENV *envp;
+ bdb_DB *dbst;
+ VALUE ret, env;
+
+ envp = NULL;
+ env = 0;
+ if (rb_obj_is_kind_of(obj, bdb_cEnv)) {
+ GetEnvDB(obj, envst);
+ envp = envst->envp;
+ env = obj;
+ }
+ bdb_test_error(db_create(&dbp, envp, 0));
+ dbp->set_errpfx(dbp, "BDB::");
+ dbp->set_errcall(dbp, bdb_env_errcall);
+ ret = Data_Make_Struct(bdb_cCommon, bdb_DB, bdb_mark, bdb_free, dbst);
+ rb_obj_call_init(ret, 0, 0);
+ dbst->env = env;
+ dbst->dbp = dbp;
+ if (envp) {
+ dbst->options |= envst->options & BDB_INIT_LOCK;
+ }
+ return ret;
+}
+#endif
+
+static VALUE
+bdb_s_upgrade(int argc, VALUE *argv, VALUE obj)
+{
+#if BDB_VERSION >= 30000
+ bdb_DB *dbst;
+ VALUE a, b;
+ int flags;
+ VALUE val;
+
+ rb_secure(4);
+ flags = 0;
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flags = NUM2INT(b);
+ }
+ SafeStringValue(a);
+ val = bdb_i_create(obj);
+ GetDB(val, dbst);
+ bdb_test_error(dbst->dbp->upgrade(dbst->dbp, StringValuePtr(a), flags));
+ return val;
+#else
+ rb_raise(bdb_eFatal, "You can't upgrade a database with this version of DB");
+#endif
+}
+
+static VALUE
+bdb_s_remove(int argc, VALUE *argv, VALUE obj)
+{
+#if BDB_VERSION >= 30000
+ bdb_DB *dbst;
+ VALUE a, b, c;
+ char *name, *subname;
+
+ rb_secure(2);
+ c = bdb_i_create(obj);
+ GetDB(c, dbst);
+ name = subname = NULL;
+ a = b = Qnil;
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ if (!NIL_P(b)) {
+ SafeStringValue(b);
+ subname = StringValuePtr(b);
+ }
+ }
+ SafeStringValue(a);
+ name = StringValuePtr(a);
+ bdb_test_error(dbst->dbp->remove(dbst->dbp, name, subname, 0));
+#else
+ rb_raise(bdb_eFatal, "You can't remove a database with this version of DB");
+#endif
+ return Qtrue;
+}
+
+static VALUE
+bdb_s_rename(int argc, VALUE *argv, VALUE obj)
+{
+#if BDB_VERSION >= 30114
+ bdb_DB *dbst;
+ VALUE a, b, c;
+ char *name, *subname, *newname;
+
+ rb_secure(2);
+ c = bdb_i_create(obj);
+ GetDB(c, dbst);
+ name = subname = NULL;
+ a = b = c = Qnil;
+ rb_scan_args(argc, argv, "30", &a, &b, &c);
+ if (!NIL_P(b)) {
+ SafeStringValue(b);
+ subname = StringValuePtr(b);
+ }
+ SafeStringValue(a);
+ SafeStringValue(c);
+ name = StringValuePtr(a);
+ newname = StringValuePtr(c);
+ bdb_test_error(dbst->dbp->rename(dbst->dbp, name, subname, newname, 0));
+#else
+ rb_raise(bdb_eFatal, "You can't rename a database with this version of DB");
+#endif
+ return Qtrue;
+}
+
+#if BDB_VERSION >= 20600
+
+static VALUE
+bdb_i_joinclose(st)
+ eachst *st;
+{
+ bdb_DB *dbst;
+
+ GetDB(st->db, dbst);
+ if (st->dbcp && dbst && dbst->dbp) {
+ st->dbcp->c_close(st->dbcp);
+ }
+ return Qnil;
+}
+
+
+static VALUE
+bdb_i_join(st)
+ eachst *st;
+{
+ int ret;
+ DBT key, data;
+ db_recno_t recno;
+ bdb_DB *dbst;
+
+ GetDB(st->db, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ SET_PARTIAL(dbst, data);
+ do {
+ ret = bdb_test_error(st->dbcp->c_get(st->dbcp, &key, &data, st->sens));
+ if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY)
+ return Qnil;
+ rb_yield(bdb_assoc(st->db, &key, &data));
+ } while (1);
+ return Qnil;
+}
+
+static VALUE
+bdb_join(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ bdb_DBC *dbcst;
+ DBC *dbc, **dbcarr;
+ int flags, i;
+ eachst st;
+ VALUE a, b, c;
+
+ c = 0;
+ flags = 0;
+ GetDB(obj, dbst);
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flags = NUM2INT(b);
+ }
+ if (TYPE(a) != T_ARRAY) {
+ rb_raise(bdb_eFatal, "first argument must an array of cursors");
+ }
+ if (RARRAY(a)->len == 0) {
+ rb_raise(bdb_eFatal, "empty array");
+ }
+ dbcarr = ALLOCA_N(DBC *, RARRAY(a)->len + 1);
+ {
+ DBC **dbs;
+ bdb_DB *tmp;
+
+ for (dbs = dbcarr, i = 0; i < RARRAY(a)->len; i++, dbs++) {
+ if (!rb_obj_is_kind_of(RARRAY(a)->ptr[i], bdb_cCursor)) {
+ rb_raise(bdb_eFatal, "element %d is not a cursor");
+ }
+ GetCursorDB(RARRAY(a)->ptr[i], dbcst, tmp);
+ *dbs = dbcst->dbc;
+ }
+ *dbs = 0;
+ }
+ dbc = 0;
+#if BDB_VERSION < 30000
+ bdb_test_error(dbst->dbp->join(dbst->dbp, dbcarr, 0, &dbc));
+#else
+ bdb_test_error(dbst->dbp->join(dbst->dbp, dbcarr, &dbc, 0));
+#endif
+ st.db = obj;
+ st.dbcp = dbc;
+ st.sens = flags | TEST_INIT_LOCK(dbst);
+ rb_ensure(bdb_i_join, (VALUE)&st, bdb_i_joinclose, (VALUE)&st);
+ return obj;
+}
+
+static VALUE
+bdb_byteswapp(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ int byteswap = 0;
+#if BDB_VERSION < 20500
+ rb_raise(bdb_eFatal, "byteswapped needs Berkeley DB 2.5 or later");
+#endif
+ GetDB(obj, dbst);
+#if BDB_VERSION < 30000
+ return dbst->dbp->byteswapped?Qtrue:Qfalse;
+#else
+#if BDB_VERSION < 30300
+ return dbst->dbp->get_byteswapped(dbst->dbp)?Qtrue:Qfalse;
+#else
+ dbst->dbp->get_byteswapped(dbst->dbp, &byteswap);
+ return byteswap?Qtrue:Qfalse;
+#endif
+#endif
+}
+
+#endif
+
+#if BDB_VERSION >= 30300
+
+static VALUE
+bdb_internal_second_call(tmp)
+ VALUE *tmp;
+{
+ return rb_funcall2(tmp[0], bdb_id_call, 3, tmp + 1);
+}
+
+static int
+bdb_call_secondary(secst, pkey, pdata, skey)
+ DB *secst;
+ DBT *pkey;
+ DBT *pdata;
+ DBT *skey;
+{
+ VALUE obj, ary, second;
+ bdb_DB *dbst, *secondst;
+ VALUE result = Qnil;
+ int i, inter;
+
+ GetIdDb(obj, dbst);
+ if (!dbst->dbp || !RTEST(dbst->secondary)) return DB_DONOTINDEX;
+ for (i = 0; i < RARRAY(dbst->secondary)->len; i++) {
+ ary = RARRAY(dbst->secondary)->ptr[i];
+ if (RARRAY(ary)->len != 2) continue;
+ second = RARRAY(ary)->ptr[0];
+ Data_Get_Struct(second, bdb_DB, secondst);
+ if (!secondst->dbp) continue;
+ if (secondst->dbp == secst) {
+ VALUE tmp[4];
+
+ tmp[0] = RARRAY(ary)->ptr[1];
+ tmp[1] = second;
+ tmp[2] = bdb_test_load_key(obj, pkey);
+ tmp[3] = bdb_test_load(obj, pdata, FILTER_VALUE|FILTER_FREE);
+ inter = 0;
+ result = rb_protect(bdb_internal_second_call, (VALUE)tmp, &inter);
+ if (inter) return BDB_ERROR_PRIVATE;
+ if (result == Qfalse) return DB_DONOTINDEX;
+ MEMZERO(skey, DBT, 1);
+ if (result == Qtrue) {
+ skey->data = pkey->data;
+ skey->size = pkey->size;
+ }
+ else {
+ DBT stmp;
+ MEMZERO(&stmp, DBT, 1);
+ result = bdb_test_dump(second, &stmp, result, FILTER_KEY);
+ skey->data = stmp.data;
+ skey->size = stmp.size;
+ }
+ return 0;
+ }
+ }
+ rb_gv_set("$!", rb_str_new2("secondary index not found ?"));
+ return BDB_ERROR_PRIVATE;
+}
+
+static VALUE
+bdb_associate(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst, *secondst;
+ VALUE second, flag;
+ int flags = 0;
+
+ if (!rb_block_given_p()) {
+ rb_raise(bdb_eFatal, "call out of an iterator");
+ }
+ if (rb_scan_args(argc, argv, "11", &second, &flag) == 2) {
+ flags = NUM2INT(flag);
+ }
+ if (!rb_obj_is_kind_of(second, bdb_cCommon)) {
+ rb_raise(bdb_eFatal, "associate expect a BDB object");
+ }
+ GetDB(second, secondst);
+ if (RTEST(secondst->secondary)) {
+ rb_raise(bdb_eFatal, "associate with a primary index");
+ }
+ GetDB(obj, dbst);
+
+ dbst->options |= BDB_NEED_CURRENT;
+ if (!dbst->secondary) {
+ dbst->secondary = rb_ary_new();
+ }
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_db, obj);
+#if RUBY_VERSION_CODE >= 180
+ rb_ary_push(dbst->secondary, rb_assoc_new(second, rb_block_proc()));
+#else
+ rb_ary_push(dbst->secondary, rb_assoc_new(second, rb_f_lambda()));
+#endif
+ secondst->secondary = Qnil;
+
+#if BDB_VERSION >= 40100
+ {
+ DB_TXN *txnid = NULL;
+ if (RTEST(dbst->txn)) {
+ bdb_TXN *txnst;
+
+ GetTxnDB(dbst->txn, txnst);
+ txnid = txnst->txnid;
+ }
+ else if (dbst->options & BDB_AUTO_COMMIT) {
+ flags |= DB_AUTO_COMMIT;
+ }
+ bdb_test_error(dbst->dbp->associate(dbst->dbp, txnid, secondst->dbp,
+ bdb_call_secondary, flags));
+ }
+#else
+ bdb_test_error(dbst->dbp->associate(dbst->dbp, secondst->dbp,
+ bdb_call_secondary, flags));
+#endif
+ return obj;
+}
+
+#endif
+
+static VALUE
+bdb_filename(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ GetDB(obj, dbst);
+ return dbst->filename;
+}
+
+static VALUE
+bdb_database(obj)
+ VALUE obj;
+{
+ bdb_DB *dbst;
+ GetDB(obj, dbst);
+ return dbst->database;
+}
+
+#if BDB_VERSION >= 30300
+static VALUE
+bdb_verify(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ char *file, *database;
+ VALUE flagv = Qnil, iov = Qnil;
+ int flags = 0;
+ OpenFile *fptr;
+ FILE *io = NULL;
+
+ rb_secure(4);
+ file = database = NULL;
+ switch(rb_scan_args(argc, argv, "02", &iov, &flagv)) {
+ case 2:
+ flags = NUM2INT(flagv);
+ case 1:
+ if (!NIL_P(iov)) {
+ iov = rb_convert_type(iov, T_FILE, "IO", "to_io");
+ GetOpenFile(iov, fptr);
+ rb_io_check_writable(fptr);
+ io = GetWriteFile(fptr);
+ }
+ break;
+ case 0:
+ break;
+ }
+ GetDB(obj, dbst);
+ if (!NIL_P(dbst->filename)) {
+ file = StringValuePtr(dbst->filename);
+ }
+ if (!NIL_P(dbst->database)) {
+ database = StringValuePtr(dbst->database);
+ }
+ bdb_test_error(dbst->dbp->verify(dbst->dbp, file, database, io, flags));
+ return Qnil;
+}
+#endif
+
+static VALUE
+bdb__txn__dup(VALUE obj, VALUE a)
+{
+ bdb_DB *dbp, *dbh;
+ bdb_TXN *txnst;
+ VALUE res;
+
+ GetDB(obj, dbp);
+ GetTxnDB(a, txnst);
+ res = Data_Make_Struct(CLASS_OF(obj), bdb_DB, bdb_mark, bdb_free, dbh);
+ MEMCPY(dbh, dbp, bdb_DB, 1);
+ dbh->txn = a;
+ dbh->orig = obj;
+ dbh->ori_val = res;
+ dbh->options |= (txnst->options & BDB_INIT_LOCK) | BDB_NOT_OPEN;
+ return res;
+}
+
+static VALUE
+bdb__txn__close(VALUE obj, VALUE commit, VALUE real)
+{
+ bdb_DB *dbst, *dbst1;
+
+ if (!real) {
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ dbst->dbp = NULL;
+ }
+ else {
+ if (commit) {
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ if (dbst->orig) {
+ Data_Get_Struct(dbst->orig, bdb_DB, dbst1);
+ dbst1->len = dbst->len;
+ }
+ }
+ bdb_close(0, 0, obj);
+ }
+ return Qnil;
+}
+
+#ifdef DB_PRIORITY_DEFAULT
+
+static VALUE
+bdb_cache_priority_set(VALUE obj, VALUE a)
+{
+ int priority;
+ bdb_DB *dbst;
+ GetDB(obj, dbst);
+ priority = dbst->priority;
+ bdb_test_error(dbst->dbp->set_cache_priority(dbst->dbp, NUM2INT(a)));
+ dbst->priority = NUM2INT(a);
+ return INT2FIX(priority);
+}
+
+static VALUE
+bdb_cache_priority_get(VALUE obj)
+{
+ bdb_DB *dbst;
+ GetDB(obj, dbst);
+ return INT2FIX(dbst->priority);
+}
+#endif
+
+#if BDB_VERSION >= 30000
+
+static VALUE
+bdb_feedback_set(VALUE obj, VALUE a)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (NIL_P(a)) {
+ dbst->feedback = a;
+ }
+ else {
+ if (!rb_respond_to(a, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ dbst->feedback = a;
+ if (!(dbst->options & BDB_FEEDBACK)) {
+ dbst->options |= BDB_FEEDBACK;
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_db, obj);
+ }
+ }
+ return a;
+}
+
+#endif
+
+#if BDB_VERSION >= 40250
+
+static VALUE
+bdb_i_conf(obj, a)
+ VALUE obj, a;
+{
+ bdb_DB *dbst;
+ u_int32_t bytes, gbytes, value;
+ int intval, ncache;
+ const char *str, *filename, *dbname, *strval;
+ VALUE res;
+
+ GetDB(obj, dbst);
+ str = StringValuePtr(a);
+ if (strcmp(str, "bt_minkey") == 0) {
+ bdb_test_error(dbst->dbp->get_bt_minkey(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "cachesize") == 0) {
+ bdb_test_error(dbst->dbp->get_cachesize(dbst->dbp, &gbytes, &bytes, &ncache));
+ res = rb_ary_new2(3);
+ rb_ary_push(res, INT2NUM(gbytes));
+ rb_ary_push(res, INT2NUM(bytes));
+ rb_ary_push(res, INT2NUM(ncache));
+ return res;
+ }
+ if (strcmp(str, "dbname") == 0) {
+ bdb_test_error(dbst->dbp->get_dbname(dbst->dbp, &filename, &dbname));
+ res = rb_ary_new2(3);
+ if (filename && strlen(filename)) {
+ rb_ary_push(res, rb_tainted_str_new2(filename));
+ }
+ else {
+ rb_ary_push(res, Qnil);
+ }
+ if (dbname && strlen(dbname)) {
+ rb_ary_push(res, rb_tainted_str_new2(dbname));
+ }
+ else {
+ rb_ary_push(res, Qnil);
+ }
+ return res;
+ }
+ if (strcmp(str, "env") == 0) {
+ return bdb_env(obj);
+ }
+ if (strcmp(str, "h_ffactor") == 0) {
+ bdb_test_error(dbst->dbp->get_h_ffactor(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "h_nelem") == 0) {
+ bdb_test_error(dbst->dbp->get_h_nelem(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "lorder") == 0) {
+ bdb_test_error(dbst->dbp->get_lorder(dbst->dbp, &intval));
+ return INT2NUM(intval);
+ }
+ if (strcmp(str, "pagesize") == 0) {
+ bdb_test_error(dbst->dbp->get_pagesize(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "q_extentsize") == 0) {
+ bdb_test_error(dbst->dbp->get_q_extentsize(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "re_delim") == 0) {
+ bdb_test_error(dbst->dbp->get_re_delim(dbst->dbp, &intval));
+ return INT2NUM(intval);
+ }
+ if (strcmp(str, "re_len") == 0) {
+ bdb_test_error(dbst->dbp->get_re_len(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "re_pad") == 0) {
+ bdb_test_error(dbst->dbp->get_re_pad(dbst->dbp, &intval));
+ return INT2NUM(intval);
+ }
+ if (strcmp(str, "re_source") == 0) {
+ bdb_test_error(dbst->dbp->get_re_source(dbst->dbp, &strval));
+ if (strval && strlen(strval)) {
+ return rb_tainted_str_new2(strval);
+ }
+ return Qnil;
+ }
+ if (strcmp(str, "flags") == 0) {
+ bdb_test_error(dbst->dbp->get_flags(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "open_flags") == 0) {
+ bdb_test_error(dbst->dbp->get_open_flags(dbst->dbp, &value));
+ return INT2NUM(value);
+ }
+ rb_raise(rb_eArgError, "Unknown option %s", str);
+ return obj;
+}
+
+static char *
+options[] = {
+ "bt_minkey", "cachesize", "dbname", "env", "h_ffactor", "h_nelem",
+ "lorder", "pagesize", "q_extentsize", "re_delim", "re_len", "re_pad",
+ "re_source", "flags", "open_flags", 0
+};
+
+struct optst {
+ VALUE obj, str;
+};
+
+static VALUE
+bdb_intern_conf(optp)
+ struct optst *optp;
+{
+ return bdb_i_conf(optp->obj, optp->str);
+}
+
+static VALUE
+bdb_conf(int argc, VALUE *argv, VALUE obj)
+{
+ int i, state;
+ VALUE res, val;
+ struct optst opt;
+
+ if (argc > 1) {
+ rb_raise(rb_eArgError, "invalid number of arguments (%d for 1)", argc);
+ }
+ if (argc == 1) {
+ return bdb_i_conf(obj, argv[0]);
+ }
+ res = rb_hash_new();
+ opt.obj = obj;
+ for (i = 0; options[i] != NULL; i++) {
+ opt.str = rb_str_new2(options[i]);
+ val = rb_protect(bdb_intern_conf, (VALUE)&opt, &state);
+ if (state == 0) {
+ rb_hash_aset(res, opt.str, val);
+ }
+ }
+ return res;
+}
+
+#endif
+
+void bdb_init_common()
+{
+ id_bt_compare = rb_intern("bdb_bt_compare");
+ id_bt_prefix = rb_intern("bdb_bt_prefix");
+ id_dup_compare = rb_intern("bdb_dup_compare");
+ id_h_hash = rb_intern("bdb_h_hash");
+#if BDB_VERSION >= 40100
+ id_append_recno = rb_intern("bdb_append_recno");
+#endif
+#if BDB_VERSION >= 30000
+ id_feedback = rb_intern("bdb_feedback");
+#endif
+ bdb_cCommon = rb_define_class_under(bdb_mDb, "Common", rb_cObject);
+ rb_define_private_method(bdb_cCommon, "initialize", bdb_init, -1);
+ rb_include_module(bdb_cCommon, rb_mEnumerable);
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ rb_define_alloc_func(bdb_cCommon, bdb_s_alloc);
+#else
+ rb_define_singleton_method(bdb_cCommon, "allocate", bdb_s_alloc, 0);
+#endif
+ rb_define_singleton_method(bdb_cCommon, "new", bdb_s_new, -1);
+ rb_define_singleton_method(bdb_cCommon, "create", bdb_s_new, -1);
+ rb_define_singleton_method(bdb_cCommon, "open", bdb_s_open, -1);
+ rb_define_singleton_method(bdb_cCommon, "[]", bdb_s_create, -1);
+ rb_define_singleton_method(bdb_cCommon, "remove", bdb_s_remove, -1);
+ rb_define_singleton_method(bdb_cCommon, "bdb_remove", bdb_s_remove, -1);
+ rb_define_singleton_method(bdb_cCommon, "unlink", bdb_s_remove, -1);
+ rb_define_singleton_method(bdb_cCommon, "upgrade", bdb_s_upgrade, -1);
+ rb_define_singleton_method(bdb_cCommon, "bdb_upgrade", bdb_s_upgrade, -1);
+ rb_define_singleton_method(bdb_cCommon, "rename", bdb_s_rename, -1);
+ rb_define_singleton_method(bdb_cCommon, "bdb_rename", bdb_s_rename, -1);
+ rb_define_private_method(bdb_cCommon, "__txn_close__", bdb__txn__close, 2);
+ rb_define_private_method(bdb_cCommon, "__txn_dup__", bdb__txn__dup, 1);
+ rb_define_method(bdb_cCommon, "filename", bdb_filename, 0);
+ rb_define_method(bdb_cCommon, "subname", bdb_database, 0);
+ rb_define_method(bdb_cCommon, "database", bdb_database, 0);
+#if BDB_VERSION >= 30300
+ rb_define_method(bdb_cCommon, "verify", bdb_verify, -1);
+#endif
+ rb_define_method(bdb_cCommon, "close", bdb_close, -1);
+ rb_define_method(bdb_cCommon, "db_close", bdb_close, -1);
+ rb_define_method(bdb_cCommon, "put", bdb_put, -1);
+ rb_define_method(bdb_cCommon, "db_put", bdb_put, -1);
+ rb_define_method(bdb_cCommon, "[]=", bdb_aset, 2);
+ rb_define_method(bdb_cCommon, "store", bdb_put, -1);
+ rb_define_method(bdb_cCommon, "env", bdb_env, 0);
+ rb_define_method(bdb_cCommon, "environment", bdb_env, 0);
+ rb_define_method(bdb_cCommon, "has_env?", bdb_env_p, 0);
+ rb_define_method(bdb_cCommon, "has_environment?", bdb_env_p, 0);
+ rb_define_method(bdb_cCommon, "env?", bdb_env_p, 0);
+ rb_define_method(bdb_cCommon, "environment?", bdb_env_p, 0);
+ rb_define_method(bdb_cCommon, "txn", bdb_txn, 0);
+ rb_define_method(bdb_cCommon, "transaction", bdb_txn, 0);
+ rb_define_method(bdb_cCommon, "txn?", bdb_txn_p, 0);
+ rb_define_method(bdb_cCommon, "transaction?", bdb_txn_p, 0);
+ rb_define_method(bdb_cCommon, "in_txn?", bdb_txn_p, 0);
+ rb_define_method(bdb_cCommon, "in_transaction?", bdb_txn_p, 0);
+#if BDB_VERSION >= 20600
+ rb_define_method(bdb_cCommon, "count", bdb_count, 1);
+ rb_define_method(bdb_cCommon, "dup_count", bdb_count, 1);
+ rb_define_method(bdb_cCommon, "each_dup", bdb_common_each_dup, -1);
+ rb_define_method(bdb_cCommon, "each_dup_value", bdb_common_each_dup_val, -1);
+ rb_define_method(bdb_cCommon, "dups", bdb_common_dups, -1);
+ rb_define_method(bdb_cCommon, "duplicates", bdb_common_dups, -1);
+ rb_define_method(bdb_cCommon, "get_dup", bdb_get_dup, -1);
+#endif
+ rb_define_method(bdb_cCommon, "get", bdb_get_dyna, -1);
+ rb_define_method(bdb_cCommon, "db_get", bdb_get_dyna, -1);
+ rb_define_method(bdb_cCommon, "[]", bdb_get_dyna, -1);
+#if BDB_VERSION >= 30300
+ rb_define_method(bdb_cCommon, "pget", bdb_pget, -1);
+ rb_define_method(bdb_cCommon, "primary_get", bdb_pget, -1);
+ rb_define_method(bdb_cCommon, "db_pget", bdb_pget, -1);
+#endif
+ rb_define_method(bdb_cCommon, "fetch", bdb_fetch, -1);
+ rb_define_method(bdb_cCommon, "delete", bdb_del, 1);
+ rb_define_method(bdb_cCommon, "del", bdb_del, 1);
+ rb_define_method(bdb_cCommon, "db_del", bdb_del, 1);
+ rb_define_method(bdb_cCommon, "sync", bdb_sync, 0);
+ rb_define_method(bdb_cCommon, "db_sync", bdb_sync, 0);
+ rb_define_method(bdb_cCommon, "flush", bdb_sync, 0);
+ rb_define_method(bdb_cCommon, "each", bdb_each_pair, -1);
+ rb_define_method(bdb_cCommon, "each_primary", bdb_each_pair_prim, -1);
+ rb_define_method(bdb_cCommon, "each_value", bdb_each_value, -1);
+ rb_define_method(bdb_cCommon, "reverse_each_value", bdb_each_eulav, -1);
+ rb_define_method(bdb_cCommon, "each_key", bdb_each_key, -1);
+ rb_define_method(bdb_cCommon, "reverse_each_key", bdb_each_yek, -1);
+ rb_define_method(bdb_cCommon, "each_pair", bdb_each_pair, -1);
+ rb_define_method(bdb_cCommon, "reverse_each", bdb_each_riap, -1);
+ rb_define_method(bdb_cCommon, "reverse_each_pair", bdb_each_riap, -1);
+ rb_define_method(bdb_cCommon, "reverse_each_primary", bdb_each_riap_prim, -1);
+ rb_define_method(bdb_cCommon, "keys", bdb_keys, 0);
+ rb_define_method(bdb_cCommon, "values", bdb_values, 0);
+ rb_define_method(bdb_cCommon, "delete_if", bdb_delete_if, -1);
+ rb_define_method(bdb_cCommon, "reject!", bdb_delete_if, -1);
+ rb_define_method(bdb_cCommon, "reject", bdb_reject, -1);
+ rb_define_method(bdb_cCommon, "clear", bdb_clear, -1);
+ rb_define_method(bdb_cCommon, "truncate", bdb_clear, -1);
+ rb_define_method(bdb_cCommon, "replace", bdb_replace, 1);
+ rb_define_method(bdb_cCommon, "update", bdb_update, 1);
+ rb_define_method(bdb_cCommon, "include?", bdb_has_key, 1);
+ rb_define_method(bdb_cCommon, "has_key?", bdb_has_key, 1);
+ rb_define_method(bdb_cCommon, "key?", bdb_has_key, 1);
+ rb_define_method(bdb_cCommon, "member?", bdb_has_key, 1);
+ rb_define_method(bdb_cCommon, "has_value?", bdb_has_value, 1);
+ rb_define_method(bdb_cCommon, "value?", bdb_has_value, 1);
+ rb_define_method(bdb_cCommon, "has_both?", bdb_has_both, 2);
+ rb_define_method(bdb_cCommon, "both?", bdb_has_both, 2);
+ rb_define_method(bdb_cCommon, "to_a", bdb_to_a, 0);
+ rb_define_method(bdb_cCommon, "to_hash", bdb_to_hash, 0);
+ rb_define_method(bdb_cCommon, "invert", bdb_invert, 0);
+ rb_define_method(bdb_cCommon, "empty?", bdb_empty, 0);
+ rb_define_method(bdb_cCommon, "length", bdb_length, 0);
+ rb_define_alias(bdb_cCommon, "size", "length");
+ rb_define_method(bdb_cCommon, "index", bdb_index, 1);
+ rb_define_method(bdb_cCommon, "indexes", bdb_indexes, -1);
+ rb_define_method(bdb_cCommon, "indices", bdb_indexes, -1);
+ rb_define_method(bdb_cCommon, "select", bdb_select, -1);
+ rb_define_method(bdb_cCommon, "values_at", bdb_values_at, -1);
+ rb_define_method(bdb_cCommon, "set_partial", bdb_set_partial, 2);
+ rb_define_method(bdb_cCommon, "clear_partial", bdb_clear_partial, 0);
+ rb_define_method(bdb_cCommon, "partial_clear", bdb_clear_partial, 0);
+#if BDB_VERSION >= 20600
+ rb_define_method(bdb_cCommon, "join", bdb_join, -1);
+ rb_define_method(bdb_cCommon, "byteswapped?", bdb_byteswapp, 0);
+ rb_define_method(bdb_cCommon, "get_byteswapped", bdb_byteswapp, 0);
+#endif
+#if BDB_VERSION >= 30300
+ rb_define_method(bdb_cCommon, "associate", bdb_associate, -1);
+#endif
+#ifdef DB_PRIORITY_DEFAULT
+ rb_define_method(bdb_cCommon, "cache_priority=", bdb_cache_priority_set, 1);
+ rb_define_method(bdb_cCommon, "cache_priority", bdb_cache_priority_get, 0);
+#endif
+#if BDB_VERSION >= 30000
+ rb_define_method(bdb_cCommon, "feedback=", bdb_feedback_set, 1);
+#endif
+ bdb_cBtree = rb_define_class_under(bdb_mDb, "Btree", bdb_cCommon);
+ rb_define_method(bdb_cBtree, "stat", bdb_tree_stat, -1);
+ rb_define_method(bdb_cBtree, "each_by_prefix", bdb_each_prefix, -1);
+ rb_define_method(bdb_cBtree, "reverse_each_by_prefix", bdb_each_xiferp, -1);
+#if BDB_VERSION >= 40416
+ rb_define_method(bdb_cBtree, "compact", bdb_treerec_compact, -1);
+#endif
+#if BDB_VERSION >= 30100
+ bdb_sKeyrange = rb_struct_define("Keyrange", "less", "equal", "greater", 0);
+ rb_global_variable(&bdb_sKeyrange);
+ rb_define_method(bdb_cBtree, "key_range", bdb_btree_key_range, 1);
+#endif
+ bdb_cHash = rb_define_class_under(bdb_mDb, "Hash", bdb_cCommon);
+#if BDB_VERSION >= 30000
+ rb_define_method(bdb_cHash, "stat", bdb_hash_stat, -1);
+#endif
+ bdb_cRecno = rb_define_class_under(bdb_mDb, "Recno", bdb_cCommon);
+ rb_define_method(bdb_cRecno, "each_index", bdb_each_key, -1);
+ rb_define_method(bdb_cRecno, "unshift", bdb_unshift, -1);
+ rb_define_method(bdb_cRecno, "<<", bdb_append, 1);
+ rb_define_method(bdb_cRecno, "push", bdb_append_m, -1);
+ rb_define_method(bdb_cRecno, "stat", bdb_tree_stat, -1);
+#if BDB_VERSION >= 40416
+ rb_define_method(bdb_cRecno, "compact", bdb_treerec_compact, -1);
+#endif
+#if BDB_VERSION >= 30000
+ bdb_cQueue = rb_define_class_under(bdb_mDb, "Queue", bdb_cCommon);
+ rb_define_singleton_method(bdb_cQueue, "new", bdb_queue_s_new, -1);
+ rb_define_singleton_method(bdb_cQueue, "create", bdb_queue_s_new, -1);
+ rb_define_method(bdb_cQueue, "each_index", bdb_each_key, -1);
+ rb_define_method(bdb_cQueue, "<<", bdb_append, 1);
+ rb_define_method(bdb_cQueue, "push", bdb_append_m, -1);
+ rb_define_method(bdb_cQueue, "shift", bdb_consume, 0);
+ rb_define_method(bdb_cQueue, "stat", bdb_queue_stat, -1);
+ rb_define_method(bdb_cQueue, "pad", bdb_queue_padlen, 0);
+#endif
+#if BDB_VERSION >= 40250
+ rb_define_method(bdb_cCommon, "configuration", bdb_conf, -1);
+ rb_define_method(bdb_cCommon, "conf", bdb_conf, -1);
+#endif
+ bdb_cUnknown = rb_define_class_under(bdb_mDb, "Unknown", bdb_cCommon);
+}
Added: packages/libdb4.3-ruby/branches/upstream/current/src/env.c
===================================================================
--- packages/libdb4.3-ruby/branches/upstream/current/src/env.c (rev 0)
+++ packages/libdb4.3-ruby/branches/upstream/current/src/env.c 2007-12-08 12:00:45 UTC (rev 2142)
@@ -0,0 +1,1806 @@
+#include "bdb.h"
+
+ID bdb_id_call;
+
+#if BDB_VERSION >= 30000
+static ID id_feedback;
+#endif
+
+ID bdb_id_current_env;
+static void bdb_env_mark _((bdb_ENV *));
+
+#define GetIdEnv(obj, envst) do { \
+ (obj) = rb_thread_local_aref(rb_thread_current(), bdb_id_current_env); \
+ if (TYPE(obj) != T_DATA || \
+ RDATA(obj)->dmark != (RUBY_DATA_FUNC)bdb_env_mark) { \
+ rb_raise(bdb_eFatal, "BUG : current_env not set"); \
+ } \
+ GetEnvDB(obj, envst); \
+} while (0)
+
+#if BDB_VERSION >= 40100
+static ID id_app_dispatch;
+#endif
+
+struct db_stoptions {
+ bdb_ENV *env;
+ VALUE config;
+ int lg_max, lg_bsize;
+};
+
+#if BDB_VERSION >= 40000
+#if BDB_VERSION >= 40200
+static int
+bdb_env_rep_transport(DB_ENV *env, const DBT *control, const DBT *rec,
+ const DB_LSN *lsn, int envid, u_int32_t flags)
+
+{
+ VALUE obj, av, bv, res;
+ bdb_ENV *envst;
+ struct dblsnst *lsnst;
+ VALUE lsnobj;
+
+ GetIdEnv(obj, envst);
+ lsnobj = bdb_makelsn(obj);
+ Data_Get_Struct(lsnobj, struct dblsnst, lsnst);
+ MEMCPY(lsnst->lsn, lsn, DB_LSN, 1);
+ av = rb_tainted_str_new(control->data, control->size);
+ bv = rb_tainted_str_new(rec->data, rec->size);
+ if (envst->rep_transport == 0) {
+ res = rb_funcall(obj, rb_intern("bdb_rep_transport"), 5, av, bv, lsnobj,
+ INT2FIX(envid), INT2FIX(flags));
+ }
+ else {
+ res = rb_funcall(envst->rep_transport, bdb_id_call, 4,
+ av, bv, lsnobj, INT2FIX(envid), INT2FIX(flags));
+ }
+ return NUM2INT(res);
+}
+#else
+static int
+bdb_env_rep_transport(DB_ENV *env, const DBT *control, const DBT *rec,
+ int envid, u_int32_t flags)
+{
+ VALUE obj, av, bv, res;
+ bdb_ENV *envst;
+
+ GetIdEnv(obj, envst);
+ av = rb_tainted_str_new(control->data, control->size);
+ bv = rb_tainted_str_new(rec->data, rec->size);
+ if (envst->rep_transport == 0) {
+ res = rb_funcall(obj, rb_intern("bdb_rep_transport"), 4, av, bv,
+ INT2FIX(envid), INT2FIX(flags));
+ }
+ else {
+ res = rb_funcall(envst->rep_transport, bdb_id_call, 4,
+ av, bv, INT2FIX(envid), INT2FIX(flags));
+ }
+ return NUM2INT(res);
+}
+#endif
+
+static VALUE
+bdb_env_rep_elect(int argc, VALUE *argv, VALUE env)
+{
+ VALUE nb, pri, ti, nvo;
+ bdb_ENV *envst;
+ int envid = 0, nvotes = 0;
+
+ GetEnvDB(env, envst);
+ if (rb_scan_args(argc, argv, "31", &nb, &pri, &ti, &nvo) == 4) {
+ nvotes = NUM2INT(nvo);
+ }
+
+#if BDB_VERSION >= 40300
+ bdb_test_error(envst->envp->rep_elect(envst->envp, NUM2INT(nb), nvotes,
+ NUM2INT(pri), NUM2INT(ti), &envid, 0));
+#else
+ bdb_test_error(envst->envp->rep_elect(envst->envp, NUM2INT(nb),
+ NUM2INT(pri), NUM2INT(ti), &envid));
+#endif
+ return INT2NUM(envid);
+}
+
+static VALUE
+bdb_env_rep_process_message(VALUE env, VALUE av, VALUE bv, VALUE ev)
+{
+ bdb_ENV *envst;
+ DBT control, rec;
+ int ret, envid;
+ VALUE result;
+#if BDB_VERSION >= 40200
+ VALUE lsn;
+ struct dblsnst *lsnst;
+#endif
+
+
+ GetEnvDB(env, envst);
+ av = rb_str_to_str(av);
+ bv = rb_str_to_str(bv);
+ MEMZERO(&control, DBT, 1);
+ MEMZERO(&rec, DBT, 1);
+ control.size = RSTRING(av)->len;
+ control.data = StringValuePtr(av);
+ rec.size = RSTRING(bv)->len;
+ rec.data = StringValuePtr(bv);
+ envid = NUM2INT(ev);
+#if BDB_VERSION >= 40200
+ lsn = bdb_makelsn(env);
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+
+ ret = envst->envp->rep_process_message(envst->envp, &control, &rec,
+ &envid, lsnst->lsn);
+#else
+ ret = envst->envp->rep_process_message(envst->envp, &control, &rec,
+ &envid);
+#endif
+ if (ret == DB_RUNRECOVERY) {
+ bdb_test_error(ret);
+ }
+ result = rb_ary_new();
+ rb_ary_push(result, INT2NUM(ret));
+ rb_ary_push(result, rb_str_new(rec.data, rec.size));
+ rb_ary_push(result, INT2NUM(envid));
+#if BDB_VERSION >= 42000
+ if (ret == DB_REP_NOTPERM || ret == DB_REP_ISPERM) {
+ rb_ary_push(result, lsn);
+ }
+#endif
+ return result;
+}
+
+static VALUE
+bdb_env_rep_start(VALUE env, VALUE ident, VALUE flags)
+{
+ bdb_ENV *envst;
+ DBT cdata;
+
+ GetEnvDB(env, envst);
+ if (!NIL_P(ident)) {
+ ident = rb_str_to_str(ident);
+ MEMZERO(&cdata, DBT, 1);
+ cdata.size = RSTRING(ident)->len;
+ cdata.data = StringValuePtr(ident);
+ }
+ bdb_test_error(envst->envp->rep_start(envst->envp,
+ NIL_P(ident)?NULL:&cdata,
+ NUM2INT(flags)));
+ return Qnil;
+}
+
+#if BDB_VERSION >= 40100
+
+static VALUE
+bdb_env_rep_limit(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_ENV *envst;
+ VALUE a, b;
+ u_int32_t gbytes, bytes;
+
+ GetEnvDB(obj, envst);
+ gbytes = bytes = 0;
+ switch(rb_scan_args(argc, argv, "11", &a, &b)) {
+ case 1:
+ if (TYPE(a) == T_ARRAY) {
+ if (RARRAY(a)->len != 2) {
+ rb_raise(bdb_eFatal, "Expected an Array with 2 values");
+ }
+ gbytes = NUM2UINT(RARRAY(a)->ptr[0]);
+ bytes = NUM2UINT(RARRAY(a)->ptr[1]);
+ }
+ else {
+ bytes = NUM2UINT(RARRAY(a)->ptr[1]);
+ }
+ break;
+ case 2:
+ gbytes = NUM2UINT(a);
+ bytes = NUM2UINT(b);
+ break;
+ }
+ bdb_test_error(envst->envp->set_rep_limit(envst->envp, gbytes, bytes));
+ return obj;
+}
+#endif
+
+#endif
+
+#if BDB_VERSION >= 30000
+static void
+bdb_env_feedback(DB_ENV *envp, int opcode, int pct)
+{
+ VALUE obj;
+ bdb_ENV *envst;
+
+ GetIdEnv(obj, envst);
+ if (NIL_P(envst->feedback)) {
+ return;
+ }
+ if (envst->feedback == 0) {
+ rb_funcall(obj, id_feedback, 2, INT2NUM(opcode), INT2NUM(pct));
+ }
+ else {
+ rb_funcall(envst->feedback, bdb_id_call, 2, INT2NUM(opcode), INT2NUM(pct));
+ }
+}
+
+#endif
+
+#if BDB_VERSION >= 40100
+
+static int
+bdb_env_app_dispatch(DB_ENV *envp, DBT *log_rec, DB_LSN *lsn, db_recops op)
+{
+ VALUE obj, lsnobj, logobj, res;
+ bdb_ENV *envst;
+ struct dblsnst *lsnst;
+
+ GetIdEnv(obj, envst);
+ lsnobj = bdb_makelsn(obj);
+ Data_Get_Struct(lsnobj, struct dblsnst, lsnst);
+ MEMCPY(lsnst->lsn, lsn, DB_LSN, 1);
+ logobj = rb_str_new(log_rec->data, log_rec->size);
+ if (envst->app_dispatch == 0) {
+ res = rb_funcall(obj, id_app_dispatch, 3, logobj, lsnobj, INT2NUM(op));
+ }
+ else {
+ res = rb_funcall(envst->app_dispatch, bdb_id_call, 3, logobj, lsnobj, INT2NUM(op));
+ }
+ return NUM2INT(res);
+}
+
+#endif
+
+#if BDB_VERSION >= 40416
+
+static ID id_msgcall;
+
+static void
+bdb_env_msgcall(const DB_ENV *dbenv, const char *msg)
+{
+ VALUE obj;
+ bdb_ENV *envst;
+
+ GetIdEnv(obj, envst);
+ if (NIL_P(envst->msgcall)) {
+ return;
+ }
+ if (envst->msgcall == 0) {
+ rb_funcall(obj, id_msgcall, 1, rb_tainted_str_new2(msg));
+ }
+ else {
+ rb_funcall(envst->msgcall, bdb_id_call, 1, rb_tainted_str_new2(msg));
+ }
+}
+
+static ID id_thread_id;
+
+static void
+bdb_env_thread_id(DB_ENV *dbenv, pid_t *pid, db_threadid_t *tid)
+{
+ VALUE obj;
+ bdb_ENV *envst;
+ VALUE res;
+
+ GetIdEnv(obj, envst);
+ if (NIL_P(envst->thread_id)) {
+ *pid = 0;
+ *tid = 0;
+ return;
+ }
+ if (envst->thread_id == 0) {
+ res = rb_funcall2(obj, id_thread_id, 0, 0);
+ }
+ else {
+ res = rb_funcall2(envst->thread_id, bdb_id_call, 0, 0);
+ }
+ res = rb_Array(res);
+ if (TYPE(res) != T_ARRAY || RARRAY(res)->len != 2) {
+ rb_raise(bdb_eFatal, "expected [pid, threadid]");
+ }
+ *pid = NUM2INT(RARRAY(res)->ptr[0]);
+ *tid = NUM2INT(RARRAY(res)->ptr[0]);
+ return;
+}
+
+static ID id_thread_id_string;
+
+static char *
+bdb_env_thread_id_string(DB_ENV *dbenv, pid_t pid, db_threadid_t tid, char *buf)
+{
+ VALUE obj;
+ bdb_ENV *envst;
+ VALUE res, a, b;
+
+ GetIdEnv(obj, envst);
+ if (NIL_P(envst->thread_id_string)) {
+ snprintf(buf, DB_THREADID_STRLEN, "%d/%d", pid, (int)tid);
+ return buf;
+ }
+ a = INT2NUM(pid);
+ b = INT2NUM(tid);
+ if (envst->thread_id_string == 0) {
+ res = rb_funcall(obj, id_thread_id_string, 2, a, b);
+ }
+ else {
+ res = rb_funcall(envst->thread_id_string, bdb_id_call, 2, a, b);
+ }
+ snprintf(buf, DB_THREADID_STRLEN, "%s", StringValuePtr(res));
+ return buf;
+}
+
+static ID id_isalive;
+
+static int
+bdb_env_isalive(DB_ENV *dbenv, pid_t pid, db_threadid_t tid)
+{
+ VALUE obj;
+ bdb_ENV *envst;
+ VALUE res, a ,b;
+
+ GetIdEnv(obj, envst);
+ if (NIL_P(envst->isalive)) {
+ return 0;
+ }
+ a = INT2NUM(pid);
+ b = INT2NUM(tid);
+ if (envst->isalive == 0) {
+ res = rb_funcall(obj, id_isalive, 2, INT2NUM(pid), INT2NUM(tid));
+ }
+ else {
+ res = rb_funcall(envst->isalive, bdb_id_call, 2, INT2NUM(pid), INT2NUM(tid));
+ }
+ if (RTEST(res)) {
+ return 1;
+ }
+ return 0;
+}
+
+
+#endif
+
+static VALUE
+bdb_env_i_options(VALUE obj, VALUE db_stobj)
+{
+ char *options;
+ DB_ENV *envp;
+ VALUE key, value;
+ bdb_ENV *envst;
+ struct db_stoptions *db_st;
+
+ Data_Get_Struct(db_stobj, struct db_stoptions, db_st);
+ envst = db_st->env;
+
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ envp = envst->envp;
+ key = rb_obj_as_string(key);
+ options = StringValuePtr(key);
+ if (strcmp(options, "set_cachesize") == 0) {
+ switch (TYPE(value)) {
+ case T_FIXNUM:
+ case T_FLOAT:
+ case T_BIGNUM:
+#if BDB_VERSION < 30000
+ envp->mp_size = NUM2INT(value);
+#else
+ bdb_test_error(envp->set_cachesize(envp, 0, NUM2UINT(value), 0));
+#endif
+ break;
+ default:
+ Check_Type(value, T_ARRAY);
+ if (RARRAY(value)->len < 3) {
+ rb_raise(bdb_eFatal, "expected 3 values for cachesize");
+ }
+#if BDB_VERSION < 30000
+ envp->mp_size = NUM2INT(RARRAY(value)->ptr[1]);
+#else
+ bdb_test_error(envp->set_cachesize(envp,
+ NUM2UINT(RARRAY(value)->ptr[0]),
+ NUM2UINT(RARRAY(value)->ptr[1]),
+ NUM2INT(RARRAY(value)->ptr[2])));
+#endif
+ break;
+ }
+ }
+#if DB_VERSION_MAJOR == 3
+ else if (strcmp(options, "set_region_init") == 0) {
+#if BDB_VERSION < 30114
+ bdb_test_error(envp->set_region_init(envp, NUM2INT(value)));
+#else
+ bdb_test_error(db_env_set_region_init(NUM2INT(value)));
+#endif
+ }
+#endif
+#if BDB_VERSION >= 30000
+ else if (strcmp(options, "set_tas_spins") == 0) {
+#if BDB_VERSION < 30114 || BDB_VERSION >= 40000
+#if BDB_VERSION >= 40416
+ rb_warning("Invalid option :set_tas_spins");
+#else
+ bdb_test_error(envp->set_tas_spins(envp, NUM2INT(value)));
+#endif
+#else
+ bdb_test_error(db_env_set_tas_spins(NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_tx_max") == 0) {
+ bdb_test_error(envp->set_tx_max(envp, NUM2INT(value)));
+ }
+#if BDB_VERSION >= 30100
+ else if (strcmp(options, "set_tx_timestamp") == 0) {
+ time_t ti;
+ value = rb_Integer(value);
+ ti = (time_t)NUM2INT(value);
+ bdb_test_error(envp->set_tx_timestamp(envp, &ti));
+ }
+#endif
+#endif
+#if BDB_VERSION < 30000
+ else if (strcmp(options, "set_verbose") == 0) {
+ envp->db_verbose = NUM2INT(value);
+ }
+#else
+#if BDB_VERSION < 40300
+ else if (strcmp(options, "set_verb_chkpoint") == 0) {
+ bdb_test_error(envp->set_verbose(envp, DB_VERB_CHKPOINT, NUM2INT(value)));
+ }
+#endif
+ else if (strcmp(options, "set_verb_deadlock") == 0) {
+ bdb_test_error(envp->set_verbose(envp, DB_VERB_DEADLOCK, NUM2INT(value)));
+ }
+ else if (strcmp(options, "set_verb_recovery") == 0) {
+ bdb_test_error(envp->set_verbose(envp, DB_VERB_RECOVERY, NUM2INT(value)));
+ }
+ else if (strcmp(options, "set_verb_waitsfor") == 0) {
+ bdb_test_error(envp->set_verbose(envp, DB_VERB_WAITSFOR, NUM2INT(value)));
+ }
+#if BDB_VERSION >= 40000
+ else if (strcmp(options, "set_verb_replication") == 0) {
+ bdb_test_error(envp->set_verbose(envp, DB_VERB_REPLICATION, NUM2INT(value)));
+ }
+#endif
+#endif
+ else if (strcmp(options, "set_lk_detect") == 0) {
+#if BDB_VERSION < 30000
+ envp->lk_detect = NUM2INT(value);
+#else
+ bdb_test_error(envp->set_lk_detect(envp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_lk_max") == 0) {
+#if BDB_VERSION < 30000
+ envp->lk_max = NUM2INT(value);
+#else
+ bdb_test_error(envp->set_lk_max(envp, NUM2INT(value)));
+#endif
+ }
+ else if (strcmp(options, "set_lk_conflicts") == 0) {
+ int i, j, l, v;
+ unsigned char *conflits, *p;
+
+ Check_Type(value, T_ARRAY);
+ l = RARRAY(value)->len;
+ p = conflits = ALLOC_N(unsigned char, l * l);
+ for (i = 0; i < l; i++) {
+ if (TYPE(RARRAY(value)->ptr[i]) != T_ARRAY ||
+ RARRAY(RARRAY(value)->ptr[i])->len != l) {
+ free(conflits);
+ rb_raise(bdb_eFatal, "invalid array for lk_conflicts");
+ }
+ for (j = 0; j < l; j++, p++) {
+ if (TYPE(RARRAY(RARRAY(value)->ptr[i])->ptr[j]) != T_FIXNUM) {
+ free(conflits);
+ rb_raise(bdb_eFatal, "invalid value for lk_conflicts");
+ }
+ v = NUM2INT(RARRAY(RARRAY(value)->ptr[i])->ptr[j]);
+ if (v != 0 && v != 1) {
+ free(conflits);
+ rb_raise(bdb_eFatal, "invalid value for lk_conflicts");
+ }
+ *p = (unsigned char)v;
+ }
+ }
+#if BDB_VERSION < 30000
+ envp->lk_modes = l;
+ envp->lk_conflicts = conflits;
+#else
+ bdb_test_error(envp->set_lk_conflicts(envp, conflits, l));
+#endif
+ }
+ else if (strcmp(options, "set_lg_max") == 0) {
+ db_st->lg_max = NUM2INT(value);
+ }
+#if BDB_VERSION >= 30000
+ else if (strcmp(options, "set_lg_bsize") == 0) {
+ db_st->lg_bsize = NUM2INT(value);
+ }
+#endif
+ else if (strcmp(options, "set_data_dir") == 0) {
+ SafeStringValue(value);
+#if BDB_VERSION >= 30100
+ bdb_test_error(envp->set_data_dir(envp, StringValuePtr(value)));
+#else
+ {
+ char *tmp;
+
+ tmp = ALLOCA_N(char, strlen("DB_DATA_DIR") + RSTRING(value)->len + 2);
+ sprintf(tmp, "DB_DATA_DIR %s", StringValuePtr(value));
+ rb_ary_push(db_st->config, rb_str_new2(tmp));
+ }
+#endif
+ }
+ else if (strcmp(options, "set_lg_dir") == 0) {
+ SafeStringValue(value);
+#if BDB_VERSION >= 30100
+ bdb_test_error(envp->set_lg_dir(envp, StringValuePtr(value)));
+#else
+ {
+ char *tmp;
+
+ tmp = ALLOCA_N(char, strlen("DB_LOG_DIR") + RSTRING(value)->len + 2);
+ sprintf(tmp, "DB_LOG_DIR %s", StringValuePtr(value));
+ rb_ary_push(db_st->config, rb_str_new2(tmp));
+ }
+#endif
+ }
+ else if (strcmp(options, "set_tmp_dir") == 0) {
+ SafeStringValue(value);
+#if BDB_VERSION >= 30100
+ bdb_test_error(envp->set_tmp_dir(envp, StringValuePtr(value)));
+#else
+ {
+ char *tmp;
+
+ tmp = ALLOCA_N(char, strlen("DB_TMP_DIR") + RSTRING(value)->len + 2);
+ sprintf(tmp, "DB_TMP_DIR %s", StringValuePtr(value));
+ rb_ary_push(db_st->config, rb_str_new2(tmp));
+ }
+#endif
+ }
+#if BDB_VERSION >= 30100
+ else if (strcmp(options, "set_server") == 0 ||
+ strcmp(options, "set_rpc_server") == 0) {
+ char *host;
+ long sv_timeout, cl_timeout;
+ unsigned long flags;
+
+ host = 0;
+ sv_timeout = cl_timeout = 0;
+ flags = 0;
+ switch (TYPE(value)) {
+ case T_STRING:
+ SafeStringValue(value);
+ host = StringValuePtr(value);
+ break;
+ case T_ARRAY:
+ switch (RARRAY(value)->len) {
+ default:
+ case 3:
+ sv_timeout = NUM2INT(RARRAY(value)->ptr[2]);
+ case 2:
+ cl_timeout = NUM2INT(RARRAY(value)->ptr[1]);
+ case 1:
+ SafeStringValue(RARRAY(value)->ptr[0]);
+ host = StringValuePtr(RARRAY(value)->ptr[0]);
+ break;
+ case 0:
+ rb_raise(bdb_eFatal, "Empty array for \"set_server\"");
+ break;
+ }
+ break;
+ default:
+ rb_raise(bdb_eFatal, "Invalid type for \"set_server\"");
+ break;
+ }
+#if BDB_VERSION >= 30300
+ bdb_test_error(envp->set_rpc_server(envp, NULL, host, cl_timeout, sv_timeout, flags));
+#else
+ bdb_test_error(envp->set_server(envp, host, cl_timeout, sv_timeout, flags));
+#endif
+ }
+#endif
+#if BDB_VERSION >= 30200
+ else if (strcmp(options, "set_flags") == 0) {
+ bdb_test_error(envp->set_flags(envp, NUM2UINT(value), 1));
+ }
+#endif
+ else if (strcmp(options, "marshal") == 0) {
+ switch (value) {
+ case Qtrue: envst->marshal = bdb_mMarshal; break;
+ case Qfalse: envst->marshal = Qfalse; break;
+ default:
+ if (!rb_respond_to(value, bdb_id_load) ||
+ !rb_respond_to(value, bdb_id_dump)) {
+ rb_raise(bdb_eFatal, "marshal value must be true or false");
+ }
+ envst->marshal = value;
+ break;
+ }
+ }
+ else if (strcmp(options, "thread") == 0) {
+ if (RTEST(value)) {
+ envst->options &= ~BDB_NO_THREAD;
+ }
+ else {
+ envst->options |= BDB_NO_THREAD;
+ }
+ }
+#if BDB_VERSION >= 40000
+ else if (strcmp(options, "set_rep_transport") == 0) {
+ if (TYPE(value) != T_ARRAY || RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "expected an Array of length 2 for set_rep_transport");
+ }
+ if (!FIXNUM_P(RARRAY(value)->ptr[0])) {
+ rb_raise(bdb_eFatal, "expected a Fixnum for the 1st arg of set_rep_transport");
+ }
+ if (!rb_respond_to(RARRAY(value)->ptr[1], bdb_id_call)) {
+ rb_raise(bdb_eFatal, "2nd arg must respond to #call");
+ }
+ envst->rep_transport = RARRAY(value)->ptr[1];
+ bdb_test_error(envst->envp->set_rep_transport(envst->envp, NUM2INT(RARRAY(value)->ptr[0]), bdb_env_rep_transport));
+ envst->options |= BDB_REP_TRANSPORT;
+ }
+ else if (strcmp(options, "set_timeout") == 0) {
+ if (TYPE(value) == T_ARRAY) {
+ if (RARRAY(value)->len >= 1 && !NIL_P(RARRAY(value)->ptr[0])) {
+
+ bdb_test_error(envst->envp->set_timeout(envst->envp,
+ NUM2UINT(RARRAY(value)->ptr[0]),
+ DB_SET_TXN_TIMEOUT));
+ }
+ if (RARRAY(value)->len == 2 && !NIL_P(RARRAY(value)->ptr[1])) {
+ bdb_test_error(envst->envp->set_timeout(envst->envp,
+ NUM2UINT(RARRAY(value)->ptr[0]),
+ DB_SET_LOCK_TIMEOUT));
+ }
+ }
+ else {
+ bdb_test_error(envst->envp->set_timeout(envst->envp,
+ NUM2UINT(value),
+ DB_SET_TXN_TIMEOUT));
+ }
+ }
+ else if (strcmp(options, "set_txn_timeout") == 0) {
+ bdb_test_error(envst->envp->set_timeout(envst->envp,
+ NUM2UINT(value),
+ DB_SET_TXN_TIMEOUT));
+ }
+ else if (strcmp(options, "set_lock_timeout") == 0) {
+ bdb_test_error(envst->envp->set_timeout(envst->envp,
+ NUM2UINT(value),
+ DB_SET_LOCK_TIMEOUT));
+ }
+#endif
+#if BDB_VERSION >= 40100
+ else if (strcmp(options, "set_encrypt") == 0) {
+ char *passwd;
+ int flags = DB_ENCRYPT_AES;
+ if (TYPE(value) == T_ARRAY) {
+ if (RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "Expected an Array with 2 values");
+ }
+ passwd = StringValuePtr(RARRAY(value)->ptr[0]);
+ flags = NUM2INT(RARRAY(value)->ptr[1]);
+ }
+ else {
+ passwd = StringValuePtr(value);
+ }
+ bdb_test_error(envst->envp->set_encrypt(envst->envp, passwd, flags));
+ envst->options |= BDB_ENV_ENCRYPT;
+ }
+ else if (strcmp(options, "set_rep_limit") == 0) {
+ u_int32_t gbytes, bytes;
+ gbytes = bytes = 0;
+ if (TYPE(value) == T_ARRAY) {
+ if (RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "Expected an Array with 2 values");
+ }
+ gbytes = NUM2UINT(RARRAY(value)->ptr[0]);
+ bytes = NUM2UINT(RARRAY(value)->ptr[1]);
+ }
+ else {
+ bytes = NUM2UINT(RARRAY(value)->ptr[1]);
+ }
+ bdb_test_error(envst->envp->set_rep_limit(envst->envp, gbytes, bytes));
+ }
+#endif
+#if BDB_VERSION >= 30000
+ else if (strcmp(options, "set_feedback") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->options |= BDB_FEEDBACK;
+ envst->feedback = value;
+ envst->envp->set_feedback(envst->envp, bdb_env_feedback);
+ }
+#endif
+#if BDB_VERSION >= 40100
+ else if (strcmp(options, "set_app_dispatch") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->options |= BDB_APP_DISPATCH;
+ envst->app_dispatch = value;
+ envst->envp->set_app_dispatch(envst->envp, bdb_env_app_dispatch);
+ }
+#endif
+#if BDB_VERSION >= 40416
+ else if (strcmp(options, "set_msgcall") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->msgcall = value;
+ envst->envp->set_msgcall(envst->envp, bdb_env_msgcall);
+ }
+ else if (strcmp(options, "set_thread_id") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->thread_id = value;
+ envst->envp->set_thread_id(envst->envp, bdb_env_thread_id);
+ }
+ else if (strcmp(options, "set_thread_id_string") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->thread_id_string = value;
+ envst->envp->set_thread_id_string(envst->envp, bdb_env_thread_id_string);
+ }
+ else if (strcmp(options, "set_isalive") == 0) {
+ if (!rb_respond_to(value, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->isalive = value;
+ envst->envp->set_isalive(envst->envp, bdb_env_isalive);
+ }
+#endif
+#if BDB_VERSION >= 40250
+ else if (strcmp(options, "set_shm_key") == 0) {
+ bdb_test_error(envst->envp->set_shm_key(envst->envp, NUM2INT(value)));
+ }
+#endif
+ return Qnil;
+}
+
+struct env_iv {
+ bdb_ENV *envst;
+ VALUE env;
+};
+
+#if BDB_VERSION >= 30000
+
+static VALUE
+bdb_env_aref()
+{
+ VALUE obj;
+ bdb_ENV *envst;
+
+ GetIdEnv(obj, envst);
+ return obj;
+}
+
+#endif
+
+VALUE
+bdb_protect_close(VALUE obj)
+{
+ return rb_funcall2(obj, rb_intern("close"), 0, 0);
+}
+
+static void
+bdb_final(bdb_ENV *envst)
+{
+ VALUE obj, *ary;
+ bdb_ENV *thst;
+ int i;
+
+ ary = envst->db_ary.ptr;
+ if (ary) {
+ envst->db_ary.mark = Qtrue;
+ for (i = 0; i < envst->db_ary.len; i++) {
+ if (rb_respond_to(ary[i], rb_intern("close"))) {
+ rb_protect(bdb_protect_close, ary[i], 0);
+ }
+ }
+ envst->db_ary.mark = Qfalse;
+ envst->db_ary.total = envst->db_ary.len = 0;
+ envst->db_ary.ptr = 0;
+ free(ary);
+ }
+ if (envst->envp) {
+ if (!(envst->options & BDB_ENV_NOT_OPEN)) {
+#if BDB_VERSION < 30000
+ db_appexit(envst->envp);
+ free(envst->envp);
+#else
+ envst->envp->close(envst->envp, 0);
+#endif
+ }
+ envst->envp = NULL;
+ }
+#if BDB_VERSION >= 30000
+ {
+ int status;
+
+ obj = rb_protect(bdb_env_aref, 0, &status);
+ if (!status) {
+ Data_Get_Struct(obj, bdb_ENV, thst);
+ if (thst == envst) {
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_env, Qnil);
+ }
+ }
+ }
+#endif
+}
+
+static void
+bdb_env_free(bdb_ENV *envst)
+{
+ bdb_final(envst);
+ free(envst);
+}
+
+static VALUE
+bdb_env_close(VALUE obj)
+{
+ bdb_ENV *envst;
+
+ if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4) {
+ rb_raise(rb_eSecurityError, "Insecure: can't close the environnement");
+ }
+ GetEnvDB(obj, envst);
+ bdb_final(envst);
+ RDATA(obj)->dfree = free;
+ return Qnil;
+}
+
+static void
+bdb_env_mark(bdb_ENV *envst)
+{
+ rb_gc_mark(envst->marshal);
+#if BDB_VERSION >= 40000
+ rb_gc_mark(envst->rep_transport);
+#if BDB_VERSION >= 40100
+ rb_gc_mark(envst->app_dispatch);
+#endif
+#endif
+#if BDB_VERSION >= 40416
+ rb_gc_mark(envst->msgcall);
+ rb_gc_mark(envst->thread_id);
+ rb_gc_mark(envst->thread_id_string);
+ rb_gc_mark(envst->isalive);
+#endif
+#if BDB_VERSION >= 30000
+ rb_gc_mark(envst->feedback);
+#endif
+ rb_gc_mark(envst->home);
+ bdb_ary_mark(&envst->db_ary);
+}
+
+VALUE
+bdb_env_open_db(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE cl;
+
+ if (argc < 1)
+ rb_raise(bdb_eFatal, "Invalid number of arguments");
+ cl = argv[0];
+ if (FIXNUM_P(cl)) {
+ switch (NUM2INT(cl)) {
+ case DB_BTREE: cl = bdb_cBtree; break;
+ case DB_HASH: cl = bdb_cHash; break;
+ case DB_RECNO: cl = bdb_cRecno; break;
+#if BDB_VERSION >= 30000
+ case DB_QUEUE: cl = bdb_cQueue; break;
+#endif
+ case DB_UNKNOWN: cl = bdb_cUnknown; break;
+ default: rb_raise(bdb_eFatal, "Unknown database type");
+ }
+ }
+ else if (TYPE(cl) != T_CLASS) {
+ cl = CLASS_OF(cl);
+ }
+ MEMCPY(argv, argv + 1, VALUE, argc - 1);
+ if (argc > 1 && TYPE(argv[argc - 2]) == T_HASH) {
+ argc--;
+ }
+ else {
+ argv[argc - 1] = rb_hash_new();
+ }
+ if (rb_obj_is_kind_of(obj, bdb_cEnv)) {
+ rb_hash_aset(argv[argc - 1], rb_tainted_str_new2("env"), obj);
+ }
+ else {
+ rb_hash_aset(argv[argc - 1], rb_tainted_str_new2("txn"), obj);
+ }
+ return rb_funcall2(cl, rb_intern("new"), argc, argv);
+}
+
+#if BDB_VERSION >= 40300
+void
+bdb_env_errcall(const DB_ENV *env, const char *errpfx, const char *msg)
+{
+ bdb_errcall = 1;
+ bdb_errstr = rb_tainted_str_new2(msg);
+}
+
+#else
+
+void
+bdb_env_errcall(const char *errpfx, char *msg)
+{
+ bdb_errcall = 1;
+ bdb_errstr = rb_tainted_str_new2(msg);
+}
+
+#endif
+
+VALUE
+bdb_return_err()
+{
+ if (bdb_errcall) {
+ bdb_errcall = 0;
+ return bdb_errstr;
+ }
+ return Qnil;
+}
+
+#ifndef NT
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#endif /* HAVE_SYS_TIME_H */
+#endif /* NT */
+
+static int
+bdb_func_sleep(unsigned long sec, unsigned long usec)
+{
+ struct timeval timeout;
+ timeout.tv_sec = sec;
+ timeout.tv_usec = usec;
+ rb_thread_wait_for(timeout);
+ return 0;
+}
+
+static int
+bdb_func_yield()
+{
+ rb_thread_schedule();
+ return 0;
+}
+
+static void *
+bdb_func_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+static VALUE
+bdb_set_func(bdb_ENV *envst)
+{
+#if BDB_VERSION >= 30000
+#if BDB_VERSION < 30114
+ bdb_test_error(envst->envp->set_func_sleep(envst->envp, bdb_func_sleep));
+ bdb_test_error(envst->envp->set_func_yield(envst->envp, bdb_func_yield));
+#else
+ bdb_test_error(db_env_set_func_sleep(bdb_func_sleep));
+ bdb_test_error(db_env_set_func_yield(bdb_func_yield));
+#endif
+#else
+ bdb_test_error(db_jump_set((void *)bdb_func_sleep, DB_FUNC_SLEEP));
+ bdb_test_error(db_jump_set((void *)bdb_func_yield, DB_FUNC_YIELD));
+#endif
+ return Qtrue;
+}
+
+static VALUE
+bdb_env_each_options(VALUE opt, VALUE stobj)
+{
+ VALUE res;
+ DB_ENV *envp;
+ struct db_stoptions *db_st;
+
+ res = rb_iterate(rb_each, opt, bdb_env_i_options, stobj);
+ Data_Get_Struct(stobj, struct db_stoptions, db_st);
+ envp = db_st->env->envp;
+#if BDB_VERSION >= 30000
+ if (db_st->lg_bsize) {
+ bdb_test_error(envp->set_lg_bsize(envp, db_st->lg_bsize));
+ }
+#endif
+ if (db_st->lg_max) {
+#if BDB_VERSION < 30000
+ envp->lg_max = db_st->lg_max;
+#else
+ bdb_test_error(envp->set_lg_max(envp, db_st->lg_max));
+#endif
+ }
+ return res;
+}
+
+static VALUE
+bdb_env_s_i_options(VALUE obj, int *flags)
+{
+ char *options;
+ VALUE key, value;
+
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ key = rb_obj_as_string(key);
+ options = StringValuePtr(key);
+ if (strcmp(options, "env_flags") == 0) {
+ *flags = NUM2INT(value);
+ }
+#ifdef DB_CLIENT
+ else if (strcmp(options, "set_rpc_server") == 0 ||
+ strcmp(options, "set_server") == 0) {
+ *flags |= DB_CLIENT;
+ }
+#endif
+ return Qnil;
+}
+
+static VALUE
+bdb_env_s_alloc(VALUE obj)
+{
+ VALUE res;
+ bdb_ENV *envst;
+
+ res = Data_Make_Struct(obj, bdb_ENV, bdb_env_mark, bdb_env_free, envst);
+ envst->options |= BDB_ENV_NOT_OPEN;
+ return res;
+}
+
+static VALUE
+bdb_env_s_new(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_ENV *envst;
+ VALUE res;
+ int flags = 0;
+
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ res = rb_obj_alloc(obj);
+#else
+ res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
+#endif
+ Data_Get_Struct(res, bdb_ENV, envst);
+#if BDB_VERSION < 30000
+ envst->envp = ALLOC(DB_ENV);
+ MEMZERO(envst->envp, DB_ENV, 1);
+ envst->envp->db_errpfx = "BDB::";
+ envst->envp->db_errcall = bdb_env_errcall;
+#else
+#if BDB_VERSION >= 30100
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ rb_iterate(rb_each, argv[argc - 1], bdb_env_s_i_options, (VALUE)&flags);
+ }
+#endif
+ bdb_test_error(db_env_create(&(envst->envp), flags));
+ envst->envp->set_errpfx(envst->envp, "BDB::");
+ envst->envp->set_errcall(envst->envp, bdb_env_errcall);
+#if BDB_VERSION >= 30300
+ bdb_test_error(envst->envp->set_alloc(envst->envp, malloc, realloc, free));
+#endif
+#endif
+ rb_obj_call_init(res, argc, argv);
+ return res;
+}
+
+
+#if BDB_VERSION >= 40000
+
+VALUE
+bdb_env_s_rslbl(int argc, VALUE *argv, VALUE obj, DB_ENV *env)
+{
+ bdb_ENV *envst;
+ VALUE res;
+
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ res = rb_obj_alloc(obj);
+#else
+ res = rb_funcall2(obj, rb_intern("allocate"), 0, 0);
+#endif
+ Data_Get_Struct(res, bdb_ENV, envst);
+ envst->envp = env;
+ envst->envp->set_errpfx(envst->envp, "BDB::");
+ envst->envp->set_errcall(envst->envp, bdb_env_errcall);
+ bdb_test_error(envst->envp->set_alloc(envst->envp, malloc, realloc, free));
+ rb_obj_call_init(res, argc, argv);
+ return res;
+}
+
+#endif
+
+VALUE
+bdb_env_init(int argc, VALUE *argv, VALUE obj)
+{
+ DB_ENV *envp;
+ bdb_ENV *envst;
+ VALUE a, c, d;
+ char *db_home, **db_config;
+ int ret, mode, flags;
+ VALUE st_config;
+ VALUE envid;
+
+ envid = 0;
+ st_config = 0;
+ db_config = 0;
+ mode = flags = 0;
+ if (!RDATA(obj)->dmark) {
+ RDATA(obj)->dmark = (RUBY_DATA_FUNC)bdb_env_mark;
+ }
+ Data_Get_Struct(obj, bdb_ENV, envst);
+#if BDB_VERSION >= 30000
+ envst->envp->set_errcall(envst->envp, bdb_env_errcall);
+#endif
+ envp = envst->envp;
+#if BDB_VERSION >= 40100
+ if (rb_const_defined(CLASS_OF(obj), rb_intern("BDB_ENCRYPT"))) {
+ char *passwd;
+ int flags = DB_ENCRYPT_AES;
+ VALUE value = rb_const_get(CLASS_OF(obj), rb_intern("BDB_ENCRYPT"));
+ if (TYPE(value) == T_ARRAY) {
+ if (RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "Expected an Array with 2 values");
+ }
+ passwd = StringValuePtr(RARRAY(value)->ptr[0]);
+ flags = NUM2INT(RARRAY(value)->ptr[1]);
+ }
+ else {
+ passwd = StringValuePtr(value);
+ }
+ bdb_test_error(envp->set_encrypt(envp, passwd, flags));
+ envst->options |= BDB_ENV_ENCRYPT;
+ }
+#endif
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ int i;
+ VALUE db_stobj;
+ struct db_stoptions *db_st;
+
+ st_config = rb_ary_new();
+ db_stobj = Data_Make_Struct(rb_cObject, struct db_stoptions, 0, free, db_st);
+ db_st->env = envst;
+ db_st->config = st_config;
+ bdb_env_each_options(argv[argc - 1], db_stobj);
+ if (RARRAY(st_config)->len > 0) {
+ db_config = ALLOCA_N(char *, RARRAY(st_config)->len + 1);
+ for (i = 0; i < RARRAY(st_config)->len; i++) {
+ db_config[i] = StringValuePtr(RARRAY(st_config)->ptr[i]);
+ }
+ db_config[RARRAY(st_config)->len] = 0;
+ }
+ argc--;
+ }
+ rb_scan_args(argc, argv, "12", &a, &c, &d);
+ SafeStringValue(a);
+ db_home = StringValuePtr(a);
+ switch (argc) {
+ case 3:
+ mode = NUM2INT(d);
+ case 2:
+ flags = NUM2INT(c);
+ break;
+ }
+ if (flags & DB_CREATE) {
+ rb_secure(4);
+ }
+ if (flags & DB_USE_ENVIRON) {
+ rb_secure(1);
+ }
+#ifndef BDB_NO_THREAD_COMPILE
+ if (!(envst->options & BDB_NO_THREAD)) {
+ bdb_set_func(envst);
+ flags |= DB_THREAD;
+ }
+#endif
+#if BDB_VERSION < 30000
+ if ((ret = db_appinit(db_home, db_config, envp, flags)) != 0) {
+ if (envst->envp) {
+ free(envst->envp);
+ }
+ envst->envp = NULL;
+ if (bdb_errcall) {
+ bdb_errcall = 0;
+ rb_raise(bdb_eFatal, "%s -- %s", StringValuePtr(bdb_errstr), db_strerror(ret));
+ }
+ else
+ rb_raise(bdb_eFatal, "%s", db_strerror(ret));
+ }
+#else
+#if BDB_VERSION >= 40000
+ if (envst->rep_transport == 0 && rb_respond_to(obj, rb_intern("bdb_rep_transport")) == Qtrue) {
+ if (!rb_const_defined(CLASS_OF(obj), rb_intern("ENVID"))) {
+ rb_raise(bdb_eFatal, "ENVID must be defined to use rep_transport");
+ }
+ envid = rb_const_get(CLASS_OF(obj), rb_intern("ENVID"));
+ bdb_test_error(envp->set_rep_transport(envp, NUM2INT(envid),
+ bdb_env_rep_transport));
+ envst->options |= BDB_REP_TRANSPORT;
+ }
+#endif
+#if BDB_VERSION >= 30000
+ if (envst->feedback == 0 && rb_respond_to(obj, id_feedback) == Qtrue) {
+ envp->set_feedback(envp, bdb_env_feedback);
+ envst->options |= BDB_FEEDBACK;
+ }
+#endif
+#if BDB_VERSION >= 40100
+ if (envst->app_dispatch == 0 && rb_respond_to(obj, id_app_dispatch) == Qtrue) {
+ envp->set_app_dispatch(envp, bdb_env_app_dispatch);
+ envst->options |= BDB_APP_DISPATCH;
+ }
+#endif
+#if BDB_VERSION >= 40416
+ if (envst->msgcall == 0 && rb_respond_to(obj, id_msgcall) == Qtrue) {
+ envp->set_msgcall(envp, bdb_env_msgcall);
+ }
+ if (envst->thread_id == 0 && rb_respond_to(obj, id_thread_id) == Qtrue) {
+ envp->set_thread_id(envp, bdb_env_thread_id);
+ }
+ if (envst->thread_id_string == 0 && rb_respond_to(obj, id_thread_id_string) == Qtrue) {
+ envp->set_thread_id_string(envp, bdb_env_thread_id_string);
+ }
+ if (envst->isalive == 0 && rb_respond_to(obj, id_isalive) == Qtrue) {
+ envp->set_isalive(envp, bdb_env_isalive);
+ }
+#endif
+#if BDB_VERSION >= 30100
+ if ((ret = envp->open(envp, db_home, flags, mode)) != 0)
+#else
+ if ((ret = envp->open(envp, db_home, db_config, flags, mode)) != 0)
+#endif
+ {
+ envp->close(envp, 0);
+ envst->envp = NULL;
+ if (bdb_errcall) {
+ bdb_errcall = 0;
+ rb_raise(bdb_eFatal, "%s -- %s", StringValuePtr(bdb_errstr), db_strerror(ret));
+ }
+ else
+ rb_raise(bdb_eFatal, "%s", db_strerror(ret));
+ }
+#endif
+ envst->options &= ~BDB_ENV_NOT_OPEN;
+ if (flags & DB_INIT_LOCK) {
+ envst->options |= BDB_INIT_LOCK;
+ }
+ if (flags & DB_INIT_TXN) {
+ envst->options |= BDB_AUTO_COMMIT;
+ }
+ envst->home = rb_tainted_str_new2(db_home);
+ OBJ_FREEZE(envst->home);
+#if BDB_VERSION >= 30000
+ if (envst->options & BDB_NEED_ENV_CURRENT) {
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_env, obj);
+ }
+#endif
+ return obj;
+}
+
+static VALUE
+bdb_env_internal_close(VALUE obj)
+{
+ return rb_funcall2(obj, rb_intern("close"), 0, 0);
+}
+
+static VALUE
+bdb_env_s_open(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE res = rb_funcall2(obj, rb_intern("new"), argc, argv);
+ if (rb_block_given_p()) {
+ return rb_ensure(rb_yield, res, bdb_env_internal_close, res);
+ }
+ return res;
+}
+
+static VALUE
+bdb_env_s_remove(int argc, VALUE *argv, VALUE obj)
+{
+ DB_ENV *envp;
+ VALUE a, b;
+ char *db_home;
+ int flag = 0;
+
+ rb_secure(2);
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flag = NUM2INT(b);
+ }
+ db_home = StringValuePtr(a);
+#if BDB_VERSION < 30000
+ envp = ALLOCA_N(DB_ENV, 1);
+ MEMZERO(envp, DB_ENV, 1);
+ envp->db_errpfx = "BDB::";
+ envp->db_errcall = bdb_env_errcall;
+ if (lock_unlink(db_home, flag, envp) == EBUSY) {
+ rb_raise(bdb_eFatal, "The shared memory region was in use");
+ }
+ if (log_unlink(db_home, flag, envp) == EBUSY) {
+ rb_raise(bdb_eFatal, "The shared memory region was in use");
+ }
+ if (memp_unlink(db_home, flag, envp) == EBUSY) {
+ rb_raise(bdb_eFatal, "The shared memory region was in use");
+ }
+ if (txn_unlink(db_home, flag, envp) == EBUSY) {
+ rb_raise(bdb_eFatal, "The shared memory region was in use");
+ }
+#else
+ bdb_test_error(db_env_create(&envp, 0));
+ envp->set_errpfx(envp, "BDB::");
+ envp->set_errcall(envp, bdb_env_errcall);
+#if BDB_VERSION < 30100
+ bdb_test_error(envp->remove(envp, db_home, NULL, flag));
+#else
+ bdb_test_error(envp->remove(envp, db_home, flag));
+#endif
+#endif
+ return Qtrue;
+}
+
+static VALUE
+bdb_env_set_flags(int argc, VALUE *argv, VALUE obj)
+{
+#if BDB_VERSION >= 30200
+ bdb_ENV *envst;
+ VALUE opt, flag;
+ int state = 1;
+
+ GetEnvDB(obj, envst);
+ if (rb_scan_args(argc, argv, "11", &flag, &opt)) {
+ switch (TYPE(opt)) {
+ case T_TRUE:
+ state = 1;
+ break;
+ case T_FALSE:
+ state = 0;
+ break;
+ case T_FIXNUM:
+ state = NUM2INT(opt);
+ break;
+ default:
+ rb_raise(bdb_eFatal, "invalid value for onoff");
+ }
+ }
+ bdb_test_error(envst->envp->set_flags(envst->envp, NUM2INT(flag), state));
+#endif
+ return Qnil;
+}
+
+static VALUE
+bdb_env_home(VALUE obj)
+{
+ bdb_ENV *envst;
+ GetEnvDB(obj, envst);
+ return envst->home;
+}
+
+#if BDB_VERSION >= 40000
+
+static VALUE
+bdb_env_iterate(VALUE *tmp)
+{
+ return rb_funcall2(tmp[0], rb_intern("__bdb_thread_init__"),
+ (int)tmp[1], (VALUE *)tmp[2]);
+}
+
+static VALUE
+bdb_thread_init(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE env;
+
+ if ((env = rb_thread_local_aref(rb_thread_current(), bdb_id_current_env)) != Qnil) {
+ rb_thread_local_aset(obj, bdb_id_current_env, env);
+ }
+ if (rb_block_given_p()) {
+ VALUE tmp[3];
+ tmp[0] = obj;
+ tmp[1] = (VALUE)argc;
+ tmp[2] = (VALUE)argv;
+ return rb_iterate((VALUE (*)(VALUE))bdb_env_iterate, (VALUE)tmp, rb_yield, obj);
+ }
+ return rb_funcall2(obj, rb_intern("__bdb_thread_init__"), argc, argv);
+}
+
+#endif
+
+#if BDB_VERSION >= 30000
+
+static VALUE
+bdb_env_feedback_set(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ if (NIL_P(a)) {
+ envst->feedback = a;
+ }
+ else {
+ if (!rb_respond_to(a, bdb_id_call)) {
+ rb_raise(bdb_eFatal, "arg must respond to #call");
+ }
+ envst->feedback = a;
+ if (!(envst->options & BDB_NEED_ENV_CURRENT)) {
+ envst->options |= BDB_FEEDBACK;
+ rb_thread_local_aset(rb_thread_current(), bdb_id_current_env, obj);
+ }
+ }
+ return a;
+}
+
+#endif
+
+#if BDB_VERSION >= 40250
+
+static VALUE
+bdb_env_i_conf(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+ u_int32_t bytes, gbytes, value, lk_detect;
+ int i, ncache;
+ char *str;
+ const char *strval, **dirs;
+ db_timeout_t timeout;
+ long shm_key;
+ time_t timeval;
+ size_t size;
+ VALUE res;
+
+ GetEnvDB(obj, envst);
+ str = StringValuePtr(a);
+ if (strcmp(str, "cachesize") == 0) {
+ bdb_test_error(envst->envp->get_cachesize(envst->envp, &gbytes, &bytes, &ncache));
+ res = rb_ary_new2(3);
+ rb_ary_push(res, INT2NUM(gbytes));
+ rb_ary_push(res, INT2NUM(bytes));
+ rb_ary_push(res, INT2NUM(ncache));
+ return res;
+ }
+ if (strcmp(str, "data_dirs") == 0) {
+ bdb_test_error(envst->envp->get_data_dirs(envst->envp, &dirs));
+ res = rb_ary_new();
+ if (dirs) {
+ for (i = 0; dirs[i] != NULL; i++) {
+ rb_ary_push(res, rb_tainted_str_new2(dirs[i]));
+ }
+ }
+ return res;
+ }
+ if (strcmp(str, "flags") == 0) {
+ bdb_test_error(envst->envp->get_flags(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "home") == 0) {
+ bdb_test_error(envst->envp->get_home(envst->envp, &strval));
+ if (strval && strlen(strval)) {
+ return rb_tainted_str_new2(strval);
+ }
+ return Qnil;
+ }
+ if (strcmp(str, "lg_bsize") == 0) {
+ bdb_test_error(envst->envp->get_lg_bsize(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "lg_dir") == 0) {
+ bdb_test_error(envst->envp->get_lg_dir(envst->envp, &strval));
+ if (strval && strlen(strval)) {
+ return rb_tainted_str_new2(strval);
+ }
+ return Qnil;
+ }
+ if (strcmp(str, "lg_max") == 0) {
+ bdb_test_error(envst->envp->get_lg_max(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "lg_regionmax") == 0) {
+ bdb_test_error(envst->envp->get_lg_regionmax(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "lk_detect") == 0) {
+ bdb_test_error(envst->envp->get_lk_detect(envst->envp, &lk_detect));
+ return INT2NUM(lk_detect);
+ }
+ if (strcmp(str, "lk_max_lockers") == 0) {
+ bdb_test_error(envst->envp->get_lk_max_lockers(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "lk_max_locks") == 0) {
+ bdb_test_error(envst->envp->get_lk_max_locks(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "lk_max_objects") == 0) {
+ bdb_test_error(envst->envp->get_lk_max_objects(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "mp_mmapsize") == 0) {
+ bdb_test_error(envst->envp->get_mp_mmapsize(envst->envp, &size));
+ return INT2NUM(size);
+ }
+ if (strcmp(str, "open_flags") == 0) {
+ bdb_test_error(envst->envp->get_open_flags(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "rep_limit") == 0) {
+ bdb_test_error(envst->envp->get_rep_limit(envst->envp, &gbytes, &bytes));
+ res = rb_ary_new2(2);
+ rb_ary_push(res, INT2NUM(gbytes));
+ rb_ary_push(res, INT2NUM(bytes));
+ return res;
+ }
+ if (strcmp(str, "shm_key") == 0) {
+ bdb_test_error(envst->envp->get_shm_key(envst->envp, &shm_key));
+ return INT2NUM(shm_key);
+ }
+ if (strcmp(str, "tas_spins") == 0) {
+#if BDB_VERSION >= 40416
+ rb_warn("Invalid option :tas_spins");
+ return Qfalse;
+#else
+ bdb_test_error(envst->envp->get_tas_spins(envst->envp, &value));
+ return INT2NUM(value);
+#endif
+ }
+ if (strcmp(str, "txn_timeout") == 0) {
+ bdb_test_error(envst->envp->get_timeout(envst->envp, &timeout, DB_SET_TXN_TIMEOUT));
+ return INT2NUM(timeout);
+ }
+ if (strcmp(str, "lock_timeout") == 0) {
+ bdb_test_error(envst->envp->get_timeout(envst->envp, &timeout, DB_SET_LOCK_TIMEOUT));
+ return INT2NUM(timeout);
+ }
+ if (strcmp(str, "tmp_dir") == 0) {
+ bdb_test_error(envst->envp->get_tmp_dir(envst->envp, &strval));
+ if (strval && strlen(strval)) {
+ return rb_tainted_str_new2(strval);
+ }
+ return Qnil;
+ }
+ if (strcmp(str, "tx_max") == 0) {
+ bdb_test_error(envst->envp->get_tx_max(envst->envp, &value));
+ return INT2NUM(value);
+ }
+ if (strcmp(str, "tx_timestamp") == 0) {
+ bdb_test_error(envst->envp->get_tx_timestamp(envst->envp, &timeval));
+ return INT2NUM(timeval);
+ }
+ rb_raise(rb_eArgError, "Unknown option %s", str);
+ return obj;
+}
+
+static char *
+options[] = {
+ "cachesize", "data_dirs", "flags", "home", "lg_bsize", "lg_dir",
+ "lg_max", "lg_regionmax", "lk_detect", "lk_max_lockers", "lk_max_locks",
+ "lk_max_objects", "mp_mmapsize", "open_flags", "rep_limit", "shm_key",
+ "tas_spins", "txn_timeout", "lock_timeout", "tmp_dir", "tx_max",
+ "tx_timestamp", 0
+};
+
+struct optst {
+ VALUE obj, str;
+};
+
+static VALUE
+bdb_env_intern_conf(struct optst *optp)
+{
+ return bdb_env_i_conf(optp->obj, optp->str);
+}
+
+static VALUE
+bdb_env_conf(int argc, VALUE *argv, VALUE obj)
+{
+ int i, state;
+ VALUE res, val;
+ struct optst opt;
+
+ if (argc > 1) {
+ rb_raise(rb_eArgError, "invalid number of arguments (%d for 1)", argc);
+ }
+ if (argc == 1) {
+ return bdb_env_i_conf(obj, argv[0]);
+ }
+ res = rb_hash_new();
+ opt.obj = obj;
+ for (i = 0; options[i] != NULL; i++) {
+ opt.str = rb_str_new2(options[i]);
+ val = rb_protect((VALUE (*)(ANYARGS))bdb_env_intern_conf, (VALUE)&opt, &state);
+ if (state == 0) {
+ rb_hash_aset(res, opt.str, val);
+ }
+ }
+ return res;
+}
+
+#endif
+
+#if BDB_VERSION >= 40416
+
+static VALUE
+bdb_env_lsn_reset(int argc, VALUE *argv, VALUE obj)
+{
+ char *file;
+ int flags;
+ VALUE a, b;
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ flags = 0;
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flags = NUM2INT(b);
+ }
+ file = StringValuePtr(a);
+ bdb_test_error(envst->envp->lsn_reset(envst->envp, file, flags));
+ return obj;
+}
+
+static VALUE
+bdb_env_fileid_reset(int argc, VALUE *argv, VALUE obj)
+{
+ char *file;
+ int flags;
+ VALUE a, b;
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ flags = 0;
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flags = NUM2INT(b);
+ }
+ file = StringValuePtr(a);
+ bdb_test_error(envst->envp->fileid_reset(envst->envp, file, flags));
+ return obj;
+}
+
+static VALUE
+bdb_env_set_msgcall(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ if (NIL_P(a)) {
+ envst->msgcall = Qnil;
+ envst->envp->set_msgcall(envst->envp, NULL);
+ return obj;
+ }
+ if (!rb_respond_to(a, bdb_id_call)) {
+ rb_raise(rb_eArgError, "object must respond to #call");
+ }
+ if (!RTEST(envst->msgcall)) {
+ envst->envp->set_msgcall(envst->envp, bdb_env_msgcall);
+ }
+ envst->msgcall = a;
+ return obj;
+}
+
+static VALUE
+bdb_env_set_thread_id(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ if (!rb_respond_to(a, bdb_id_call)) {
+ rb_raise(rb_eArgError, "object must respond to #call");
+ }
+ if (!RTEST(envst->thread_id)) {
+ envst->envp->set_thread_id(envst->envp, bdb_env_thread_id);
+ }
+ envst->thread_id = a;
+ return obj;
+}
+
+static VALUE
+bdb_env_set_thread_id_string(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ if (!rb_respond_to(a, bdb_id_call)) {
+ rb_raise(rb_eArgError, "object must respond to #call");
+ }
+ if (!RTEST(envst->thread_id_string)) {
+ envst->envp->set_thread_id_string(envst->envp, bdb_env_thread_id_string);
+ }
+ envst->thread_id_string = a;
+ return obj;
+}
+
+static VALUE
+bdb_env_set_isalive(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+
+ GetEnvDB(obj, envst);
+ if (!rb_respond_to(a, bdb_id_call)) {
+ rb_raise(rb_eArgError, "object must respond to #call");
+ }
+ if (!RTEST(envst->isalive)) {
+ envst->envp->set_isalive(envst->envp, bdb_env_isalive);
+ }
+ envst->isalive = a;
+ return obj;
+}
+
+static VALUE
+bdb_env_failcheck(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_ENV *envst;
+ int flags = 0;
+ VALUE a;
+
+ GetEnvDB(obj, envst);
+ if (rb_scan_args(argc, argv, "01", &a)) {
+ flags = NUM2INT(a);
+ }
+ bdb_test_error(flags = envst->envp->failchk(envst->envp, flags));
+ return INT2NUM(flags);
+}
+
+
+#endif
+
+void bdb_init_env()
+{
+ bdb_id_call = rb_intern("call");
+#if BDB_VERSION >= 30000
+ id_feedback = rb_intern("bdb_feedback");
+#endif
+ bdb_id_current_env = rb_intern("bdb_current_env");
+#if BDB_VERSION >= 40100
+ id_app_dispatch = rb_intern("bdb_app_dispatch");
+#if BDB_VERSION >= 40416
+ id_msgcall = rb_intern("bdb_msgcall");
+ id_thread_id = rb_intern("bdb_thread_id");
+ id_thread_id_string = rb_intern("bdb_thread_id_string");
+ id_isalive = rb_intern("bdb_isalive");
+#endif
+#endif
+ bdb_cEnv = rb_define_class_under(bdb_mDb, "Env", rb_cObject);
+ rb_define_private_method(bdb_cEnv, "initialize", bdb_env_init, -1);
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ rb_define_alloc_func(bdb_cEnv, bdb_env_s_alloc);
+#else
+ rb_define_singleton_method(bdb_cEnv, "allocate", bdb_env_s_alloc, 0);
+#endif
+ rb_define_singleton_method(bdb_cEnv, "new", bdb_env_s_new, -1);
+ rb_define_singleton_method(bdb_cEnv, "create", bdb_env_s_new, -1);
+ rb_define_singleton_method(bdb_cEnv, "open", bdb_env_s_open, -1);
+ rb_define_singleton_method(bdb_cEnv, "remove", bdb_env_s_remove, -1);
+ rb_define_singleton_method(bdb_cEnv, "unlink", bdb_env_s_remove, -1);
+ rb_define_method(bdb_cEnv, "open_db", bdb_env_open_db, -1);
+ rb_define_method(bdb_cEnv, "close", bdb_env_close, 0);
+ rb_define_method(bdb_cEnv, "set_flags", bdb_env_set_flags, -1);
+ rb_define_method(bdb_cEnv, "home", bdb_env_home, 0);
+#if BDB_VERSION >= 40000
+ rb_define_method(bdb_cEnv, "rep_elect", bdb_env_rep_elect, -1);
+ rb_define_method(bdb_cEnv, "elect", bdb_env_rep_elect, -1);
+ rb_define_method(bdb_cEnv, "rep_process_message", bdb_env_rep_process_message, 3);
+ rb_define_method(bdb_cEnv, "process_message", bdb_env_rep_process_message, 3);
+ rb_define_method(bdb_cEnv, "rep_start", bdb_env_rep_start, 2);
+ if (!rb_method_boundp(rb_cThread, rb_intern("__bdb_thread_init__"), 1)) {
+ rb_alias(rb_cThread, rb_intern("__bdb_thread_init__"), rb_intern("initialize"));
+ rb_define_method(rb_cThread, "initialize", bdb_thread_init, -1);
+ }
+#if BDB_VERSION >= 40100
+ rb_define_method(bdb_cEnv, "rep_limit=", bdb_env_rep_limit, -1);
+#endif
+#endif
+#if BDB_VERSION >= 30000
+ rb_define_method(bdb_cEnv, "feedback=", bdb_env_feedback_set, 1);
+#endif
+#if BDB_VERSION >= 40250
+ rb_define_method(bdb_cEnv, "configuration", bdb_env_conf, -1);
+ rb_define_method(bdb_cEnv, "conf", bdb_env_conf, -1);
+#endif
+#if BDB_VERSION >= 40416
+ rb_define_method(bdb_cEnv, "lsn_reset", bdb_env_lsn_reset, -1);
+ rb_define_method(bdb_cEnv, "fileid_reset", bdb_env_fileid_reset, -1);
+ rb_define_method(bdb_cEnv, "msgcall=", bdb_env_set_msgcall, 1);
+ rb_define_method(bdb_cEnv, "thread_id=", bdb_env_set_thread_id, 1);
+ rb_define_method(bdb_cEnv, "thread_id_string=", bdb_env_set_thread_id_string, 1);
+ rb_define_method(bdb_cEnv, "isalive=", bdb_env_set_isalive, 1);
+ rb_define_method(bdb_cEnv, "failcheck", bdb_env_failcheck, -1);
+#endif
+}
Added: packages/libdb4.3-ruby/branches/upstream/current/src/lock.c
===================================================================
--- packages/libdb4.3-ruby/branches/upstream/current/src/lock.c (rev 0)
+++ packages/libdb4.3-ruby/branches/upstream/current/src/lock.c 2007-12-08 12:00:45 UTC (rev 2142)
@@ -0,0 +1,499 @@
+#include "bdb.h"
+
+static void
+lockid_mark( bdb_LOCKID *dblockid)
+{
+ rb_gc_mark(dblockid->env);
+}
+
+void
+bdb_clean_env(VALUE env, VALUE obj)
+{
+ bdb_ENV *envst;
+ Data_Get_Struct(env, bdb_ENV, envst);
+ bdb_ary_delete(&envst->db_ary, obj);
+}
+
+static void
+lockid_free( bdb_LOCKID *dblockid)
+{
+#if BDB_VERSION >= 40000
+ bdb_ENV *envst;
+
+ bdb_clean_env(dblockid->env, dblockid->self);
+ Data_Get_Struct(dblockid->env, bdb_ENV, envst);
+ if (envst->envp) {
+ envst->envp->lock_id_free(envst->envp, dblockid->lock);
+ }
+#endif
+ free(dblockid);
+}
+
+static VALUE
+bdb_env_lockid(VALUE obj)
+{
+ unsigned int idp;
+ bdb_ENV *envst;
+ bdb_LOCKID *dblockid;
+ VALUE a;
+
+ GetEnvDB(obj, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lk_info) {
+ rb_raise(bdb_eLock, "lock region not open");
+ }
+ bdb_test_error(lock_id(envst->envp->lk_info, &idp));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->lock_id(envst->envp, &idp));
+#else
+ bdb_test_error(lock_id(envst->envp, &idp));
+#endif
+#endif
+ a = Data_Make_Struct(bdb_cLockid, bdb_LOCKID, lockid_mark, lockid_free, dblockid);
+ dblockid->lock = idp;
+ dblockid->env = obj;
+ dblockid->self = a;
+#if BDB_VERSION >= 40000
+ bdb_ary_push(&envst->db_ary, a);
+#endif
+ return a;
+}
+
+static VALUE
+bdb_env_lockid_close(VALUE obj)
+{
+ bdb_ENV *envst;
+ bdb_LOCKID *dblockid;
+
+ Data_Get_Struct(obj, bdb_LOCKID, dblockid);
+ bdb_clean_env(dblockid->env, obj);
+#if BDB_VERSION >= 40000
+ GetEnvDB(dblockid->env, envst);
+ RDATA(obj)->dfree = free;
+ if (envst->envp) {
+ bdb_test_error(envst->envp->lock_id_free(envst->envp, dblockid->lock));
+ }
+#endif
+ dblockid->env = 0;
+ return Qnil;
+}
+
+static VALUE
+bdb_env_lockdetect(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE a, b;
+ bdb_ENV *envst;
+ int flags, atype, aborted;
+
+ flags = atype = aborted = 0;
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flags = NUM2INT(b);
+ }
+ atype = NUM2INT(a);
+ GetEnvDB(obj, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lk_info) {
+ rb_raise(bdb_eLock, "lock region not open");
+ }
+ bdb_test_error(lock_detect(envst->envp->lk_info, flags, atype));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->lock_detect(envst->envp, flags, atype, &aborted));
+#else
+ bdb_test_error(lock_detect(envst->envp, flags, atype, &aborted));
+#endif
+#endif
+ return INT2NUM(aborted);
+}
+
+static VALUE
+bdb_env_lockstat(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_ENV *envst;
+ DB_LOCK_STAT *statp;
+ VALUE a, b;
+ int flags;
+
+ GetEnvDB(obj, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lk_info) {
+ rb_raise(bdb_eLock, "lock region not open");
+ }
+ if (argc != 0) {
+ rb_raise(rb_eArgError, "invalid number of arguments (%d for 0)", argc);
+ }
+ bdb_test_error(lock_stat(envst->envp->lk_info, &statp, 0));
+ a = rb_hash_new();
+ rb_hash_aset(a, rb_tainted_str_new2("st_magic"), INT2NUM(statp->st_magic));
+ rb_hash_aset(a, rb_tainted_str_new2("st_version"), INT2NUM(statp->st_version));
+ rb_hash_aset(a, rb_tainted_str_new2("st_refcnt"), INT2NUM(statp->st_refcnt));
+ rb_hash_aset(a, rb_tainted_str_new2("st_numobjs"), INT2NUM(statp->st_numobjs));
+ rb_hash_aset(a, rb_tainted_str_new2("st_regsize"), INT2NUM(statp->st_regsize));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxlocks"), INT2NUM(statp->st_maxlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nmodes"), INT2NUM(statp->st_nmodes));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nlockers"), INT2NUM(statp->st_nlockers));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nconflicts"), INT2NUM(statp->st_nconflicts));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nrequests"), INT2NUM(statp->st_nrequests));
+ rb_hash_aset(a, rb_tainted_str_new2("st_ndeadlocks"), INT2NUM(statp->st_ndeadlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_region_wait"), INT2NUM(statp->st_region_wait));
+ rb_hash_aset(a, rb_tainted_str_new2("st_region_nowait"), INT2NUM(statp->st_region_nowait));
+#else
+#if BDB_VERSION >= 40000
+ flags = 0;
+ if (rb_scan_args(argc, argv, "01", &b) == 1) {
+ flags = NUM2INT(b);
+ }
+ bdb_test_error(envst->envp->lock_stat(envst->envp, &statp, flags));
+ a = rb_hash_new();
+#if BDB_VERSION >= 40100
+ rb_hash_aset(a, rb_tainted_str_new2("st_lastid"), INT2NUM(statp->st_id));
+#else
+ rb_hash_aset(a, rb_tainted_str_new2("st_lastid"), INT2NUM(statp->st_lastid));
+#endif
+ rb_hash_aset(a, rb_tainted_str_new2("st_nmodes"), INT2NUM(statp->st_nmodes));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxlocks"), INT2NUM(statp->st_maxlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxlockers"), INT2NUM(statp->st_maxlockers));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxobjects"), INT2NUM(statp->st_maxobjects));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nlocks"), INT2NUM(statp->st_nlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxnlocks"), INT2NUM(statp->st_maxnlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nlockers"), INT2NUM(statp->st_nlockers));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxnlockers"), INT2NUM(statp->st_maxnlockers));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nobjects"), INT2NUM(statp->st_nobjects));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxnobjects"), INT2NUM(statp->st_maxnobjects));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nrequests"), INT2NUM(statp->st_nrequests));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nreleases"), INT2NUM(statp->st_nreleases));
+#if BDB_VERSION >= 40416
+ rb_hash_aset(a, rb_tainted_str_new2("st_lock_nowait"), INT2NUM(statp->st_lock_nowait));
+ rb_hash_aset(a, rb_tainted_str_new2("st_lock_wait"), INT2NUM(statp->st_lock_wait));
+#else
+ rb_hash_aset(a, rb_tainted_str_new2("st_nnowaits"), INT2NUM(statp->st_nnowaits));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nconflicts"), INT2NUM(statp->st_nconflicts));
+#endif
+ rb_hash_aset(a, rb_tainted_str_new2("st_ndeadlocks"), INT2NUM(statp->st_ndeadlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nlocktimeouts"), INT2NUM(statp->st_nlocktimeouts));
+ rb_hash_aset(a, rb_tainted_str_new2("st_ntxntimeouts"), INT2NUM(statp->st_ntxntimeouts));
+ rb_hash_aset(a, rb_tainted_str_new2("st_regsize"), INT2NUM(statp->st_regsize));
+ rb_hash_aset(a, rb_tainted_str_new2("st_region_wait"), INT2NUM(statp->st_region_wait));
+ rb_hash_aset(a, rb_tainted_str_new2("st_region_nowait"), INT2NUM(statp->st_region_nowait));
+#else
+ if (argc != 0) {
+ rb_raise(rb_eArgError, "invalid number of arguments (%d for 0)", argc);
+ }
+#if BDB_VERSION < 30300
+ bdb_test_error(lock_stat(envst->envp, &statp, 0));
+#else
+ bdb_test_error(lock_stat(envst->envp, &statp));
+#endif
+ a = rb_hash_new();
+ rb_hash_aset(a, rb_tainted_str_new2("st_lastid"), INT2NUM(statp->st_lastid));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nmodes"), INT2NUM(statp->st_nmodes));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxlocks"), INT2NUM(statp->st_maxlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nlockers"), INT2NUM(statp->st_nlockers));
+ rb_hash_aset(a, rb_tainted_str_new2("st_maxnlockers"), INT2NUM(statp->st_maxnlockers));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nconflicts"), INT2NUM(statp->st_nconflicts));
+ rb_hash_aset(a, rb_tainted_str_new2("st_nrequests"), INT2NUM(statp->st_nrequests));
+ rb_hash_aset(a, rb_tainted_str_new2("st_ndeadlocks"), INT2NUM(statp->st_ndeadlocks));
+ rb_hash_aset(a, rb_tainted_str_new2("st_regsize"), INT2NUM(statp->st_regsize));
+ rb_hash_aset(a, rb_tainted_str_new2("st_region_wait"), INT2NUM(statp->st_region_wait));
+ rb_hash_aset(a, rb_tainted_str_new2("st_region_nowait"), INT2NUM(statp->st_region_nowait));
+#endif
+#endif
+ free(statp);
+ return a;
+}
+
+#if BDB_VERSION < 30000
+#define GetLockid(obj, lockid, envst) \
+{ \
+ Data_Get_Struct(obj, bdb_LOCKID, lockid); \
+ GetEnvDB(lockid->env, envst); \
+ if (envst->envp->lk_info == 0) { \
+ rb_raise(bdb_eLock, "closed lockid"); \
+ } \
+}
+#else
+#define GetLockid(obj, lockid, envst) \
+{ \
+ Data_Get_Struct(obj, bdb_LOCKID, lockid); \
+ GetEnvDB(lockid->env, envst); \
+}
+#endif
+
+static void
+lock_mark(bdb_LOCK *lock)
+{
+ rb_gc_mark(lock->env);
+}
+
+static void
+lock_free(bdb_LOCK *lock)
+{
+#if BDB_VERSION < 30000
+ bdb_ENV *envst;
+
+ Data_Get_Struct(lock->env, bdb_ENV, envst); \
+ if (envst->envp && envst->envp->lk_info) {
+ lock_close(envst->envp->lk_info);
+ envst->envp = NULL;
+ }
+#endif
+ free(lock);
+}
+
+static VALUE
+bdb_lockid_get(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_LOCKID *lockid;
+ bdb_ENV *envst;
+ DB_LOCK lock;
+ bdb_LOCK *lockst;
+ DBT objet;
+ unsigned int flags;
+ int lock_mode;
+ VALUE a, b, c, res;
+
+ rb_secure(2);
+ flags = 0;
+ if (rb_scan_args(argc, argv, "21", &a, &b, &c) == 3) {
+ if (c == Qtrue) {
+ flags = DB_LOCK_NOWAIT;
+ }
+ else {
+ flags = NUM2UINT(c);
+ }
+ }
+ SafeStringValue(a);
+ MEMZERO(&objet, DBT, 1);
+ objet.data = StringValuePtr(a);
+ objet.size = RSTRING(a)->len;
+ lock_mode = NUM2INT(b);
+ GetLockid(obj, lockid, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lk_info) {
+ rb_raise(bdb_eLock, "lock region not open");
+ }
+ bdb_test_error(lock_get(envst->envp->lk_info, lockid->lock, flags,
+ &objet, lock_mode, &lock));
+#else
+#if BDB_VERSION >= 40000
+
+ bdb_test_error(envst->envp->lock_get(envst->envp, lockid->lock,
+ flags, &objet, lock_mode, &lock));
+#else
+ bdb_test_error(lock_get(envst->envp, lockid->lock, flags,
+ &objet, lock_mode, &lock));
+#endif
+#endif
+ res = Data_Make_Struct(bdb_cLock, bdb_LOCK, lock_mark, lock_free, lockst);
+#if BDB_VERSION < 30000
+ lockst->lock = lock;
+#else
+ lockst->lock = ALLOC(DB_LOCK);
+ MEMCPY(lockst->lock, &lock, DB_LOCK, 1);
+#endif
+ lockst->env = lockid->env;
+ return res;
+}
+
+
+#if BDB_VERSION < 30000
+#define GetLock(obj, lock, envst) \
+{ \
+ Data_Get_Struct(obj, bdb_LOCK, lock); \
+ GetEnvDB(lock->env, envst); \
+ if (envst->envp->lk_info == 0) \
+ rb_raise(bdb_eLock, "closed lock"); \
+}
+#else
+#define GetLock(obj, lock, envst) \
+{ \
+ Data_Get_Struct(obj, bdb_LOCK, lock); \
+ GetEnvDB(lock->env, envst); \
+}
+#endif
+
+struct lockreq {
+ DB_LOCKREQ *list;
+};
+
+static VALUE
+bdb_lockid_each(VALUE obj, VALUE listobj)
+{
+ VALUE key, value;
+ DB_LOCKREQ *list;
+ bdb_ENV *envst;
+ struct lockreq *listst;
+ char *options;
+
+ Data_Get_Struct(listobj, struct lockreq, listst);
+ list = listst->list;
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ key = rb_obj_as_string(key);
+ options = StringValuePtr(key);
+ if (strcmp(options, "op") == 0) {
+ list->op = NUM2INT(value);
+ }
+ else if (strcmp(options, "obj") == 0) {
+ Check_Type(value, T_STRING);
+ list->obj = ALLOC(DBT);
+ MEMZERO(list->obj, DBT, 1);
+ list->obj->data = StringValuePtr(value);
+ list->obj->size = RSTRING(value)->len;
+ }
+ else if (strcmp(options, "mode") == 0) {
+ list->mode = NUM2INT(value);
+ }
+ else if (strcmp(options, "lock") == 0) {
+ bdb_LOCK *lockst;
+
+ if (!rb_obj_is_kind_of(value, bdb_cLock)) {
+ rb_raise(bdb_eFatal, "BDB::Lock expected");
+ }
+ GetLock(value, lockst, envst);
+#if BDB_VERSION < 30000
+ list->lock = lockst->lock;
+#else
+ MEMCPY(&list->lock, lockst->lock, DB_LOCK, 1);
+#endif
+ }
+#if BDB_VERSION >= 40000
+ else if (strcmp(options, "timeout") == 0) {
+ list->timeout = rb_Integer(value);
+ }
+#endif
+ return Qnil;
+}
+
+static VALUE
+bdb_lockid_vec(int argc, VALUE *argv, VALUE obj)
+{
+ DB_LOCKREQ *list;
+ bdb_LOCKID *lockid;
+ bdb_LOCK *lockst;
+ bdb_ENV *envst;
+ unsigned int flags;
+ VALUE a, b, c, res;
+ int i, n, err;
+ VALUE listobj;
+ struct lockreq *listst;
+
+ flags = 0;
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ if (b == Qtrue) {
+ flags = DB_LOCK_NOWAIT;
+ }
+ else {
+ flags = NUM2UINT(b);
+ }
+ }
+ Check_Type(a, T_ARRAY);
+ list = ALLOCA_N(DB_LOCKREQ, RARRAY(a)->len);
+ MEMZERO(list, DB_LOCKREQ, RARRAY(a)->len);
+ listobj = Data_Make_Struct(obj, struct lockreq, 0, free, listst);
+ for (i = 0; i < RARRAY(a)->len; i++) {
+ b = RARRAY(a)->ptr[i];
+ Check_Type(b, T_HASH);
+ listst->list = &list[i];
+ rb_iterate(rb_each, b, bdb_lockid_each, listobj);
+ }
+ GetLockid(obj, lockid, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lk_info) {
+ rb_raise(bdb_eLock, "lock region not open");
+ }
+ err = lock_vec(envst->envp->lk_info, lockid->lock, flags,
+ list, RARRAY(a)->len, NULL);
+#else
+#if BDB_VERSION >= 40000
+ err = envst->envp->lock_vec(envst->envp, lockid->lock, flags,
+ list, RARRAY(a)->len, NULL);
+#else
+ err = lock_vec(envst->envp, lockid->lock, flags,
+ list, RARRAY(a)->len, NULL);
+#endif
+#endif
+ if (err != 0) {
+ for (i = 0; i < RARRAY(a)->len; i++) {
+ if (list[i].obj)
+ free(list[i].obj);
+ }
+ res = (err == DB_LOCK_DEADLOCK)?bdb_eLock:bdb_eFatal;
+ if (bdb_errcall) {
+ bdb_errcall = 0;
+ rb_raise(res, "%s -- %s", StringValuePtr(bdb_errstr), db_strerror(err));
+ }
+ else
+ rb_raise(res, "%s", db_strerror(err));
+ }
+ res = rb_ary_new2(RARRAY(a)->len);
+ n = 0;
+ for (i = 0; i < RARRAY(a)->len; i++) {
+ if (list[i].op == DB_LOCK_GET) {
+ c = Data_Make_Struct(bdb_cLock, bdb_LOCK, lock_mark, lock_free, lockst);
+#if BDB_VERSION < 30000
+ lockst->lock = list[i].lock;
+#else
+ lockst->lock = ALLOC(DB_LOCK);
+ MEMCPY(lockst->lock, &list[i].lock, DB_LOCK, 1);
+#endif
+ lockst->env = lockid->env;
+ rb_ary_push(res, c);
+ n++;
+ }
+ else {
+ rb_ary_push(res, Qnil);
+ }
+ }
+ return res;
+}
+
+static VALUE
+bdb_lock_put(VALUE obj)
+{
+ bdb_LOCK *lockst;
+ bdb_ENV *envst;
+
+ GetLock(obj, lockst, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lk_info) {
+ rb_raise(bdb_eLock, "lock region not open");
+ }
+ bdb_test_error(lock_put(envst->envp->lk_info, lockst->lock));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->lock_put(envst->envp, lockst->lock));
+#else
+ bdb_test_error(lock_put(envst->envp, lockst->lock));
+#endif
+#endif
+ return Qnil;
+}
+
+void bdb_init_lock()
+{
+ rb_define_method(bdb_cEnv, "lock_id", bdb_env_lockid, 0);
+ rb_define_method(bdb_cEnv, "lock", bdb_env_lockid, 0);
+ rb_define_method(bdb_cEnv, "lock_stat", bdb_env_lockstat, -1);
+ rb_define_method(bdb_cEnv, "lock_detect", bdb_env_lockdetect, -1);
+ bdb_cLockid = rb_define_class_under(bdb_mDb, "Lockid", rb_cObject);
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ rb_undef_alloc_func(bdb_cLockid);
+#else
+ rb_undef_method(CLASS_OF(bdb_cLockid), "allocate");
+#endif
+ rb_undef_method(CLASS_OF(bdb_cLockid), "new");
+ rb_define_method(bdb_cLockid, "lock_get", bdb_lockid_get, -1);
+ rb_define_method(bdb_cLockid, "get", bdb_lockid_get, -1);
+ rb_define_method(bdb_cLockid, "lock_vec", bdb_lockid_vec, -1);
+ rb_define_method(bdb_cLockid, "vec", bdb_lockid_vec, -1);
+ rb_define_method(bdb_cLockid, "close", bdb_env_lockid_close, 0);
+ bdb_cLock = rb_define_class_under(bdb_mDb, "Lock", rb_cObject);
+ rb_undef_method(CLASS_OF(bdb_cLock), "allocate");
+ rb_undef_method(CLASS_OF(bdb_cLock), "new");
+ rb_define_method(bdb_cLock, "put", bdb_lock_put, 0);
+ rb_define_method(bdb_cLock, "lock_put", bdb_lock_put, 0);
+ rb_define_method(bdb_cLock, "release", bdb_lock_put, 0);
+ rb_define_method(bdb_cLock, "delete", bdb_lock_put, 0);
+}
Added: packages/libdb4.3-ruby/branches/upstream/current/src/log.c
===================================================================
--- packages/libdb4.3-ruby/branches/upstream/current/src/log.c (rev 0)
+++ packages/libdb4.3-ruby/branches/upstream/current/src/log.c 2007-12-08 12:00:45 UTC (rev 2142)
@@ -0,0 +1,745 @@
+#include "bdb.h"
+
+static void
+mark_lsn(struct dblsnst *lsnst)
+{
+ rb_gc_mark(lsnst->env);
+}
+
+static void
+free_lsn(struct dblsnst *lsnst)
+{
+ if (BDB_VALID(lsnst->env, T_DATA)) {
+ bdb_clean_env(lsnst->env, lsnst->self);
+ }
+#if BDB_VERSION >= 40000
+ if (lsnst->cursor && BDB_VALID(lsnst->env, T_DATA)) {
+ bdb_ENV *envst;
+
+ Data_Get_Struct(lsnst->env, bdb_ENV, envst);
+ if (envst->envp) {
+ lsnst->cursor->close(lsnst->cursor, 0);
+ }
+ lsnst->cursor = 0;
+ }
+#endif
+ if (lsnst->lsn) free(lsnst->lsn);
+ free(lsnst);
+}
+
+VALUE
+bdb_makelsn(VALUE env)
+{
+ bdb_ENV *envst;
+ struct dblsnst *lsnst;
+ VALUE res;
+
+ GetEnvDB(env, envst);
+ res = Data_Make_Struct(bdb_cLsn, struct dblsnst, mark_lsn, free_lsn, lsnst);
+ lsnst->env = env;
+ lsnst->lsn = ALLOC(DB_LSN);
+ lsnst->self = res;
+ return res;
+}
+
+static VALUE
+bdb_s_log_put_internal(VALUE obj, VALUE a, int flag)
+{
+ bdb_ENV *envst;
+ VALUE ret;
+ DBT data;
+ struct dblsnst *lsnst;
+
+ GetEnvDB(obj, envst);
+ if (TYPE(a) != T_STRING) a = rb_str_to_str(a);
+ ret = bdb_makelsn(obj);
+ Data_Get_Struct(ret, struct dblsnst, lsnst);
+ data.data = StringValuePtr(a);
+ data.size = RSTRING(a)->len;
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_put(envst->envp->lg_info, lsnst->lsn, &data, flag));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_put(envst->envp, lsnst->lsn, &data, flag));
+#else
+ bdb_test_error(log_put(envst->envp, lsnst->lsn, &data, flag));
+#endif
+#endif
+ return ret;
+}
+
+static VALUE
+bdb_s_log_put(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE a, b;
+ int flag = 0;
+
+ if (argc == 0 || argc > 2) {
+ rb_raise(bdb_eFatal, "Invalid number of arguments");
+ }
+#ifdef DB_CHECKPOINT
+ flag = DB_CHECKPOINT;
+#endif
+ if (rb_scan_args(argc, argv, "11", &a, &b) == 2) {
+ flag = NUM2INT(b);
+ }
+ return bdb_s_log_put_internal(obj, a, flag);
+}
+
+static VALUE
+bdb_s_log_checkpoint(VALUE obj, VALUE a)
+{
+#ifdef DB_CHECKPOINT
+ return bdb_s_log_put_internal(obj, a, DB_CHECKPOINT);
+#else
+ rb_warning("BDB::CHECKPOINT is obsolete");
+ return bdb_s_log_put_internal(obj, a, 0);
+#endif
+}
+
+static VALUE
+bdb_s_log_flush(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_ENV *envst;
+
+ if (argc == 0) {
+ GetEnvDB(obj, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_flush(envst->envp->lg_info, NULL));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_flush(envst->envp, NULL));
+#else
+ bdb_test_error(log_flush(envst->envp, NULL));
+#endif
+#endif
+ return obj;
+ }
+ else if (argc == 1) {
+ return bdb_s_log_put_internal(obj, argv[0], DB_FLUSH);
+ }
+ else {
+ rb_raise(bdb_eFatal, "Invalid number of arguments");
+ }
+}
+
+static VALUE
+bdb_s_log_curlsn(VALUE obj, VALUE a)
+{
+#ifdef DB_CURSLN
+ return bdb_s_log_put_internal(obj, a, DB_CURLSN);
+#else
+ rb_warning("BDB::CURLSN is obsolete");
+ return bdb_s_log_put_internal(obj, a, 0);
+#endif
+}
+
+
+static VALUE
+bdb_env_log_stat(int argc, VALUE *argv, VALUE obj)
+{
+ DB_LOG_STAT *bdb_stat;
+ bdb_ENV *envst;
+ VALUE res, b;
+ int flags;
+
+ GetEnvDB(obj, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ if (argc != 0) {
+ rb_raise(rb_eArgError, "invalid number of arguments (%d for 0)", argc);
+ }
+ bdb_test_error(log_stat(envst->envp->lg_info, &bdb_stat, 0));
+#else
+#if BDB_VERSION >= 40000
+ flags = 0;
+ if (rb_scan_args(argc, argv, "01", &b) == 1) {
+ flags = NUM2INT(b);
+ }
+ bdb_test_error(envst->envp->log_stat(envst->envp, &bdb_stat, flags));
+#else
+ if (argc != 0) {
+ rb_raise(rb_eArgError, "invalid number of arguments (%d for 0)", argc);
+ }
+#if BDB_VERSION < 30300
+ bdb_test_error(log_stat(envst->envp, &bdb_stat, 0));
+#else
+ bdb_test_error(log_stat(envst->envp, &bdb_stat));
+#endif
+#endif
+#endif
+ res = rb_hash_new();
+ rb_hash_aset(res, rb_tainted_str_new2("st_magic"), INT2NUM(bdb_stat->st_magic));
+ rb_hash_aset(res, rb_tainted_str_new2("st_version"), INT2NUM(bdb_stat->st_version));
+ rb_hash_aset(res, rb_tainted_str_new2("st_regsize"), INT2NUM(bdb_stat->st_regsize));
+ rb_hash_aset(res, rb_tainted_str_new2("st_mode"), INT2NUM(bdb_stat->st_mode));
+#if BDB_VERSION < 30000
+ rb_hash_aset(res, rb_tainted_str_new2("st_refcnt"), INT2NUM(bdb_stat->st_refcnt));
+#else
+ rb_hash_aset(res, rb_tainted_str_new2("st_lg_bsize"), INT2NUM(bdb_stat->st_lg_bsize));
+#endif
+#if BDB_VERSION >= 40100
+ rb_hash_aset(res, rb_tainted_str_new2("st_lg_size"), INT2NUM(bdb_stat->st_lg_size));
+ rb_hash_aset(res, rb_tainted_str_new2("st_lg_max"), INT2NUM(bdb_stat->st_lg_size));
+#else
+ rb_hash_aset(res, rb_tainted_str_new2("st_lg_max"), INT2NUM(bdb_stat->st_lg_max));
+#endif
+ rb_hash_aset(res, rb_tainted_str_new2("st_w_mbytes"), INT2NUM(bdb_stat->st_w_mbytes));
+ rb_hash_aset(res, rb_tainted_str_new2("st_w_bytes"), INT2NUM(bdb_stat->st_w_bytes));
+ rb_hash_aset(res, rb_tainted_str_new2("st_wc_mbytes"), INT2NUM(bdb_stat->st_wc_mbytes));
+ rb_hash_aset(res, rb_tainted_str_new2("st_wc_bytes"), INT2NUM(bdb_stat->st_wc_bytes));
+ rb_hash_aset(res, rb_tainted_str_new2("st_wcount"), INT2NUM(bdb_stat->st_wcount));
+#if BDB_VERSION >= 30000
+ rb_hash_aset(res, rb_tainted_str_new2("st_wcount_fill"), INT2NUM(bdb_stat->st_wcount_fill));
+#endif
+ rb_hash_aset(res, rb_tainted_str_new2("st_scount"), INT2NUM(bdb_stat->st_scount));
+ rb_hash_aset(res, rb_tainted_str_new2("st_cur_file"), INT2NUM(bdb_stat->st_cur_file));
+ rb_hash_aset(res, rb_tainted_str_new2("st_cur_offset"), INT2NUM(bdb_stat->st_cur_offset));
+ rb_hash_aset(res, rb_tainted_str_new2("st_region_wait"), INT2NUM(bdb_stat->st_region_wait));
+ rb_hash_aset(res, rb_tainted_str_new2("st_region_nowait"), INT2NUM(bdb_stat->st_region_nowait));
+#if BDB_VERSION >= 40000
+ rb_hash_aset(res, rb_tainted_str_new2("st_disk_file"), INT2NUM(bdb_stat->st_disk_file));
+ rb_hash_aset(res, rb_tainted_str_new2("st_disk_offset"), INT2NUM(bdb_stat->st_disk_offset));
+#if BDB_VERSION < 40100
+ rb_hash_aset(res, rb_tainted_str_new2("st_flushcommit"), INT2NUM(bdb_stat->st_flushcommit));
+#endif
+ rb_hash_aset(res, rb_tainted_str_new2("st_maxcommitperflush"), INT2NUM(bdb_stat->st_maxcommitperflush));
+ rb_hash_aset(res, rb_tainted_str_new2("st_mincommitperflush"), INT2NUM(bdb_stat->st_mincommitperflush));
+#endif
+ free(bdb_stat);
+ return res;
+}
+
+#if BDB_VERSION < 40000
+
+static VALUE
+bdb_env_log_get(VALUE obj, VALUE a)
+{
+ bdb_ENV *envst;
+ DBT data;
+ struct dblsnst *lsnst;
+ VALUE res, lsn;
+ int ret, flag;
+
+ GetEnvDB(obj, envst);
+ flag = NUM2INT(a);
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ lsn = bdb_makelsn(obj);
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ ret = bdb_test_error(log_get(envst->envp->lg_info, lsnst->lsn, &data, flag));
+#else
+ ret = bdb_test_error(log_get(envst->envp, lsnst->lsn, &data, flag));
+#endif
+ if (ret == DB_NOTFOUND) {
+ return Qnil;
+ }
+ res = rb_tainted_str_new(data.data, data.size);
+ free(data.data);
+ return rb_assoc_new(res, lsn);
+}
+
+#endif
+
+#if BDB_VERSION >= 40000
+static VALUE bdb_log_cursor _((VALUE));
+#endif
+
+#define BDB_LOG_INIT 0
+#define BDB_LOG_SET 1
+#define BDB_LOG_NEXT 2
+
+static VALUE
+bdb_i_each_log_get(VALUE obj, int flag)
+{
+#if BDB_VERSION < 40000
+ bdb_ENV *envst;
+#endif
+ struct dblsnst *lsnst, *lsnst1;
+ DBT data;
+ VALUE lsn, res, lsn1;
+ int ret, init, flags;
+
+ init = BDB_LOG_INIT;
+#if BDB_VERSION < 40000
+ GetEnvDB(obj, envst);
+#else
+ lsn = obj;
+ Data_Get_Struct(obj, struct dblsnst, lsnst);
+ flag = lsnst->flags;
+ if (lsnst->cursor == 0) {
+ DB_LSN *lsn1;
+
+ init = BDB_LOG_SET;
+ lsn1 = lsnst->lsn;
+ lsn = bdb_makelsn(lsnst->env);
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+ MEMCPY(lsnst->lsn, lsn1, DB_LSN, 1);
+ bdb_log_cursor(lsn);
+ }
+#endif
+
+ do {
+#if BDB_VERSION < 40000
+ lsn = bdb_makelsn(obj);
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+#endif
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+ switch (init) {
+ case BDB_LOG_INIT:
+ flags = (flag == DB_NEXT)?DB_FIRST:DB_LAST;
+ break;
+ case BDB_LOG_SET:
+ flags = DB_SET;
+ break;
+ default:
+ flags = flag;
+ break;
+ }
+ init = BDB_LOG_NEXT;
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ ret = bdb_test_error(log_get(envst->envp->lg_info, lsnst->lsn, &data, flags));
+#else
+#if BDB_VERSION >= 40000
+ ret = bdb_test_error(lsnst->cursor->get(lsnst->cursor, lsnst->lsn, &data, flags));
+ lsn1 = bdb_makelsn(lsnst->env);
+ Data_Get_Struct(lsn1, struct dblsnst, lsnst1);
+ MEMCPY(lsnst1->lsn, lsnst->lsn, DB_LSN, 1);
+#else
+ ret = bdb_test_error(log_get(envst->envp, lsnst->lsn, &data, flags));
+ lsn1 = lsn;
+#endif
+#endif
+ if (ret == DB_NOTFOUND) {
+ return Qnil;
+ }
+ res = rb_tainted_str_new(data.data, data.size);
+ free(data.data);
+ rb_yield(rb_assoc_new(res, lsn));
+ } while (1);
+ return Qnil;
+}
+
+#if BDB_VERSION < 40000
+
+static VALUE
+bdb_env_log_each(VALUE obj)
+{
+ return bdb_i_each_log_get(obj, DB_NEXT);
+}
+
+static VALUE
+bdb_env_log_hcae(VALUE obj)
+{
+ return bdb_i_each_log_get(obj, DB_PREV);
+}
+
+#else
+
+static VALUE
+log_cursor_close(VALUE obj)
+{
+ struct dblsnst *lsnst;
+
+ Data_Get_Struct(obj, struct dblsnst, lsnst);
+ if (lsnst->cursor) {
+ bdb_test_error(lsnst->cursor->close(lsnst->cursor, 0));
+ lsnst->cursor = 0;
+ }
+ return Qnil;
+}
+
+static VALUE
+bdb_log_cursor_close(VALUE obj)
+{
+ struct dblsnst *lsnst;
+
+ Data_Get_Struct(obj, struct dblsnst, lsnst);
+ bdb_clean_env(lsnst->env, obj);
+
+ return log_cursor_close(obj);
+}
+
+static VALUE
+bdb_log_cursor(VALUE lsn)
+{
+ bdb_ENV *envst;
+ struct dblsnst *lsnst;
+
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+ if (!lsnst->cursor) {
+ GetEnvDB(lsnst->env, envst);
+ bdb_test_error(envst->envp->log_cursor(envst->envp, &lsnst->cursor, 0));
+ bdb_ary_push(&envst->db_ary, lsn);
+ }
+ return lsn;
+}
+
+static VALUE
+bdb_env_log_cursor(VALUE obj)
+{
+ return bdb_log_cursor(bdb_makelsn(obj));
+}
+
+static VALUE
+bdb_env_i_get(VALUE obj)
+{
+ bdb_ENV *envst;
+ struct dblsnst *lsnst;
+
+ log_cursor_close(obj);
+ Data_Get_Struct(obj, struct dblsnst, lsnst);
+ GetEnvDB(lsnst->env, envst);
+ bdb_test_error(envst->envp->log_cursor(envst->envp, &lsnst->cursor, 0));
+ return bdb_i_each_log_get(obj, lsnst->flags);
+}
+
+
+static VALUE
+bdb_env_log_each(VALUE obj)
+{
+ VALUE lsn;
+ struct dblsnst *lsnst;
+
+ lsn = bdb_makelsn(obj);
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+ lsnst->flags = DB_NEXT;
+ return rb_ensure(bdb_env_i_get, lsn, bdb_log_cursor_close, lsn);
+}
+
+static VALUE
+bdb_env_log_hcae(VALUE obj)
+{
+ VALUE lsn;
+ struct dblsnst *lsnst;
+
+ lsn = bdb_makelsn(obj);
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+ lsnst->flags = DB_PREV;
+ return rb_ensure(bdb_env_i_get, lsn, bdb_log_cursor_close, lsn);
+}
+
+static VALUE
+bdb_log_i_get(VALUE obj)
+{
+ struct dblsnst *lsnst;
+
+ log_cursor_close(obj);
+ Data_Get_Struct(obj, struct dblsnst, lsnst);
+ return bdb_i_each_log_get(obj, lsnst->flags);
+}
+
+static VALUE
+bdb_log_each(VALUE lsn)
+{
+ struct dblsnst *lsnst;
+
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+ lsnst->flags = DB_NEXT;
+ return rb_ensure(bdb_log_i_get, lsn, bdb_log_cursor_close, lsn);
+}
+
+static VALUE
+bdb_log_hcae(VALUE lsn)
+{
+ struct dblsnst *lsnst;
+
+ Data_Get_Struct(lsn, struct dblsnst, lsnst);
+ lsnst->flags = DB_PREV;
+ return rb_ensure(bdb_log_i_get, lsn, bdb_log_cursor_close, lsn);
+ }
+
+
+#endif
+
+static VALUE
+bdb_env_log_archive(int argc, VALUE *argv, VALUE obj)
+{
+ char **list, **file;
+ bdb_ENV *envst;
+ int flag;
+ VALUE res;
+
+ GetEnvDB(obj, envst);
+ flag = 0;
+ list = NULL;
+ if (rb_scan_args(argc, argv, "01", &res)) {
+ flag = NUM2INT(res);
+ }
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_archive(envst->envp->lg_info, &list, flag, NULL));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_archive(envst->envp, &list, flag));
+#else
+#if BDB_VERSION < 30300
+ bdb_test_error(log_archive(envst->envp, &list, flag, NULL));
+#else
+ bdb_test_error(log_archive(envst->envp, &list, flag));
+#endif
+#endif
+#endif
+ res = rb_ary_new();
+ for (file = list; file != NULL && *file != NULL; file++) {
+ rb_ary_push(res, rb_tainted_str_new2(*file));
+ }
+ if (list != NULL) free(list);
+ return res;
+}
+
+#define GetLsn(obj, lsnst, envst) \
+{ \
+ Data_Get_Struct(obj, struct dblsnst, lsnst); \
+ GetEnvDB(lsnst->env, envst); \
+}
+
+static VALUE
+bdb_lsn_env(VALUE obj)
+{
+ struct dblsnst *lsnst;
+ bdb_ENV *envst;
+ GetLsn(obj, lsnst, envst);
+ return lsnst->env;
+}
+
+static VALUE
+bdb_lsn_log_file(VALUE obj)
+{
+ struct dblsnst *lsnst;
+ bdb_ENV *envst;
+ char name[2048];
+
+ GetLsn(obj, lsnst, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_file(envst->envp->lg_info, lsnst->lsn, name, 2048));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_file(envst->envp, lsnst->lsn, name, 2048));
+#else
+ bdb_test_error(log_file(envst->envp, lsnst->lsn, name, 2048));
+#endif
+#endif
+ return rb_tainted_str_new2(name);
+}
+
+static VALUE
+bdb_lsn_log_flush(VALUE obj)
+{
+ struct dblsnst *lsnst;
+ bdb_ENV *envst;
+
+ GetLsn(obj, lsnst, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_flush(envst->envp->lg_info, lsnst->lsn));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_flush(envst->envp, lsnst->lsn));
+#else
+ bdb_test_error(log_flush(envst->envp, lsnst->lsn));
+#endif
+#endif
+ return obj;
+}
+
+static VALUE
+bdb_lsn_log_compare(VALUE obj, VALUE a)
+{
+ struct dblsnst *lsnst1, *lsnst2;
+ bdb_ENV *envst1, *envst2;
+
+ if (!rb_obj_is_kind_of(a, bdb_cLsn)) {
+ rb_raise(bdb_eFatal, "invalid argument for <=>");
+ }
+ GetLsn(obj, lsnst1, envst1);
+ GetLsn(a, lsnst2, envst2);
+ return INT2NUM(log_compare(lsnst1->lsn, lsnst2->lsn));
+}
+
+static VALUE
+bdb_lsn_log_get(int argc, VALUE *argv, VALUE obj)
+{
+ struct dblsnst *lsnst;
+ DBT data;
+ VALUE res, a;
+ int ret, flags;
+ bdb_ENV *envst;
+#if BDB_VERSION >= 40000
+ DB_LOGC *cursor;
+#endif
+
+ flags = DB_SET;
+ if (rb_scan_args(argc, argv, "01", &a) == 1) {
+ flags = NUM2INT(a);
+ }
+ GetLsn(obj, lsnst, envst);
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_cursor(envst->envp, &cursor, 0));
+#endif
+ MEMZERO(&data, DBT, 1);
+ data.flags |= DB_DBT_MALLOC;
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ ret = bdb_test_error(log_get(envst->envp->lg_info, lsnst->lsn, &data, flags));
+#else
+#if BDB_VERSION >= 40000
+ ret = cursor->get(cursor, lsnst->lsn, &data, flags);
+ cursor->close(cursor, 0);
+ ret = bdb_test_error(ret);
+#else
+ ret = bdb_test_error(log_get(envst->envp, lsnst->lsn, &data, flags));
+#endif
+#endif
+ if (ret == DB_NOTFOUND) {
+ return Qnil;
+ }
+ res = rb_tainted_str_new(data.data, data.size);
+ free(data.data);
+ return res;
+}
+
+static VALUE
+bdb_log_register(VALUE obj, VALUE a)
+{
+#if BDB_VERSION >= 40100
+ rb_warn("log_register is obsolete");
+ return Qnil;
+#else
+ bdb_DB *dbst;
+ bdb_ENV *envst;
+
+ if (TYPE(a) != T_STRING) {
+ rb_raise(bdb_eFatal, "Need a filename");
+ }
+ if (bdb_env_p(obj) == Qfalse) {
+ rb_raise(bdb_eFatal, "Database must be open in an Env");
+ }
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ Data_Get_Struct(dbst->env, bdb_ENV, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_register(envst->envp->lg_info, dbst->dbp, StringValuePtr(a), dbst->type, &envst->fidp));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_register(envst->envp, dbst->dbp, StringValuePtr(a)));
+#else
+#if BDB_VERSION <= 30105
+ bdb_test_error(log_register(envst->envp, dbst->dbp, StringValuePtr(a), &envst->fidp));
+#else
+ bdb_test_error(log_register(envst->envp, dbst->dbp, StringValuePtr(a)));
+#endif
+#endif
+#endif
+ return obj;
+#endif
+}
+
+static VALUE
+bdb_log_unregister(VALUE obj)
+{
+#if BDB_VERSION >= 40100
+ rb_warn("log_unregister is obsolete");
+ return Qnil;
+#else
+ bdb_DB *dbst;
+ bdb_ENV *envst;
+
+ if (bdb_env_p(obj) == Qfalse) {
+ rb_raise(bdb_eFatal, "Database must be open in an Env");
+ }
+ Data_Get_Struct(obj, bdb_DB, dbst);
+ Data_Get_Struct(dbst->env, bdb_ENV, envst);
+#if BDB_VERSION < 30000
+ if (!envst->envp->lg_info) {
+ rb_raise(bdb_eFatal, "log region not open");
+ }
+ bdb_test_error(log_unregister(envst->envp->lg_info, envst->fidp));
+#else
+#if BDB_VERSION >= 40000
+ bdb_test_error(envst->envp->log_unregister(envst->envp, dbst->dbp));
+#else
+#if BDB_VERSION <= 30105
+ bdb_test_error(log_unregister(envst->envp, envst->fidp));
+#else
+ bdb_test_error(log_unregister(envst->envp, dbst->dbp));
+#endif
+#endif
+#endif
+ return obj;
+#endif
+}
+
+void bdb_init_log()
+{
+ rb_define_method(bdb_cEnv, "log_put", bdb_s_log_put, -1);
+ rb_define_method(bdb_cEnv, "log_curlsn", bdb_s_log_curlsn, 0);
+ rb_define_method(bdb_cEnv, "log_checkpoint", bdb_s_log_checkpoint, 1);
+ rb_define_method(bdb_cEnv, "log_flush", bdb_s_log_flush, -1);
+ rb_define_method(bdb_cEnv, "log_stat", bdb_env_log_stat, -1);
+ rb_define_method(bdb_cEnv, "log_archive", bdb_env_log_archive, -1);
+#if BDB_VERSION < 40000
+ rb_define_method(bdb_cEnv, "log_get", bdb_env_log_get, 1);
+#else
+ rb_define_method(bdb_cEnv, "log_cursor", bdb_env_log_cursor, 0);
+#endif
+ rb_define_method(bdb_cEnv, "log_each", bdb_env_log_each, 0);
+ rb_define_method(bdb_cEnv, "log_reverse_each", bdb_env_log_hcae, 0);
+ rb_define_method(bdb_cCommon, "log_register", bdb_log_register, 1);
+ rb_define_method(bdb_cCommon, "log_unregister", bdb_log_unregister, 0);
+ bdb_cLsn = rb_define_class_under(bdb_mDb, "Lsn", rb_cObject);
+ rb_include_module(bdb_cLsn, rb_mComparable);
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ rb_undef_alloc_func(bdb_cLsn);
+#else
+ rb_undef_method(CLASS_OF(bdb_cLsn), "allocate");
+#endif
+ rb_undef_method(CLASS_OF(bdb_cLsn), "new");
+ rb_define_method(bdb_cLsn, "env", bdb_lsn_env, 0);
+#if BDB_VERSION >= 40000
+ rb_define_method(bdb_cLsn, "log_cursor", bdb_log_cursor, 0);
+ rb_define_method(bdb_cLsn, "cursor", bdb_log_cursor, 0);
+ rb_define_method(bdb_cLsn, "log_close", bdb_log_cursor_close, 0);
+ rb_define_method(bdb_cLsn, "close", bdb_log_cursor_close, 0);
+ rb_define_method(bdb_cLsn, "log_each", bdb_log_each, 0);
+ rb_define_method(bdb_cLsn, "each", bdb_log_each, 0);
+ rb_define_method(bdb_cLsn, "log_reverse_each", bdb_log_hcae, 0);
+ rb_define_method(bdb_cLsn, "reverse_each", bdb_log_hcae, 0);
+#endif
+ rb_define_method(bdb_cLsn, "log_get", bdb_lsn_log_get, -1);
+ rb_define_method(bdb_cLsn, "get", bdb_lsn_log_get, -1);
+ rb_define_method(bdb_cLsn, "log_compare", bdb_lsn_log_compare, 1);
+ rb_define_method(bdb_cLsn, "compare", bdb_lsn_log_compare, 1);
+ rb_define_method(bdb_cLsn, "<=>", bdb_lsn_log_compare, 1);
+ rb_define_method(bdb_cLsn, "log_file", bdb_lsn_log_file, 0);
+ rb_define_method(bdb_cLsn, "file", bdb_lsn_log_file, 0);
+ rb_define_method(bdb_cLsn, "log_flush", bdb_lsn_log_flush, 0);
+ rb_define_method(bdb_cLsn, "flush", bdb_lsn_log_flush, 0);
+}
Added: packages/libdb4.3-ruby/branches/upstream/current/src/recnum.c
===================================================================
--- packages/libdb4.3-ruby/branches/upstream/current/src/recnum.c (rev 0)
+++ packages/libdb4.3-ruby/branches/upstream/current/src/recnum.c 2007-12-08 12:00:45 UTC (rev 2142)
@@ -0,0 +1,999 @@
+#include "bdb.h"
+
+static ID id_cmp;
+
+static VALUE
+bdb_recnum_init(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE *nargv;
+ VALUE array = rb_str_new2("array_base");
+ VALUE sarray = rb_str_new2("set_array_base");
+
+ if (!argc || TYPE(argv[argc - 1]) != T_HASH) {
+ nargv = ALLOCA_N(VALUE, argc + 1);
+ MEMCPY(nargv, argv, VALUE, argc);
+ nargv[argc] = rb_hash_new();
+ argv = nargv;
+ argc++;
+ }
+ rb_hash_aset(argv[argc - 1], array, INT2FIX(0));
+ if (rb_hash_aref(argv[argc - 1], sarray) != RHASH(argv[argc - 1])->ifnone) {
+ rb_hash_aset(argv[argc - 1], sarray, INT2FIX(0));
+ }
+ rb_hash_aset(argv[argc - 1], rb_str_new2("set_flags"), INT2FIX(DB_RENUMBER));
+ return bdb_init(argc, argv, obj);
+}
+
+static VALUE
+bdb_sary_subseq(VALUE obj, long beg, long len)
+{
+ VALUE ary2, a;
+ bdb_DB *dbst;
+ long i;
+
+ GetDB(obj, dbst);
+ if (beg > dbst->len) return Qnil;
+ if (beg < 0 || len < 0) return Qnil;
+
+ if (beg + len > dbst->len) {
+ len = dbst->len - beg;
+ }
+ if (len <= 0) return rb_ary_new2(0);
+
+ ary2 = rb_ary_new2(len);
+ for (i = 0; i < len; i++) {
+ a = INT2NUM(i + beg);
+ rb_ary_push(ary2, bdb_get(1, &a, obj));
+ }
+ return ary2;
+}
+
+static VALUE
+bdb_sary_entry(VALUE obj, VALUE position)
+{
+ bdb_DB *dbst;
+ long offset;
+
+ GetDB(obj, dbst);
+ if (dbst->len == 0) return Qnil;
+ offset = NUM2LONG(position);
+ if (offset < 0) {
+ offset += dbst->len;
+ }
+ if (offset < 0 || dbst->len <= offset) return Qnil;
+ position = INT2NUM(offset);
+ return bdb_get(1, &position, obj);
+}
+
+static VALUE
+bdb_sary_aref(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE arg1, arg2;
+ long beg, len;
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
+ beg = NUM2LONG(arg1);
+ len = NUM2LONG(arg2);
+ if (beg < 0) {
+ beg = dbst->len + beg;
+ }
+ return bdb_sary_subseq(obj, beg, len);
+ }
+
+ if (FIXNUM_P(arg1)) {
+ return bdb_sary_entry(obj, arg1);
+ }
+ else if (TYPE(arg1) == T_BIGNUM) {
+ rb_raise(rb_eIndexError, "index too big");
+ }
+ else {
+ switch (rb_range_beg_len(arg1, &beg, &len, dbst->len, 0)) {
+ case Qfalse:
+ break;
+ case Qnil:
+ return Qnil;
+ default:
+ return bdb_sary_subseq(obj, beg, len);
+ }
+ }
+ return bdb_sary_entry(obj, arg1);
+}
+
+static VALUE
+bdb_intern_shift_pop(VALUE obj, int depart, int len)
+{
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBC *dbcp;
+ DBT key, data;
+ int i, ret, flags;
+ db_recno_t recno;
+ VALUE res;
+
+ rb_secure(4);
+ INIT_TXN(txnid, obj, dbst);
+ MEMZERO(&key, DBT, 1);
+ INIT_RECNO(dbst, key, recno);
+ MEMZERO(&data, DBT, 1);
+ data.flags = DB_DBT_MALLOC;
+#if BDB_VERSION < 20600
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp));
+#else
+ bdb_test_error(dbst->dbp->cursor(dbst->dbp, txnid, &dbcp, 0));
+#endif
+ SET_PARTIAL(dbst, data);
+ flags = TEST_INIT_LOCK(dbst);
+ res = rb_ary_new2(len);
+ for (i = 0; i < len; i++) {
+ bdb_cache_error(dbcp->c_get(dbcp, &key, &data, depart | flags),
+ dbcp->c_close(dbcp), ret);
+ if (ret == DB_NOTFOUND) break;
+ rb_ary_push(res, bdb_test_load(obj, &data, FILTER_VALUE));
+ bdb_cache_error(dbcp->c_del(dbcp, 0), dbcp->c_close(dbcp), ret);
+ if (dbst->len > 0) dbst->len--;
+ }
+ dbcp->c_close(dbcp);
+ if (RARRAY(res)->len == 0) return Qnil;
+ else if (RARRAY(res)->len == 1) return RARRAY(res)->ptr[0];
+ else return res;
+}
+
+static void
+bdb_sary_replace(VALUE obj, VALUE beg, long len, long rpl)
+{
+ long i, j, rlen;
+ VALUE tmp[2];
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (len < 0) rb_raise(rb_eIndexError, "negative length %d", len);
+ if (beg < 0) {
+ beg += dbst->len;
+ }
+ if (beg < 0) {
+ beg -= dbst->len;
+ rb_raise(rb_eIndexError, "index %d out of array", beg);
+ }
+ if (beg + len > dbst->len) {
+ len = dbst->len - beg;
+ }
+
+ if (NIL_P(rpl)) {
+ rpl = rb_ary_new2(0);
+ }
+ else if (TYPE(rpl) != T_ARRAY) {
+ rpl = rb_ary_new3(1, rpl);
+ }
+ rlen = RARRAY(rpl)->len;
+
+ tmp[1] = Qnil;
+ if (beg >= dbst->len) {
+ for (i = dbst->len; i < beg; i++) {
+ tmp[0] = INT2NUM(i);
+ bdb_put(2, tmp, obj);
+ dbst->len++;
+ }
+ for (i = beg, j = 0; j < RARRAY(rpl)->len; i++, j++) {
+ tmp[0] = INT2NUM(i);
+ tmp[1] = RARRAY(rpl)->ptr[j];
+ bdb_put(2, tmp, obj);
+ dbst->len++;
+ }
+ }
+ else {
+ if (len < rlen) {
+ tmp[1] = Qnil;
+ for (i = dbst->len - 1; i >= (beg + len); i--) {
+ tmp[0] = INT2NUM(i);
+ tmp[1] = bdb_get(1, tmp, obj);
+ tmp[0] = INT2NUM(i + rlen - len);
+ bdb_put(2, tmp, obj);
+ }
+ dbst->len += rlen - len;
+ }
+ for (i = beg, j = 0; j < rlen; i++, j++) {
+ tmp[0] = INT2NUM(i);
+ tmp[1] = RARRAY(rpl)->ptr[j];
+ bdb_put(2, tmp, obj);
+ }
+ if (len > rlen) {
+ for (i = beg + len; i < dbst->len; i++) {
+ tmp[0] = INT2NUM(i);
+ tmp[1] = bdb_get(1, tmp, obj);
+ tmp[0] = INT2NUM(i + rlen - len);
+ bdb_put(2, tmp, obj);
+ }
+ bdb_intern_shift_pop(obj, DB_LAST, len - rlen);
+ }
+ }
+}
+
+static VALUE
+bdb_sary_aset(int argc, VALUE *argv, VALUE obj)
+{
+ long beg, len;
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (argc == 3) {
+ bdb_sary_replace(obj, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
+ return argv[2];
+ }
+ if (argc != 2) {
+ rb_raise(rb_eArgError, "wrong # of arguments(%d for 2)", argc);
+ }
+ if (FIXNUM_P(argv[0])) {
+ beg = FIX2LONG(argv[0]);
+ goto fixnum;
+ }
+ else if (rb_range_beg_len(argv[0], &beg, &len, dbst->len, 1)) {
+ bdb_sary_replace(obj, beg, len, argv[1]);
+ return argv[1];
+ }
+ if (TYPE(argv[0]) == T_BIGNUM) {
+ rb_raise(rb_eIndexError, "index too big");
+ }
+
+ beg = NUM2LONG(argv[0]);
+ fixnum:
+ if (beg < 0) {
+ beg += dbst->len;
+ if (beg < 0) {
+ rb_raise(rb_eIndexError, "index %d out of array",
+ beg - dbst->len);
+ }
+ }
+ if (beg > dbst->len) {
+ VALUE nargv[2];
+ int i;
+
+ nargv[1] = Qnil;
+ for (i = dbst->len; i < beg; i++) {
+ nargv[0] = INT2NUM(i);
+ bdb_put(2, nargv, obj);
+ dbst->len++;
+ }
+ }
+ argv[0] = INT2NUM(beg);
+ bdb_put(2, argv, obj);
+ dbst->len++;
+ return argv[1];
+}
+
+#if RUBY_VERSION_CODE >= 172
+
+static VALUE
+bdb_sary_insert(int argc, VALUE *argv, VALUE obj)
+{
+ long pos;
+
+ if (argc < 2) {
+ rb_raise(rb_eArgError, "wrong number of arguments(at least 2)");
+ }
+ pos = NUM2LONG(argv[0]);
+ if (pos == -1) {
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ pos = dbst->len;
+ }
+ else if (pos < 0) {
+ pos++;
+ }
+
+ bdb_sary_replace(obj, pos, 0, rb_ary_new4(argc-1, argv+1));
+ return obj;
+}
+
+#endif
+
+static VALUE
+bdb_sary_at(VALUE obj, VALUE pos)
+{
+ return bdb_sary_entry(obj, pos);
+}
+
+static VALUE
+bdb_sary_first(VALUE obj)
+{
+ bdb_DB *dbst;
+ VALUE tmp;
+
+ GetDB(obj, dbst);
+ tmp = INT2NUM(0);
+ return bdb_get(1, &tmp, obj);
+}
+
+static VALUE
+bdb_sary_last(VALUE obj)
+{
+ bdb_DB *dbst;
+ VALUE tmp;
+
+ GetDB(obj, dbst);
+ if (!dbst->len) return Qnil;
+ tmp = INT2NUM(dbst->len);
+ return bdb_get(1, &tmp, obj);
+}
+
+static VALUE
+bdb_sary_fetch(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE pos, ifnone;
+ bdb_DB *dbst;
+ long idx;
+
+ GetDB(obj, dbst);
+ rb_scan_args(argc, argv, "11", &pos, &ifnone);
+ idx = NUM2LONG(pos);
+
+ if (idx < 0) {
+ idx += dbst->len;
+ }
+ if (idx < 0 || dbst->len <= idx) {
+ return ifnone;
+ }
+ pos = INT2NUM(idx);
+ return bdb_get(1, &pos, obj);
+}
+
+
+static VALUE
+bdb_sary_concat(VALUE obj, VALUE y)
+{
+ bdb_DB *dbst;
+ long i;
+ VALUE tmp[2];
+
+ y = rb_convert_type(y, T_ARRAY, "Array", "to_ary");
+ GetDB(obj, dbst);
+ for (i = 0; i < RARRAY(y)->len; i++) {
+ tmp[0] = INT2NUM(dbst->len);
+ tmp[1] = RARRAY(y)->ptr[i];
+ bdb_put(2, tmp, obj);
+ dbst->len++;
+ }
+ return obj;
+}
+
+static VALUE
+bdb_sary_push(VALUE obj, VALUE y)
+{
+ bdb_DB *dbst;
+ VALUE tmp[2];
+
+ GetDB(obj, dbst);
+ tmp[0] = INT2NUM(dbst->len);
+ tmp[1] = y;
+ bdb_put(2, tmp, obj);
+ dbst->len++;
+ return obj;
+}
+
+static VALUE
+bdb_sary_push_m(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ long i;
+ VALUE tmp[2];
+
+ if (argc == 0) {
+ rb_raise(rb_eArgError, "wrong # of arguments(at least 1)");
+ }
+ if (argc > 0) {
+ GetDB(obj, dbst);
+ for (i = 0; i < argc; i++) {
+ tmp[0] = INT2NUM(dbst->len);
+ tmp[1] = argv[i];
+ bdb_put(2, tmp, obj);
+ dbst->len++;
+ }
+ }
+ return obj;
+}
+
+static VALUE
+bdb_sary_s_create(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE res;
+
+ res = rb_funcall2(obj, rb_intern("new"), 0, 0);
+ if (argc < 0) {
+ rb_raise(rb_eArgError, "negative number of arguments");
+ }
+ if (argc > 0) {
+ bdb_sary_push_m(argc, argv, res);
+ }
+ return res;
+}
+
+static VALUE
+bdb_sary_shift(VALUE obj)
+{
+ VALUE res;
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (dbst->len == 0) return Qnil;
+ res = bdb_intern_shift_pop(obj, DB_FIRST, 1);
+ return res;
+}
+
+static VALUE
+bdb_sary_pop(VALUE obj)
+{
+ VALUE res;
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (dbst->len == 0) return Qnil;
+ res = bdb_intern_shift_pop(obj, DB_LAST, 1);
+ return res;
+}
+
+static VALUE
+bdb_sary_unshift_m(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ VALUE tmp[2];
+ long i;
+
+ if (argc == 0) {
+ rb_raise(rb_eArgError, "wrong # of arguments(at least 1)");
+ }
+ if (argc > 0) {
+/* ++ */
+ GetDB(obj, dbst);
+ for (i = dbst->len - 1; i >= 0; i++) {
+ tmp[0] = INT2NUM(i);
+ tmp[1] = bdb_get(1, tmp, obj);
+ tmp[0] = INT2NUM(i + argc);
+ bdb_put(2, tmp, obj);
+ }
+ for (i = 0; i < argc; i++) {
+ tmp[0] = INT2NUM(i);
+ tmp[1] = argv[i];
+ bdb_put(2, tmp, obj);
+ dbst->len++;
+ }
+ }
+ return obj;
+}
+
+static VALUE
+bdb_sary_length(VALUE obj)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (dbst->len < 0) rb_raise(bdb_eFatal, "Invalid BDB::Recnum");
+ return INT2NUM(dbst->len);
+}
+
+static VALUE
+bdb_sary_empty_p(VALUE obj)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (dbst->len < 0) rb_raise(bdb_eFatal, "Invalid BDB::Recnum");
+ return (dbst->len)?Qfalse:Qtrue;
+}
+
+static VALUE
+bdb_sary_rindex(VALUE obj, VALUE a)
+{
+ return bdb_internal_value(obj, a, Qtrue, DB_PREV);
+}
+
+static VALUE
+bdb_sary_to_a(VALUE obj)
+{
+ return bdb_to_type(obj, rb_ary_new(), Qfalse);
+}
+
+static VALUE
+bdb_sary_reverse_m(VALUE obj)
+{
+ return bdb_to_type(obj, rb_ary_new(), Qnil);
+}
+
+static VALUE
+bdb_sary_reverse_bang(VALUE obj)
+{
+ long i, j;
+ bdb_DB *dbst;
+ VALUE tmp[2], interm;
+
+ GetDB(obj, dbst);
+ if (dbst->len <= 1) return obj;
+ i = 0;
+ j = dbst->len - 1;
+ while (i < j) {
+ tmp[0] = INT2NUM(i);
+ interm = bdb_get(1, tmp, obj);
+ tmp[0] = INT2NUM(j);
+ tmp[1] = bdb_get(1, tmp, obj);
+ tmp[0] = INT2NUM(i);
+ bdb_put(2, tmp, obj);
+ tmp[0] = INT2NUM(j);
+ tmp[1] = interm;
+ bdb_put(2, tmp, obj);
+ i++; j--;
+ }
+ return obj;
+}
+
+static VALUE
+bdb_sary_collect_bang(int argc, VALUE *argv, VALUE obj)
+{
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, Qtrue, BDB_ST_VALUE);
+}
+
+static VALUE
+bdb_sary_collect(int argc, VALUE *argv, VALUE obj)
+{
+ if (!rb_block_given_p()) {
+ return bdb_sary_to_a(obj);
+ }
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, rb_ary_new(), BDB_ST_VALUE);
+}
+
+static VALUE
+bdb_sary_select(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE result;
+ long i;
+
+ if (rb_block_given_p()) {
+ if (argc > 0) {
+ rb_raise(rb_eArgError, "wrong number arguments(%d for 0)", argc);
+ }
+ return bdb_each_kvc(argc, argv, obj, DB_NEXT, rb_ary_new(), BDB_ST_SELECT);
+ }
+#if RUBY_VERSION_CODE >= 180
+ rb_warn("Recnum#select(index..) is deprecated; use Recnum#values_at");
+#endif
+ result = rb_ary_new();
+ for (i = 0; i < argc; i++) {
+ rb_ary_push(result, bdb_sary_fetch(1, argv + i, obj));
+ }
+ return result;
+}
+
+static VALUE
+bdb_sary_values_at(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE result;
+ long i;
+
+ result = rb_ary_new();
+ for (i = 0; i < argc; i++) {
+ rb_ary_push(result, bdb_sary_fetch(1, argv + i, obj));
+ }
+ return result;
+}
+
+static VALUE
+bdb_sary_indexes(int argc, VALUE *argv, VALUE obj)
+{
+#if RUBY_VERSION_CODE >= 172
+ rb_warn("Recnum#%s is deprecated; use Recnum#values_at",
+ rb_id2name(rb_frame_last_func()));
+#endif
+ return bdb_sary_values_at(argc, argv, obj);
+}
+
+static VALUE
+bdb_sary_filter(int argc, VALUE *argv, VALUE obj)
+{
+ rb_warn("BDB::Recnum#filter is deprecated; use BDB::Recnum#collect!");
+ return bdb_sary_collect_bang(argc, argv, obj);
+}
+
+static VALUE
+bdb_sary_delete(VALUE obj, VALUE item)
+{
+ bdb_DB *dbst;
+ long i1, i2;
+ VALUE tmp, a;
+
+ GetDB(obj, dbst);
+ i2 = dbst->len;
+ for (i1 = 0; i1 < dbst->len;) {
+ tmp = INT2NUM(i1);
+ a = bdb_get(1, &tmp, obj);
+ if (rb_equal(a, item)) {
+ bdb_del(obj, INT2NUM(i1));
+ dbst->len--;
+ }
+ else {
+ i1++;
+ }
+ }
+ if (dbst->len == i2) {
+ if (rb_block_given_p()) {
+ return rb_yield(item);
+ }
+ return Qnil;
+ }
+ return item;
+}
+
+static VALUE
+bdb_sary_delete_at_m(VALUE obj, VALUE a)
+{
+ bdb_DB *dbst;
+ long pos;
+ VALUE tmp;
+ VALUE del = Qnil;
+
+ GetDB(obj, dbst);
+ pos = NUM2INT(a);
+ if (pos >= dbst->len) return Qnil;
+ if (pos < 0) pos += dbst->len;
+ if (pos < 0) return Qnil;
+
+ tmp = INT2NUM(pos);
+ del = bdb_get(1, &tmp, obj);
+ bdb_del(obj, tmp);
+ dbst->len--;
+ return del;
+}
+
+static VALUE
+bdb_sary_reject_bang(VALUE obj)
+{
+ bdb_DB *dbst;
+ long i1, i2;
+ VALUE tmp, a;
+
+ GetDB(obj, dbst);
+ i2 = dbst->len;
+ for (i1 = 0; i1 < dbst->len;) {
+ tmp = INT2NUM(i1);
+ a = bdb_get(1, &tmp, obj);
+ if (!RTEST(rb_yield(a))) {
+ i1++;
+ continue;
+ }
+ bdb_del(obj, tmp);
+ dbst->len--;
+ }
+ if (dbst->len == i2) return Qnil;
+ return obj;
+}
+
+static VALUE
+bdb_sary_delete_if(VALUE obj)
+{
+ bdb_sary_reject_bang(obj);
+ return obj;
+}
+
+static VALUE
+bdb_sary_replace_m(VALUE obj, VALUE obj2)
+{
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ obj2 = rb_convert_type(obj2, T_ARRAY, "Array", "to_ary");
+ bdb_sary_replace(obj, 0, dbst->len, obj2);
+ return obj;
+}
+
+static VALUE
+bdb_sary_clear(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_DB *dbst;
+ VALUE g;
+ int flags = 0;
+
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ VALUE f = argv[argc - 1];
+ if ((g = rb_hash_aref(f, rb_intern("flags"))) != RHASH(f)->ifnone ||
+ (g = rb_hash_aref(f, rb_str_new2("flags"))) != RHASH(f)->ifnone) {
+ flags = NUM2INT(g);
+ }
+ argc--;
+ }
+ if (argc == 1) {
+ flags = NUM2INT(argv[0]);
+ }
+ g = INT2FIX(flags);
+ bdb_clear(1, &g, obj);
+ GetDB(obj, dbst);
+ dbst->len = 0;
+ return obj;
+}
+
+static VALUE
+bdb_sary_fill(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE item, arg1, arg2, tmp[2];
+ long beg, len, i;
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ rb_scan_args(argc, argv, "12", &item, &arg1, &arg2);
+ switch (argc) {
+ case 1:
+ len = dbst->len;
+ beg = 0;
+ break;
+ case 2:
+ if (rb_range_beg_len(arg1, &beg, &len, dbst->len, 1)) {
+ break;
+ }
+ /* fall through */
+ case 3:
+ beg = NIL_P(arg1)?0:NUM2LONG(arg1);
+ if (beg < 0) {
+ beg += dbst->len;
+ if (beg < 0) beg = 0;
+ }
+ len = NIL_P(arg2)?dbst->len - beg:NUM2LONG(arg2);
+ break;
+ }
+ tmp[1] = item;
+ for (i = 0; i < len; i++) {
+ tmp[0] = INT2NUM(i + beg);
+ bdb_put(2, tmp, obj);
+ if ((i + beg) >= dbst->len) dbst->len++;
+ }
+ return obj;
+}
+
+static VALUE
+bdb_sary_cmp(VALUE obj, VALUE obj2)
+{
+ bdb_DB *dbst, *dbst2 = 0;
+ VALUE a, a2, tmp, ary;
+ long i, len;
+
+ if (obj == obj2) return INT2FIX(0);
+ GetDB(obj, dbst);
+ len = dbst->len;
+ if (!rb_obj_is_kind_of(obj2, bdb_cRecnum)) {
+ obj2 = rb_convert_type(obj2, T_ARRAY, "Array", "to_ary");
+ if (len > RARRAY(obj2)->len) {
+ len = RARRAY(obj2)->len;
+ }
+ ary = Qtrue;
+ }
+ else {
+ GetDB(obj2, dbst2);
+ len = dbst->len;
+ if (len > dbst2->len) {
+ len = dbst2->len;
+ }
+ ary = Qfalse;
+ }
+ for (i = 0; i < len; i++) {
+ tmp = INT2NUM(i);
+ a = bdb_get(1, &tmp, obj);
+ if (ary) {
+ a2 = RARRAY(obj2)->ptr[i];
+ }
+ else {
+ a2 = bdb_get(1, &tmp, obj2);
+ }
+ tmp = rb_funcall(a, id_cmp, 1, a2);
+ if (tmp != INT2FIX(0)) {
+ return tmp;
+ }
+ }
+ len = dbst->len - ary?RARRAY(obj2)->len:dbst2->len;
+ if (len == 0) return INT2FIX(0);
+ if (len > 0) return INT2FIX(1);
+ return INT2FIX(-1);
+}
+
+static VALUE
+bdb_sary_slice_bang(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE arg1, arg2;
+ long pos, len;
+ bdb_DB *dbst;
+
+ GetDB(obj, dbst);
+ if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) {
+ pos = NUM2LONG(arg1);
+ len = NUM2LONG(arg2);
+ delete_pos_len:
+ if (pos < 0) {
+ pos = dbst->len + pos;
+ }
+ arg2 = bdb_sary_subseq(obj, pos, len);
+ bdb_sary_replace(obj, pos, len, Qnil);
+ return arg2;
+ }
+
+ if (!FIXNUM_P(arg1) && rb_range_beg_len(arg1, &pos, &len, dbst->len, 1)) {
+ goto delete_pos_len;
+ }
+
+ pos = NUM2LONG(arg1);
+ if (pos >= dbst->len) return Qnil;
+ if (pos < 0) pos += dbst->len;
+ if (pos < 0) return Qnil;
+
+ arg1 = INT2NUM(pos);
+ arg2 = bdb_sary_at(obj, arg1);
+ if (bdb_del(obj, arg1) != Qnil) dbst->len--;
+ return arg2;
+}
+
+static VALUE
+bdb_sary_plus(VALUE obj, VALUE y)
+{
+ return rb_ary_plus(bdb_sary_to_a(obj), y);
+}
+
+static VALUE
+bdb_sary_times(VALUE obj, VALUE y)
+{
+ return rb_funcall(bdb_sary_to_a(obj), rb_intern("*"), 1, y);
+}
+
+static VALUE
+bdb_sary_diff(VALUE obj, VALUE y)
+{
+ return rb_funcall(bdb_sary_to_a(obj), rb_intern("-"), 1, y);
+}
+
+static VALUE
+bdb_sary_and(VALUE obj, VALUE y)
+{
+ return rb_funcall(bdb_sary_to_a(obj), rb_intern("&"), 1, y);
+}
+
+static VALUE
+bdb_sary_or(VALUE obj, VALUE y)
+{
+ return rb_funcall(bdb_sary_to_a(obj), rb_intern("|"), 1, y);
+}
+
+static VALUE
+bdb_sary_compact(VALUE obj)
+{
+ return rb_funcall(bdb_sary_to_a(obj), rb_intern("compact!"), 0, 0);
+}
+
+static VALUE
+bdb_sary_compact_bang(VALUE obj)
+{
+ bdb_DB *dbst;
+ long i, j;
+ VALUE tmp;
+
+ GetDB(obj, dbst);
+ j = dbst->len;
+ for (i = 0; i < dbst->len; ) {
+ tmp = INT2NUM(i);
+ tmp = bdb_get(1, &tmp, obj);
+ if (NIL_P(tmp)) {
+ bdb_del(obj, INT2NUM(i));
+ dbst->len--;
+ }
+ else {
+ i++;
+ }
+ }
+ if (dbst->len == j) return Qnil;
+ return obj;
+}
+
+static VALUE
+bdb_sary_nitems(VALUE obj)
+{
+ bdb_DB *dbst;
+ long i, j;
+ VALUE tmp;
+
+ GetDB(obj, dbst);
+ j = 0;
+ for (i = 0; i < dbst->len; ) {
+ tmp = INT2NUM(i);
+ tmp = bdb_get(1, &tmp, obj);
+ if (!NIL_P(tmp)) j++;
+ }
+ return INT2NUM(j);
+}
+
+void bdb_init_recnum()
+{
+ id_cmp = rb_intern("<=>");
+ bdb_cRecnum = rb_define_class_under(bdb_mDb, "Recnum", bdb_cCommon);
+ rb_define_singleton_method(bdb_cRecnum, "[]", bdb_sary_s_create, -1);
+ rb_define_private_method(bdb_cRecnum, "initialize", bdb_recnum_init, -1);
+ rb_define_method(bdb_cRecnum, "[]", bdb_sary_aref, -1);
+ rb_define_method(bdb_cRecnum, "get", bdb_sary_aref, -1);
+ rb_define_method(bdb_cRecnum, "db_get", bdb_sary_aref, -1);
+ rb_define_method(bdb_cRecnum, "[]=", bdb_sary_aset, -1);
+ rb_define_method(bdb_cRecnum, "put", bdb_sary_aset, -1);
+ rb_define_method(bdb_cRecnum, "db_put", bdb_sary_aset, -1);
+ rb_define_method(bdb_cRecnum, "store", bdb_sary_aset, -1);
+ rb_define_method(bdb_cRecnum, "at", bdb_sary_at, 1);
+ rb_define_method(bdb_cRecnum, "fetch", bdb_sary_fetch, -1);
+ rb_define_method(bdb_cRecnum, "first", bdb_sary_first, 0);
+ rb_define_method(bdb_cRecnum, "last", bdb_sary_last, 0);
+ rb_define_method(bdb_cRecnum, "concat", bdb_sary_concat, 1);
+ rb_define_method(bdb_cRecnum, "<<", bdb_sary_push, 1);
+ rb_define_method(bdb_cRecnum, "push", bdb_sary_push_m, -1);
+ rb_define_method(bdb_cRecnum, "pop", bdb_sary_pop, 0);
+ rb_define_method(bdb_cRecnum, "shift", bdb_sary_shift, 0);
+ rb_define_method(bdb_cRecnum, "unshift", bdb_sary_unshift_m, -1);
+#if RUBY_VERSION_CODE >= 172
+ rb_define_method(bdb_cRecnum, "insert", bdb_sary_insert, -1);
+#endif
+ rb_define_method(bdb_cRecnum, "each", bdb_each_value, -1);
+ rb_define_method(bdb_cRecnum, "each_index", bdb_each_key, -1);
+ rb_define_method(bdb_cRecnum, "reverse_each", bdb_each_eulav, -1);
+ rb_define_method(bdb_cRecnum, "length", bdb_sary_length, 0);
+ rb_define_alias(bdb_cRecnum, "size", "length");
+ rb_define_method(bdb_cRecnum, "empty?", bdb_sary_empty_p, 0);
+ rb_define_method(bdb_cRecnum, "index", bdb_index, 1);
+ rb_define_method(bdb_cRecnum, "rindex", bdb_sary_rindex, 1);
+ rb_define_method(bdb_cRecnum, "indexes", bdb_sary_indexes, -1);
+ rb_define_method(bdb_cRecnum, "indices", bdb_sary_indexes, -1);
+ rb_define_method(bdb_cRecnum, "reverse", bdb_sary_reverse_m, 0);
+ rb_define_method(bdb_cRecnum, "reverse!", bdb_sary_reverse_bang, 0);
+ rb_define_method(bdb_cRecnum, "collect", bdb_sary_collect, -1);
+ rb_define_method(bdb_cRecnum, "collect!", bdb_sary_collect_bang, -1);
+#if RUBY_VERSION_CODE >= 172
+ rb_define_method(bdb_cRecnum, "map", bdb_sary_collect, 0);
+ rb_define_method(bdb_cRecnum, "select", bdb_sary_select, -1);
+ rb_define_method(bdb_cRecnum, "values_at", bdb_sary_values_at, -1);
+#endif
+ rb_define_method(bdb_cRecnum, "map!", bdb_sary_collect_bang, -1);
+ rb_define_method(bdb_cRecnum, "filter", bdb_sary_filter, -1);
+ rb_define_method(bdb_cRecnum, "delete", bdb_sary_delete, 1);
+ rb_define_method(bdb_cRecnum, "delete_at", bdb_sary_delete_at_m, 1);
+ rb_define_method(bdb_cRecnum, "delete_if", bdb_sary_delete_if, 0);
+ rb_define_method(bdb_cRecnum, "reject!", bdb_sary_reject_bang, 0);
+ rb_define_method(bdb_cRecnum, "replace", bdb_sary_replace_m, 1);
+ rb_define_method(bdb_cRecnum, "clear", bdb_sary_clear, -1);
+ rb_define_method(bdb_cRecnum, "fill", bdb_sary_fill, -1);
+ rb_define_method(bdb_cRecnum, "include?", bdb_has_value, 1);
+ rb_define_method(bdb_cRecnum, "<=>", bdb_sary_cmp, 1);
+ rb_define_method(bdb_cRecnum, "slice", bdb_sary_aref, -1);
+ rb_define_method(bdb_cRecnum, "slice!", bdb_sary_slice_bang, -1);
+/*
+ rb_define_method(bdb_cRecnum, "assoc", bdb_sary_assoc, 1);
+ rb_define_method(bdb_cRecnum, "rassoc", bdb_sary_rassoc, 1);
+*/
+ rb_define_method(bdb_cRecnum, "+", bdb_sary_plus, 1);
+ rb_define_method(bdb_cRecnum, "*", bdb_sary_times, 1);
+
+ rb_define_method(bdb_cRecnum, "-", bdb_sary_diff, 1);
+ rb_define_method(bdb_cRecnum, "&", bdb_sary_and, 1);
+ rb_define_method(bdb_cRecnum, "|", bdb_sary_or, 1);
+
+/*
+ rb_define_method(bdb_cRecnum, "uniq", bdb_sary_uniq, 0);
+ rb_define_method(bdb_cRecnum, "uniq!", bdb_sary_uniq_bang, 0);
+*/
+ rb_define_method(bdb_cRecnum, "compact", bdb_sary_compact, 0);
+ rb_define_method(bdb_cRecnum, "compact!", bdb_sary_compact_bang, 0);
+/*
+ rb_define_method(bdb_cRecnum, "flatten", bdb_sary_flatten, 0);
+ rb_define_method(bdb_cRecnum, "flatten!", bdb_sary_flatten_bang, 0);
+*/
+ rb_define_method(bdb_cRecnum, "nitems", bdb_sary_nitems, 0);
+ rb_define_method(bdb_cRecnum, "stat", bdb_tree_stat, -1);
+ rb_define_method(bdb_cRecnum, "to_a", bdb_sary_to_a, 0);
+ rb_define_method(bdb_cRecnum, "to_ary", bdb_sary_to_a, 0);
+ /* RECNO */
+ rb_define_method(bdb_cRecno, "shift", bdb_sary_shift, 0);
+ rb_define_method(bdb_cRecno, "to_a", bdb_sary_to_a, 0);
+ rb_define_method(bdb_cRecno, "to_ary", bdb_sary_to_a, 0);
+ rb_define_method(bdb_cRecno, "pop", bdb_sary_pop, 0);
+ /* QUEUE */
+#if BDB_VERSION >= 30000
+ rb_define_method(bdb_cQueue, "to_a", bdb_sary_to_a, 0);
+ rb_define_method(bdb_cQueue, "to_ary", bdb_sary_to_a, 0);
+#endif
+}
Added: packages/libdb4.3-ruby/branches/upstream/current/src/sequence.c
===================================================================
--- packages/libdb4.3-ruby/branches/upstream/current/src/sequence.c (rev 0)
+++ packages/libdb4.3-ruby/branches/upstream/current/src/sequence.c 2007-12-08 12:00:45 UTC (rev 2142)
@@ -0,0 +1,332 @@
+#include "bdb.h"
+
+#if BDB_VERSION >= 40300
+
+static VALUE bdb_cSeq;
+
+static void
+bdb_seq_free(bdb_SEQ *seqst)
+{
+ if (seqst->seqp) {
+ seqst->seqp->close(seqst->seqp, 0);
+ seqst->seqp = NULL;
+ }
+ free(seqst);
+}
+
+static void
+bdb_seq_mark(bdb_SEQ *seqst)
+{
+ rb_gc_mark(seqst->db);
+ rb_gc_mark(seqst->txn);
+ rb_gc_mark(seqst->orig);
+}
+
+static VALUE
+bdb_seq_close(VALUE obj)
+{
+ bdb_SEQ *seqst;
+
+ GetSEQ(obj, seqst);
+ seqst->seqp->close(seqst->seqp, 0);
+ seqst->seqp = NULL;
+ return Qnil;
+}
+
+static VALUE
+bdb_seq_txn_dup(VALUE obj, VALUE a)
+{
+ bdb_SEQ *seq0, *seq1;
+ bdb_TXN *txnst;
+ VALUE res;
+
+ GetSEQ(obj, seq0);
+ GetTxnDB(a, txnst);
+ res = Data_Make_Struct(obj, bdb_SEQ, bdb_seq_mark, bdb_seq_free, seq1);
+ MEMCPY(seq1, seq0, bdb_SEQ, 1);
+ seq1->txn = a;
+ seq1->txnid = txnst->txnid;
+ seq1->orig = obj;
+ return res;
+}
+
+static VALUE
+bdb_seq_txn_close(VALUE obj, VALUE commit, VALUE real)
+{
+ bdb_SEQ *seqst;
+
+ if (!real) {
+ Data_Get_Struct(obj, bdb_SEQ, seqst);
+ seqst->seqp = NULL;
+ }
+ else {
+ bdb_seq_close(obj);
+ }
+ return Qnil;
+}
+
+static VALUE
+bdb_seq_i_options(VALUE obj, VALUE seqobj)
+{
+ VALUE key, value;
+ bdb_SEQ *seqst;
+ char *options;
+
+ key = rb_ary_entry(obj, 0);
+ value = rb_ary_entry(obj, 1);
+ key = rb_obj_as_string(key);
+ options = StringValuePtr(key);
+ Data_Get_Struct(seqobj, bdb_SEQ, seqst);
+ if (strcmp(options, "set_cachesize") == 0) {
+ if (seqst->seqp->set_cachesize(seqst->seqp, NUM2INT(value))) {
+ seqst->seqp->remove(seqst->seqp, 0, 0);
+ rb_raise(rb_eArgError, "Invalid value (%d) for set_cachesize",
+ NUM2INT(value));
+ }
+ }
+ else if (strcmp(options, "set_flags") == 0) {
+ if (seqst->seqp->set_flags(seqst->seqp, NUM2INT(value))) {
+ seqst->seqp->remove(seqst->seqp, 0, 0);
+ rb_raise(rb_eArgError, "Invalid value (%d) for set_flags",
+ NUM2INT(value));
+ }
+ }
+ else if (strcmp(options, "set_range") == 0) {
+ Check_Type(value, T_ARRAY);
+ if (RARRAY(value)->len != 2) {
+ rb_raise(bdb_eFatal, "expected 2 values for range");
+ }
+ if (seqst->seqp->set_range(seqst->seqp,
+ NUM2LONG(RARRAY(value)->ptr[0]),
+ NUM2LONG(RARRAY(value)->ptr[1]))) {
+ seqst->seqp->remove(seqst->seqp, 0, 0);
+ rb_raise(rb_eArgError, "Invalid value (%d, %d) for set_range",
+ NUM2LONG(RARRAY(value)->ptr[0]),
+ NUM2LONG(RARRAY(value)->ptr[1]));
+ }
+ }
+ else {
+ rb_warning("Unknown option %s", options);
+ }
+ return Qnil;
+}
+
+static VALUE
+bdb_seq_open(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE a, b, c, res;
+ int flags = 0, count;
+ bdb_DB *dbst;
+ DB_TXN *txnid;
+ DBT key;
+ db_seq_t value;
+ db_recno_t recno;
+ bdb_SEQ *seqst;
+ VALUE options = Qnil;
+
+ INIT_TXN(txnid, obj, dbst);
+ res = Data_Make_Struct(bdb_cSeq, bdb_SEQ, bdb_seq_mark, bdb_seq_free, seqst);
+ seqst->db = obj;
+ if (argc && TYPE(argv[argc - 1]) == T_HASH) {
+ options = argv[argc - 1];
+ argc--;
+ }
+ count = rb_scan_args(argc, argv, "12", &a, &b, &c);
+ bdb_test_error(db_sequence_create(&seqst->seqp, dbst->dbp, 0));
+ switch (count) {
+ case 3:
+ value = NUM2LONG(c);
+ if (seqst->seqp->initial_value(seqst->seqp, value)) {
+ seqst->seqp->remove(seqst->seqp, 0, 0);
+ rb_raise(rb_eArgError, "invalid initial value");
+ }
+ /* ... */
+ case 2:
+ if (!NIL_P(flags)) {
+ flags = NUM2INT(b);
+ }
+ break;
+ }
+ if (!NIL_P(options)) {
+ rb_iterate(rb_each, options, bdb_seq_i_options, res);
+ }
+ a = bdb_test_recno(obj, &key, &recno, a);
+ if (seqst->seqp->open(seqst->seqp, txnid, &key, flags)) {
+ seqst->seqp->remove(seqst->seqp, txnid, 0);
+ rb_raise(rb_eArgError, "can't open the sequence");
+ }
+ seqst->txn = dbst->txn;
+ seqst->txnid = txnid;
+ if (rb_block_given_p()) {
+ return rb_ensure(rb_yield, res, bdb_seq_close, res);
+ }
+ return res;
+}
+
+static VALUE
+bdb_seq_s_open(int argc, VALUE *argv, VALUE obj)
+{
+ VALUE args[4];
+
+ if (argc <= 0 || argc > 3) {
+ rb_raise(rb_eArgError, "Invalid number of arguments %d", argc);
+ }
+ args[0] = argv[0];
+ args[1] = INT2NUM(DB_CREATE | DB_EXCL);
+ if (argc > 1) {
+ args[2] = argv[1];
+ if (argc > 2) {
+ args[3] = argv[2];
+ }
+ }
+ return bdb_seq_open(argc + 1, args, obj);
+}
+
+
+static VALUE
+bdb_seq_remove(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_SEQ *seqst;
+ VALUE a;
+ int flags = 0;
+
+ GetSEQ(obj, seqst);
+ if (rb_scan_args(argc, argv, "01", &a)) {
+ flags = NUM2INT(a);
+ }
+ if (seqst->seqp->remove(seqst->seqp, seqst->txnid, flags)) {
+ rb_raise(rb_eArgError, "invalid argument");
+ }
+ seqst->seqp = NULL;
+ return Qnil;
+}
+
+static VALUE
+bdb_seq_get(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_SEQ *seqst;
+ int delta = 1, flags = 0;
+ VALUE a, b;
+ db_seq_t val;
+
+ GetSEQ(obj, seqst);
+ switch (rb_scan_args(argc, argv, "02", &a, &b)) {
+ case 2:
+ flags = NUM2INT(b);
+ /* ... */
+ case 1:
+ delta = NUM2INT(a);
+ }
+ bdb_test_error(seqst->seqp->get(seqst->seqp, seqst->txnid, delta, &val, flags));
+ return LONG2NUM(val);
+}
+
+static VALUE
+bdb_seq_cachesize(VALUE obj)
+{
+
+ bdb_SEQ *seqst;
+ int size;
+
+ GetSEQ(obj, seqst);
+ bdb_test_error(seqst->seqp->get_cachesize(seqst->seqp, &size));
+ return INT2NUM(size);
+}
+
+static VALUE
+bdb_seq_flags(VALUE obj)
+{
+
+ bdb_SEQ *seqst;
+ unsigned int flags;
+
+ GetSEQ(obj, seqst);
+ bdb_test_error(seqst->seqp->get_flags(seqst->seqp, &flags));
+ return INT2NUM(flags);
+}
+
+static VALUE
+bdb_seq_range(VALUE obj)
+{
+ bdb_SEQ *seqst;
+ db_seq_t deb, fin;
+
+ GetSEQ(obj, seqst);
+ bdb_test_error(seqst->seqp->get_range(seqst->seqp, &deb, &fin));
+ return rb_assoc_new(LONG2NUM(deb), LONG2NUM(fin));
+}
+
+static VALUE
+bdb_seq_stat(int argc, VALUE *argv, VALUE obj)
+{
+ bdb_SEQ *seqst;
+ int flags = 0;
+ VALUE a, res;
+ DB_SEQUENCE_STAT sta;
+
+ GetSEQ(obj, seqst);
+ if (rb_scan_args(argc, argv, "01", &a)) {
+ flags = NUM2INT(a);
+ }
+ bdb_test_error(seqst->seqp->stat(seqst->seqp, (void *)&sta, flags));
+ res = rb_hash_new();
+ rb_hash_aset(res, rb_str_new2("wait"), INT2NUM(sta.st_wait));
+ rb_hash_aset(res, rb_str_new2("nowait"), INT2NUM(sta.st_nowait));
+ rb_hash_aset(res, rb_str_new2("current"), INT2NUM(sta.st_current));
+ rb_hash_aset(res, rb_str_new2("value"), INT2NUM(sta.st_value));
+ rb_hash_aset(res, rb_str_new2("last_value"), INT2NUM(sta.st_last_value));
+ rb_hash_aset(res, rb_str_new2("min"), INT2NUM(sta.st_min));
+ rb_hash_aset(res, rb_str_new2("max"), INT2NUM(sta.st_max));
+ rb_hash_aset(res, rb_str_new2("cache_size"), INT2NUM(sta.st_cache_size));
+ rb_hash_aset(res, rb_str_new2("flags"), INT2NUM(sta.st_flags));
+ return res;
+}
+
+static VALUE
+bdb_seq_db(VALUE obj)
+{
+ bdb_SEQ *seqst;
+
+ GetSEQ(obj, seqst);
+ return seqst->db;
+}
+
+static VALUE
+bdb_seq_key(VALUE obj)
+{
+ bdb_SEQ *seqst;
+ DBT key;
+
+ GetSEQ(obj, seqst);
+ bdb_test_error(seqst->seqp->get_key(seqst->seqp, &key));
+ return bdb_test_load_key(seqst->db, &key);
+}
+
+#endif
+
+void bdb_init_sequence()
+{
+#if BDB_VERSION >= 40300
+ bdb_cSeq = rb_define_class_under(bdb_mDb, "Sequence", rb_cObject);
+#ifdef HAVE_RB_DEFINE_ALLOC_FUNC
+ rb_undef_alloc_func(bdb_cSeq);
+#else
+ rb_undef_method(CLASS_OF(bdb_cSeq), "allocate");
+#endif
+ rb_undef_method(CLASS_OF(bdb_cSeq), "new");
+ rb_define_method(bdb_cCommon, "open_sequence", bdb_seq_open, -1);
+ rb_define_method(bdb_cCommon, "create_sequence", bdb_seq_s_open, -1);
+ rb_define_method(bdb_cSeq, "get", bdb_seq_get, -1);
+ rb_define_method(bdb_cSeq, "stat", bdb_seq_stat, -1);
+ rb_define_method(bdb_cSeq, "close", bdb_seq_close, 0);
+ rb_define_method(bdb_cSeq, "remove", bdb_seq_remove, -1);
+ rb_define_method(bdb_cSeq, "range", bdb_seq_range, 0);
+ rb_define_method(bdb_cSeq, "cachesize", bdb_seq_cachesize, 0);
+ rb_define_method(bdb_cSeq, "flags", bdb_seq_flags, 0);
+ rb_define_method(bdb_cSeq, "db", bdb_seq_db, 0);
+ rb_define_method(bdb_cSeq, "key", bdb_seq_key, 0);
+ rb_define_private_method(bdb_cSeq, "__txn_close__", bdb_seq_txn_close, 2);
+ rb_define_private_method(bdb_cSeq, "__txn_dup__", bdb_seq_txn_dup, 1);
+#endif
+}
+
More information about the Pkg-ruby-extras-commits
mailing list