From 22f33e0b0d9a7688aa480d68b6f998b46dba90bb Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Thu, 16 Apr 2009 07:08:22 -0600 Subject: [PATCH] Adding support for registering a logger port/pid to capture BDB messages --- c_src/bdberl_drv.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ c_src/bdberl_drv.h | 2 +- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/c_src/bdberl_drv.c b/c_src/bdberl_drv.c index f1d5b46..52fe573 100644 --- a/c_src/bdberl_drv.c +++ b/c_src/bdberl_drv.c @@ -50,6 +50,9 @@ static void* deadlock_check(void* arg); static void* trickle_write(void* arg); static void* txn_checkpoint(void* arg); +static void bdb_errcall(const DB_ENV* dbenv, const char* errpfx, const char* msg); +static void bdb_msgcall(const DB_ENV* dbenv, const char* msg); + /** * Global instance of DB_ENV; only a single one exists per O/S process. */ @@ -117,6 +120,15 @@ static unsigned int G_CHECKPOINT_INTERVAL = 60 * 60; /* Seconds between checkpoi */ static int G_BDBERL_PIPE[2] = {-1, -1}; +/** + * Lock, port and pid reference for relaying BDB output into the SASL logger. READ lock + * is required to log data. WRITE lock is used when replacing the pid/port reference. If + * no pid/port is available, no callback is registered with BDB. + */ +static ErlDrvRWLock* G_LOG_RWLOCK = 0; +static ErlDrvTermData G_LOG_PID; +static ErlDrvPort G_LOG_PORT; + /** * */ @@ -277,6 +289,11 @@ DRIVER_INIT(bdberl_drv) // TODO: Make configurable/adjustable G_TPOOL_GENERAL = bdberl_tpool_start(10); G_TPOOL_TXNS = bdberl_tpool_start(10); + + // Initialize logging lock and refs + G_LOG_RWLOCK = erl_drv_rwlock_create("bdberl_drv: G_LOG_RWLOCK"); + G_LOG_PORT = 0; + G_LOG_PID = 0; } return &bdberl_drv_entry; @@ -358,6 +375,24 @@ static void bdberl_drv_stop(ErlDrvData handle) close_database(d->dbrefs->dbref, 0, d); } + // If this port was registered as the endpoint for logging, go ahead and + // remove it. Note that we don't need to lock to check this since we only + // unregister if it's already initialized to this port. + if (G_LOG_PORT == d->port) + { + WRITE_LOCK(G_LOG_RWLOCK); + + // Remove the references + G_LOG_PORT = 0; + G_LOG_PID = 0; + + // Unregister with BDB -- MUST DO THIS WITH WRITE LOCK HELD! + G_DB_ENV->set_msgcall(G_DB_ENV, 0); + G_DB_ENV->set_errcall(G_DB_ENV, 0); + + WRITE_UNLOCK(G_LOG_RWLOCK); + } + DBG("Stopped port: %p\r\n", d->port); // Release the port instance data @@ -400,6 +435,9 @@ static void bdberl_drv_finish() erl_drv_rwlock_destroy(G_DATABASES_RWLOCK); hive_hash_destroy(G_DATABASES_NAMES); + // Release the logging rwlock + erl_drv_rwlock_destroy(G_LOG_RWLOCK); + DBG("DRIVER_FINISH\n"); } @@ -693,6 +731,25 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd, RETURN_INT(ERROR_INVALID_DBREF, outbuf); } } + case CMD_REGISTER_LOGGER: + { + // If this port is not the current logger, make it so. Only one logger can be registered + // at a time. + if (G_LOG_PORT != d->port) + { + // Grab the write lock and update the global vars; also make sure to update BDB callbacks + // within the write lock to avoid race conditions. + WRITE_LOCK(G_LOG_RWLOCK); + + G_LOG_PORT = d->port; + G_LOG_PID = driver_connected(d->port); + + G_DB_ENV->set_msgcall(G_DB_ENV, &bdb_msgcall); + G_DB_ENV->set_errcall(G_DB_ENV, &bdb_errcall); + + WRITE_UNLOCK(G_LOG_RWLOCK); + } + } } *outbuf = 0; return 0; @@ -1532,3 +1589,30 @@ static void* txn_checkpoint(void* arg) DBG("Checkpointer exiting.\r\n"); return 0; } + +static void bdb_errcall(const DB_ENV* dbenv, const char* errpfx, const char* msg) +{ + READ_LOCK(G_LOG_RWLOCK); + if (G_LOG_PORT) + { + ErlDrvTermData response[] = { ERL_DRV_ATOM, driver_mk_atom("bdb_error_log"), + ERL_DRV_STRING, (ErlDrvTermData)msg, (ErlDrvUInt)strlen(msg), + ERL_DRV_TUPLE, 2}; + driver_send_term(G_LOG_PORT, G_LOG_PID, response, sizeof(response) / sizeof(response[0])); + } + READ_UNLOCK(G_LOG_RWLOCK); +} + +static void bdb_msgcall(const DB_ENV* dbenv, const char* msg) +{ + printf("msgcall: %s\n", msg); + READ_LOCK(G_LOG_RWLOCK); + if (G_LOG_PORT) + { + ErlDrvTermData response[] = { ERL_DRV_ATOM, driver_mk_atom("bdb_info_log"), + ERL_DRV_STRING, (ErlDrvTermData)msg, (ErlDrvUInt)strlen(msg), + ERL_DRV_TUPLE, 2}; + driver_send_term(G_LOG_PORT, G_LOG_PID, response, sizeof(response) / sizeof(response[0])); + } + READ_UNLOCK(G_LOG_RWLOCK); +} diff --git a/c_src/bdberl_drv.h b/c_src/bdberl_drv.h index 46611f1..a3388d7 100644 --- a/c_src/bdberl_drv.h +++ b/c_src/bdberl_drv.h @@ -45,7 +45,7 @@ static int bdberl_drv_control(ErlDrvData handle, unsigned int cmd, #define CMD_PUT_COMMIT 14 #define CMD_REMOVE_DB 15 #define CMD_TRUNCATE 16 - +#define CMD_REGISTER_LOGGER 17 /** * Command status values