database: Add support for serializable transactions
This commit is contained in:
@@ -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
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user