diff --git a/c_src/bdberl_drv.c b/c_src/bdberl_drv.c index eff05f1..7b7f22f 100644 --- a/c_src/bdberl_drv.c +++ b/c_src/bdberl_drv.c @@ -621,8 +621,10 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd, // Make sure this port currently has dbref open -- if it doesn't, error out. Of note, // if it's in our list, we don't need to grab the RWLOCK, as we don't have to worry about // the underlying handle disappearing since we have a reference. - if (has_dbref(d, dbref)) + if (dbref == -1 || has_dbref(d, dbref)) { + memcpy(d->work_buffer, inbuf, inbuf_sz); + // Mark the port as busy and then schedule the appropriate async operation d->async_op = cmd; d->async_pool = G_TPOOL_GENERAL; @@ -1110,12 +1112,42 @@ static void do_async_truncate(void* arg) // Get the database reference and flags from the payload int dbref = UNPACK_INT(d->work_buffer, 0); - DB* db = G_DATABASES[dbref].db; + int rc = 0; - DBG("Truncating dbref %i\r\n", dbref); + if (dbref == -1) + { + DBG("Truncating all open databases...\r\n"); - u_int32_t count = 0; - int rc = db->truncate(db, d->txn, &count, 0); + // Iterate over the whole database list skipping null entries + int i = 0; // I hate C + for ( ; i < G_DATABASES_SIZE; ++i) + { + Database* database = &G_DATABASES[i]; + if (database != NULL && database->db != 0) + { + DB* db = database->db; + + DBG("Truncating dbref %i\r\n", i); + + u_int32_t count = 0; + rc = db->truncate(db, d->txn, &count, 0); + + if (rc != 0) + { + break; + } + } + } + } + else + { + DB* db = G_DATABASES[dbref].db; + + DBG("Truncating dbref %i\r\n", dbref); + + u_int32_t count = 0; + rc = db->truncate(db, d->txn, &count, 0); + } // If any error occurs while we have a txn action, abort it if (d->txn && rc) diff --git a/src/bdberl.erl b/src/bdberl.erl index 9167270..770858a 100644 --- a/src/bdberl.erl +++ b/src/bdberl.erl @@ -20,7 +20,7 @@ get/2, get/3, get_r/2, get_r/3, update/3, update/4, - truncate/1, + truncate/0, truncate/1, delete_database/1, cursor_open/1, cursor_next/0, cursor_prev/0, cursor_current/0, cursor_close/0]). @@ -210,6 +210,9 @@ update(Db, Key, Fun, Args) -> end, transaction(F). +truncate() -> + truncate(-1). + truncate(Db) -> Cmd = <>, <> = erlang:port_control(get_port(), ?CMD_TRUNCATE, Cmd), diff --git a/test/bdberl_SUITE.erl b/test/bdberl_SUITE.erl index 6e517e3..e2ebd2a 100644 --- a/test/bdberl_SUITE.erl +++ b/test/bdberl_SUITE.erl @@ -29,7 +29,8 @@ all() -> data_dir_should_be_priv_dir, delete_should_remove_file, delete_should_fail_if_db_inuse, - truncate_should_empty_database]. + truncate_should_empty_database, + truncate_all_should_empty_all_databases]. dbconfig(Config) -> @@ -219,3 +220,9 @@ truncate_should_empty_database(Config) -> ok = bdberl:put(Db, mykey, avalue), ok = bdberl:truncate(Db), not_found = bdberl:get(Db, mykey). + +truncate_all_should_empty_all_databases(Config) -> + Db = ?config(db, Config), + ok = bdberl:put(Db, mykey, avalue), + ok = bdberl:truncate(), + not_found = bdberl:get(Db, mykey).