From 24d712840e58a1082377ba419aa86475df5d684e Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Tue, 9 Dec 2008 13:46:33 -0700 Subject: [PATCH] Adding support for not_found on get and txn abort --- c_src/bdberl_drv.c | 34 ++++++++++++++++++++++++---------- src/bdberl_port.erl | 20 ++++++++++++++++++-- test/port_SUITE.erl | 24 +++++++++++++++++------- 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/c_src/bdberl_drv.c b/c_src/bdberl_drv.c index 4019281..cc18983 100644 --- a/c_src/bdberl_drv.c +++ b/c_src/bdberl_drv.c @@ -24,7 +24,7 @@ static void do_async_put(void* arg); static void do_async_put_free(void* arg); static void do_async_get(void* arg); static void do_async_get_free(void* arg); -static void do_async_commit(void* arg); +static void do_async_txnop(void* arg); static int add_dbref(PortData* data, int dbref); static int del_dbref(PortData* data, int dbref); @@ -260,6 +260,7 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd, RETURN_INT(rc, outbuf); } case CMD_TXN_COMMIT: + case CMD_TXN_ABORT: { // If an async operation is pending, fail if (d->async_op != CMD_NONE) @@ -278,11 +279,11 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd, adata->port = d; // Update port data to indicate we have an operation in progress - d->async_op = CMD_TXN_COMMIT; + d->async_op = cmd; - // Schedule async operation to execute the commit + // Schedule async operation to execute the commit/abort unsigned int key = (unsigned int)d->port; - driver_async(d->port, &key, &do_async_commit, adata, 0); + driver_async(d->port, &key, &do_async_txnop, adata, 0); // Outbuf is <> RETURN_INT(0, outbuf); @@ -382,8 +383,8 @@ static void bdberl_drv_ready_async(ErlDrvData handle, ErlDrvThreadData thread_da } case CMD_GET: { - // Extract return code == if it's zero, send back {ok, Payload} to driver process; otherwise - // send a {error, Reason} tuple + // Extract return code == if it's zero, send back {ok, Payload} or not_found to driver + // process; otherwise send a {error, Reason} tuple AsyncData* adata = (AsyncData*)thread_data; if (adata->rc == 0) { @@ -392,6 +393,12 @@ static void bdberl_drv_ready_async(ErlDrvData handle, ErlDrvThreadData thread_da ERL_DRV_TUPLE, 2}; driver_output_term(d->port, response, sizeof(response) / sizeof(response[0])); } + else if (adata->rc == DB_NOTFOUND) + { + printf("not foudn\n"); + ErlDrvTermData response[] = { ERL_DRV_ATOM, driver_mk_atom("not_found") }; + driver_output_term(d->port, response, sizeof(response) / sizeof(response[0])); + } else { ErlDrvTermData response[] = { ERL_DRV_ATOM, driver_mk_atom("error"), @@ -639,13 +646,20 @@ static void do_async_get_free(void* arg) } -static void do_async_commit(void* arg) +static void do_async_txnop(void* arg) { - printf("do_async_commit\n"); + printf("do_async_txnop\n"); - // Execute the actual commit + // Execute the actual commit/abort AsyncData* adata = (AsyncData*)arg; - adata->rc = adata->port->txn->commit(adata->port->txn, 0); + if (adata->port->async_op == CMD_TXN_COMMIT) + { + adata->rc = adata->port->txn->commit(adata->port->txn, 0); + } + else + { + adata->rc = adata->port->txn->abort(adata->port->txn); + } } diff --git a/src/bdberl_port.erl b/src/bdberl_port.erl index 5a965f1..5810059 100644 --- a/src/bdberl_port.erl +++ b/src/bdberl_port.erl @@ -9,7 +9,7 @@ -export([new/0, open_database/3, close_database/2, - txn_begin/1, txn_commit/1, + txn_begin/1, txn_commit/1, txn_abort/1, put/4, get/3]). @@ -37,7 +37,10 @@ -define(ERROR_NO_TXN, -29004). % No transaction open on this port new() -> - ok = erl_ddll:load_driver(code:priv_dir(bdberl), bdberl_drv), + case erl_ddll:load_driver(code:priv_dir(bdberl), bdberl_drv) of + ok -> ok; + {error, permanent} -> ok % Means that the driver is already active + end, Port = open_port({spawn, bdberl_drv}, [binary]), {ok, Port}. @@ -84,6 +87,18 @@ txn_commit(Port) -> ?ERROR_ASYNC_PENDING -> {error, async_pending}; ?ERROR_NO_TXN -> {error, no_txn} end. + +txn_abort(Port) -> + <> = erlang:port_control(Port, ?CMD_TXN_ABORT, <<>>), + case Result of + ?ERROR_NONE -> + receive + ok -> ok; + {error, Reason} -> {error, Reason} + end; + ?ERROR_ASYNC_PENDING -> {error, async_pending}; + ?ERROR_NO_TXN -> {error, no_txn} + end. put(Port, DbRef, Key, Value) -> @@ -110,6 +125,7 @@ get(Port, DbRef, Key) -> ?ERROR_NONE -> receive {ok, Bin} -> {ok, binary_to_term(Bin)}; + not_found -> not_found; {error, Reason} -> {error, Reason} end; ?ERROR_ASYNC_PENDING -> {error, async_pending}; diff --git a/test/port_SUITE.erl b/test/port_SUITE.erl index 6f2ce30..f674d83 100644 --- a/test/port_SUITE.erl +++ b/test/port_SUITE.erl @@ -10,7 +10,7 @@ all() -> % [test_db]. - [test_put]. + [test_put, test_txn]. init_per_testcase(TestCase, Config) -> Config. @@ -52,18 +52,28 @@ test_put(_Config) -> {ok, 0} = bdberl_port:open_database(P, "test1", hash), ok = bdberl_port:txn_begin(P), - ok = bdberl_port:put(P, 0, akey, avalue), - ok = bdberl_port:txn_commit(P), - ok = bdberl_port:txn_begin(P), - - {ok, avalue} = bdberl_port:get(P, 0, akey), - + ok = bdberl_port:txn_begin(P), + {ok, avalue} = bdberl_port:get(P, 0, akey), ok = bdberl_port:txn_commit(P). +test_txn(_Config) -> + {ok, P} = bdberl_port:new(), + {ok, 0} = bdberl_port:open_database(P, "test2", btree), + + ok = bdberl_port:txn_begin(P), + ok = bdberl_port:put(P, 0, akey, avalue), + ok = bdberl_port:txn_abort(P), + + ok = bdberl_port:txn_begin(P), + not_found = bdberl_port:get(P, 0, akey), + ok = bdberl_port:txn_commit(P). + + +