--- BDB/BDB.xs 2007/02/05 20:21:38 1.2 +++ BDB/BDB.xs 2007/02/05 22:19:07 1.3 @@ -43,19 +43,27 @@ #endif typedef SV SV8; /* byte-sv, used for argument-checking */ +typedef char *octetstring; -enum +static SV *prepare_cb; + +static inline char * +strdup_ornull (const char *s) { + return s ? strdup (s) : 0; +} + +enum { REQ_QUIT, REQ_ENV_OPEN, REQ_ENV_CLOSE, - REQ_DB_OPEN, REQ_DB_CLOSE, + REQ_DB_OPEN, REQ_DB_CLOSE, REQ_DB_COMPACT, REQ_DB_SYNC, REQ_DB_PUT, }; typedef struct aio_cb { struct aio_cb *volatile next; SV *callback; - int type, pri, errorno; + int type, pri, result; DB_ENV *env; DB *db; @@ -64,6 +72,8 @@ int int1, int2; U32 uint1, uint2; char *buf1, *buf2; + + DBT dbt1, dbt2, dbt3; } aio_cb; typedef aio_cb *aio_req; @@ -256,6 +266,8 @@ { } + errno = req->result; + PUTBACK; call_sv (req->callback, G_VOID | G_EVAL); SPAGAIN; @@ -274,7 +286,7 @@ Safefree (req); } -static void *aio_proc(void *arg); +static void *aio_proc (void *arg); static void start_thread (void) { @@ -326,6 +338,25 @@ static void req_send (aio_req req) { + SV *wait_callback = 0; + + // synthesize callback if none given + if (!SvOK (req->callback)) + { + dSP; + PUSHMARK (SP); + PUTBACK; + int count = call_sv (prepare_cb, G_ARRAY); + SPAGAIN; + + if (count != 2) + croak ("prepare callback must return exactly two values\n"); + + wait_callback = SvREFCNT_inc (POPs); + SvREFCNT_dec (req->callback); + req->callback = SvREFCNT_inc (POPs); + } + ++nreqs; LOCK (reqlock); @@ -335,6 +366,15 @@ UNLOCK (reqlock); maybe_start_thread (); + + if (wait_callback) + { + dSP; + PUSHMARK (SP); + PUTBACK; + call_sv (wait_callback, G_DISCARD); + SvREFCNT_dec (wait_callback); + } } static void end_thread (void) @@ -539,20 +579,44 @@ UNLOCK (reqlock); - errno = 0; /* strictly unnecessary */ - switch (req->type) { case REQ_QUIT: goto quit; + case REQ_ENV_OPEN: + req->result = req->env->open (req->env, req->buf1, req->uint1, req->int1); + break; + + case REQ_ENV_CLOSE: + req->result = req->env->close (req->env, req->uint1); + break; + + case REQ_DB_OPEN: + req->result = req->db->open (req->db, req->txn, req->buf1, req->buf2, req->int1, req->uint1, req->int2); + break; + + case REQ_DB_CLOSE: + req->result = req->db->close (req->db, req->uint1); + break; + + case REQ_DB_COMPACT: + req->result = req->db->compact (req->db, req->txn, &req->dbt1, &req->dbt2, 0, req->uint1, 0); + break; + + case REQ_DB_SYNC: + req->result = req->db->sync (req->db, req->uint1); + break; + + case REQ_DB_PUT: + req->result = req->db->put (req->db, req->txn, &req->dbt1, &req->dbt2, req->uint1); + break; + default: - //req->result = ENOSYS; + req->result = ENOSYS; break; } - //req->errorno = errno; - LOCK (reslock); ++npending; @@ -653,7 +717,18 @@ (var) = INT2PTR (type, tmp); \ } \ else \ - Perl_croak (# var " is not of type " # type) + Perl_croak (# var " is not of type " # class) + +inline void +set_dbt (DBT *dbt, SV *sv) +{ + STRLEN len; + char *data = SvPVbyte (sv, len); + + dbt->data = malloc (len); + memcpy (dbt->data, data, len); + dbt->size = len; +} MODULE = BDB PACKAGE = BDB @@ -736,6 +811,19 @@ const_iv (LOCK_DEADLOCK) const_iv (LOCK_NOTGRANTED) const_iv (RUNRECOVERY) + const_iv (OLD_VERSION) + const_iv (REP_HANDLE_DEAD) + const_iv (REP_LOCKOUT) + + const_iv (FREE_SPACE) + const_iv (FREELIST_ONLY) + + const_iv (APPEND) + const_iv (NODUPDATA) + const_iv (NOOVERWRITE) + + const_iv (SET_LOCK_TIMEOUT) + const_iv (SET_TXN_TIMEOUT) }; for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ-- > const_iv; ) @@ -781,7 +869,7 @@ RETVAL int -bdbreq_pri (int pri = 0) +dbreq_pri (int pri = 0) PROTOTYPE: ;$ CODE: RETVAL = next_pri - PRI_BIAS; @@ -795,7 +883,7 @@ RETVAL void -bdbreq_nice (int nice = 0) +dbreq_nice (int nice = 0) CODE: nice = next_pri - nice; if (nice < PRI_MIN) nice = PRI_MIN; @@ -813,7 +901,7 @@ } int -poll() +poll () PROTOTYPE: CODE: poll_wait (); @@ -822,7 +910,7 @@ RETVAL int -poll_fileno() +poll_fileno () PROTOTYPE: CODE: RETVAL = respipe [0]; @@ -830,7 +918,7 @@ RETVAL int -poll_cb(...) +poll_cb (...) PROTOTYPE: CODE: RETVAL = poll_cb (); @@ -838,13 +926,13 @@ RETVAL void -poll_wait() +poll_wait () PROTOTYPE: CODE: poll_wait (); int -nreqs() +nreqs () PROTOTYPE: CODE: RETVAL = nreqs; @@ -852,7 +940,7 @@ RETVAL int -nready() +nready () PROTOTYPE: CODE: RETVAL = get_nready (); @@ -860,7 +948,7 @@ RETVAL int -npending() +npending () PROTOTYPE: CODE: RETVAL = get_npending (); @@ -868,7 +956,7 @@ RETVAL int -nthreads() +nthreads () PROTOTYPE: CODE: if (WORDACCESS_UNSAFE) LOCK (wrklock); @@ -877,29 +965,38 @@ OUTPUT: RETVAL +void +set_sync_prepare (SV *cb) + PROTOTYPE: & + CODE: + SvREFCNT_dec (prepare_cb); + prepare_cb = newSVsv (cb); + DB_ENV * -bdb_env_create (U32 env_flags = 0) +db_env_create (U32 env_flags = 0) CODE: { - int err = db_env_create (&RETVAL, env_flags); - if (err) - croak ("db_env_create: %s", db_strerror (err)); + errno = db_env_create (&RETVAL, env_flags); + if (errno) + croak ("db_env_create: %s", db_strerror (errno)); } + OUTPUT: + RETVAL void -bdb_env_open (DB_ENV *env, char *db_home, U32 open_flags, int mode, SV *callback = 0) +db_env_open (DB_ENV *env, octetstring db_home, U32 open_flags, int mode, SV *callback = &PL_sv_undef) CODE: { dREQ (REQ_ENV_OPEN); req->env = env; - req->uint1 = open_flags; + req->uint1 = open_flags | DB_THREAD; req->int1 = mode; - req->buf1 = strdup (db_home); + req->buf1 = strdup_ornull (db_home); REQ_SEND; } void -bdb_env_close (DB_ENV *env, U32 flags = 0, SV *callback = 0) +db_env_close (DB_ENV *env, U32 flags = 0, SV *callback = &PL_sv_undef) CODE: { dREQ (REQ_ENV_CLOSE); @@ -909,31 +1006,33 @@ } DB * -bdb_db_create (DB_ENV *env = 0, U32 flags = 0) +db_create (DB_ENV *env = 0, U32 flags = 0) CODE: { - int err = db_create (&RETVAL, env, flags); - if (err) - croak ("db_env_create: %s", db_strerror (err)); + errno = db_create (&RETVAL, env, flags); + if (errno) + croak ("db_env_create: %s", db_strerror (errno)); } + OUTPUT: + RETVAL void -bdb_db_open (DB *db, DB_TXN *txnid, const char *file, const char *database, int type, U32 flags, int mode, SV *callback = 0) +db_open (DB *db, DB_TXN *txnid, octetstring file, octetstring database, int type, U32 flags, int mode, SV *callback = &PL_sv_undef) CODE: { dREQ (REQ_DB_OPEN); req->db = db; req->txn = txnid; - req->buf1 = strdup (file); - req->buf2 = strdup (database); + req->buf1 = strdup_ornull (file); + req->buf2 = strdup_ornull (database); req->int1 = type; - req->uint1 = flags; + req->uint1 = flags | DB_THREAD; req->int2 = mode; REQ_SEND; } void -bdb_db_close (DB *db, U32 flags = 0, SV *callback = 0) +db_close (DB *db, U32 flags = 0, SV *callback = &PL_sv_undef) CODE: { dREQ (REQ_DB_CLOSE); @@ -942,40 +1041,143 @@ REQ_SEND; } +void +db_compact (DB *db, DB_TXN *txn = 0, SV *start = 0, SV *stop = 0, SV *unused1 = 0, U32 flags = DB_FREE_SPACE, SV *unused2 = 0, SV *callback = &PL_sv_undef) + CODE: +{ + dREQ (REQ_DB_COMPACT); + req->db = db; + req->txn = txn; + set_dbt (&req->dbt1, start); + set_dbt (&req->dbt2, stop); + req->uint1 = flags; + REQ_SEND; +} + +void +db_sync (DB *db, U32 flags = 0, SV *callback = &PL_sv_undef) + CODE: +{ + dREQ (REQ_DB_SYNC); + req->db = db; + req->uint1 = flags; + REQ_SEND; +} + +void +db_put (DB *db, DB_TXN *txn, SV *key, SV *data, U32 flags = 0, SV *callback = &PL_sv_undef) + CODE: +{ + dREQ (REQ_DB_PUT); + req->db = db; + req->txn = 0; + set_dbt (&req->dbt1, key); + set_dbt (&req->dbt2, data); + req->uint1 = flags; + REQ_SEND; +} + MODULE = BDB PACKAGE = BDB::Env int set_cachesize (DB_ENV *env, U32 gbytes, U32 bytes, int ncache = 0) + CODE: + RETVAL = env->set_cachesize (env, gbytes, bytes, ncache); + OUTPUT: + RETVAL int set_flags (DB_ENV *env, U32 flags, int onoff) + CODE: + RETVAL = env->set_flags (env, flags, onoff); + OUTPUT: + RETVAL + +int set_encrypt (DB_ENV *env, const char *password, U32 flags = 0) + CODE: + RETVAL = env->set_encrypt (env, password, flags); + OUTPUT: + RETVAL + +int set_timeout (DB_ENV *env, NV timeout, U32 flags) + CODE: + RETVAL = env->set_timeout (env, timeout * 1000000, flags); + OUTPUT: + RETVAL -int set_encrypt (DB_ENV *env, const char *password, U32 flags) MODULE = BDB PACKAGE = BDB::Db int set_cachesize (DB *db, U32 gbytes, U32 bytes, int ncache = 0) + CODE: + RETVAL = db->set_cachesize (db, gbytes, bytes, ncache); + OUTPUT: + RETVAL -int set_flags (DB *env, U32 flags, int onoff) +int set_flags (DB *db, U32 flags); + CODE: + RETVAL = db->set_flags (db, flags); + OUTPUT: + RETVAL int set_encrypt (DB *db, const char *password, U32 flags) + CODE: + RETVAL = db->set_encrypt (db, password, flags); + OUTPUT: + RETVAL int set_lorder (DB *db, int lorder) + CODE: + RETVAL = db->set_lorder (db, lorder); + OUTPUT: + RETVAL int set_bt_minkey (DB *db, U32 minkey) + CODE: + RETVAL = db->set_bt_minkey (db, minkey); + OUTPUT: + RETVAL int set_re_delim(DB *db, int delim); + CODE: + RETVAL = db->set_re_delim (db, delim); + OUTPUT: + RETVAL int set_re_pad (DB *db, int re_pad) + CODE: + RETVAL = db->set_re_pad (db, re_pad); + OUTPUT: + RETVAL int set_re_source (DB *db, char *source) + CODE: + RETVAL = db->set_re_source (db, source); + OUTPUT: + RETVAL int set_re_len (DB *db, U32 re_len) + CODE: + RETVAL = db->set_re_len (db, re_len); + OUTPUT: + RETVAL int set_h_ffactor (DB *db, U32 h_ffactor) + CODE: + RETVAL = db->set_h_ffactor (db, h_ffactor); + OUTPUT: + RETVAL int set_h_nelem (DB *db, U32 h_nelem) + CODE: + RETVAL = db->set_h_nelem (db, h_nelem); + OUTPUT: + RETVAL int set_q_extentsize (DB *db, U32 extentsize) + CODE: + RETVAL = db->set_q_extentsize (db, extentsize); + OUTPUT: + RETVAL