database: Add support for serializable transactions

This commit is contained in:
Tobias Brunner
2013-10-11 15:29:10 +02:00
parent e745f5f69f
commit b283a6e9ef
4 changed files with 27 additions and 9 deletions
+7 -2
View File
@@ -115,6 +115,10 @@ struct database_t {
/** /**
* Start a transaction. * Start a transaction.
* *
* A serializable transaction forces a strict separation between other
* transactions. Due to the performance overhead they should only be used
* in certain situations (e.g. SELECT->INSERT|UPDATE).
*
* @note Either commit() or rollback() has to be called to end the * @note Either commit() or rollback() has to be called to end the
* transaction. * transaction.
* @note Transactions are thread-specific. So commit()/rollbak() has to be * @note Transactions are thread-specific. So commit()/rollbak() has to be
@@ -124,9 +128,10 @@ struct database_t {
* not supported. So if any if the "inner" transactions are rolled back * not supported. So if any if the "inner" transactions are rolled back
* the outer most transaction is rolled back. * the outer most transaction is rolled back.
* *
* @return TRUE on success * @param serializable TRUE to create a serializable transaction
* @return TRUE on success
*/ */
bool (*transaction)(database_t *this); bool (*transaction)(database_t *this, bool serializable);
/** /**
* Commit all changes made during the current transaction. * Commit all changes made during the current transaction.
@@ -652,7 +652,7 @@ METHOD(database_t, execute, int,
} }
METHOD(database_t, transaction, bool, METHOD(database_t, transaction, bool,
private_mysql_database_t *this) private_mysql_database_t *this, bool serializable)
{ {
transaction_t *trans = NULL; transaction_t *trans = NULL;
conn_t *conn; conn_t *conn;
@@ -669,6 +669,17 @@ METHOD(database_t, transaction, bool,
} }
/* these statements are not supported in prepared statements that are used /* these statements are not supported in prepared statements that are used
* by the execute() method */ * by the execute() method */
if (serializable)
{
if (mysql_query(conn->mysql,
"SET TRANSACTION ISOLATION LEVEL SERIALIZABLE") != 0)
{
DBG1(DBG_LIB, "starting transaction failed: %s",
mysql_error(conn->mysql));
conn_release(this, conn);
return FALSE;
}
}
if (mysql_query(conn->mysql, "START TRANSACTION") != 0) if (mysql_query(conn->mysql, "START TRANSACTION") != 0)
{ {
DBG1(DBG_LIB, "starting transaction failed: %s", DBG1(DBG_LIB, "starting transaction failed: %s",
@@ -305,9 +305,11 @@ METHOD(database_t, execute, int,
} }
METHOD(database_t, transaction, bool, METHOD(database_t, transaction, bool,
private_sqlite_database_t *this) private_sqlite_database_t *this, bool serializable)
{ {
transaction_t *trans; transaction_t *trans;
char *cmd = serializable ? "BEGIN EXCLUSIVE TRANSACTION"
: "BEGIN TRANSACTION";
trans = this->transaction->get(this->transaction); trans = this->transaction->get(this->transaction);
if (trans) if (trans)
@@ -315,7 +317,7 @@ METHOD(database_t, transaction, bool,
ref_get(&trans->refs); ref_get(&trans->refs);
return TRUE; return TRUE;
} }
if (execute(this, NULL, "BEGIN EXCLUSIVE TRANSACTION") == -1) if (execute(this, NULL, cmd) == -1)
{ {
return FALSE; return FALSE;
} }
+4 -4
View File
@@ -335,7 +335,7 @@ static void add(char *name, host_t *start, host_t *end, int timeout)
id = create_pool(name, start_addr, end_addr, timeout); id = create_pool(name, start_addr, end_addr, timeout);
printf("allocating %d addresses... ", count); printf("allocating %d addresses... ", count);
fflush(stdout); fflush(stdout);
db->transaction(db); db->transaction(db, FALSE);
while (TRUE) while (TRUE)
{ {
db->execute(db, NULL, db->execute(db, NULL,
@@ -413,7 +413,7 @@ static void add_addresses(char *pool, char *path, int timeout)
host_t *addr; host_t *addr;
FILE *file; FILE *file;
db->transaction(db); db->transaction(db, FALSE);
addr = host_create_from_string("%any", 0); addr = host_create_from_string("%any", 0);
pool_id = create_pool(pool, addr->get_address(addr), pool_id = create_pool(pool, addr->get_address(addr),
@@ -559,7 +559,7 @@ static void resize(char *name, host_t *end)
} }
DESTROY_IF(old_end); DESTROY_IF(old_end);
db->transaction(db); db->transaction(db, FALSE);
if (db->execute(db, NULL, if (db->execute(db, NULL,
"UPDATE pools SET end = ? WHERE name = ?", "UPDATE pools SET end = ? WHERE name = ?",
DB_BLOB, new_addr, DB_TEXT, name) <= 0) DB_BLOB, new_addr, DB_TEXT, name) <= 0)
@@ -862,7 +862,7 @@ static void batch(char *argv0, char *name)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
db->transaction(db); db->transaction(db, FALSE);
while (fgets(command, sizeof(command), file)) while (fgets(command, sizeof(command), file))
{ {
char *argv[ARGV_SIZE], *start; char *argv[ARGV_SIZE], *start;