Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add functions to handle BEGIN/COMMIT/ROLLBACK or SAVEPOINT/RELEASE/ROLLBACK TO
Matthew Seaman committed 13 years ago
commit cce74a163d19548eb63173453f19bae7917303e8
parent 0193087
4 files changed +145 -18
modified libpkg/pkg_jobs.c
@@ -165,7 +165,8 @@ pkg_jobs_install(struct pkg_jobs *j)

	p = NULL;
	/* Install */
-
	sql_exec(j->db->sqlite, "SAVEPOINT upgrade;");
+
	pkgdb_transaction_begin(j->db->sqlite, "upgrade");
+

	while (pkg_jobs(j, &p) == EPKG_OK) {
		const char *pkgorigin, *pkgrepopath, *newversion, *origin;
		bool automatic;
@@ -248,7 +249,7 @@ pkg_jobs_install(struct pkg_jobs *j)
			flags |= PKG_ADD_AUTOMATIC;

		if (pkg_add(j->db, path, flags) != EPKG_OK) {
-
			sql_exec(j->db->sqlite, "ROLLBACK TO upgrade;");
+
			pkgdb_transaction_rollback(j->db->sqlite, "upgrade");
			goto cleanup;
		}

@@ -258,15 +259,15 @@ pkg_jobs_install(struct pkg_jobs *j)
			pkg_emit_install_finished(newpkg);

		if (STAILQ_EMPTY(&pkg_queue)) {
-
			sql_exec(j->db->sqlite, "RELEASE upgrade;");
-
			sql_exec(j->db->sqlite, "SAVEPOINT upgrade;");
+
			pkgdb_transaction_commit(j->db->sqlite, "upgrade");
+
			pkgdb_transaction_begin(j->db->sqlite, "upgrade");
		}
	}

	retcode = EPKG_OK;

	cleanup:
-
	sql_exec(j->db->sqlite, "RELEASE upgrade;");
+
	pkgdb_transaction_commit(j->db->sqlite, "upgrade");
	pkg_free(newpkg);

	return (retcode);
modified libpkg/pkg_repo.c
@@ -419,7 +419,7 @@ initialize_repo(const char *repodb, bool force, sqlite3 **sqlite)
			return (retcode);
	}

-
	if ((retcode = sql_exec(*sqlite, "BEGIN TRANSACTION")) != EPKG_OK)
+
	if ((retcode = pkgdb_transaction_begin(*sqlite, NULL)) != EPKG_OK)
		return (retcode);

	/* remove anything that is no longer in the repository. */
@@ -793,10 +793,8 @@ pkg_create_repo(char *path, bool force,
		free(r);
	}

-
	if (sqlite3_exec(sqlite, "COMMIT;", NULL, NULL, &errmsg) != SQLITE_OK) {
-
		pkg_emit_error("sqlite: %s", errmsg);
+
	if (pkgdb_transaction_commit(sqlite, NULL) != SQLITE_OK)
		retcode = EPKG_FATAL;
-
	}

	cleanup:

modified libpkg/pkgdb.c
@@ -422,18 +422,22 @@ pkgdb_upgrade(struct pkgdb *db)
			return (EPKG_FATAL);
		}

-
		if (sql_exec(db->sqlite, "BEGIN;") != EPKG_OK)
+
		if (pkgdb_transaction_begin(db->sqlite, NULL) != EPKG_OK)
			return (EPKG_FATAL);

-
		if (sql_exec(db->sqlite, sql_upgrade) != EPKG_OK)
+
		if (sql_exec(db->sqlite, sql_upgrade) != EPKG_OK) {
+
			pkgdb_transaction_rollback(db->sqlite, NULL);
			return (EPKG_FATAL);
+
		}

		sql_str = "PRAGMA user_version = %" PRId64 ";";
		ret = sql_exec(db->sqlite, sql_str, db_version);
-
		if (ret != EPKG_OK)
+
		if (ret != EPKG_OK) {
+
			pkgdb_transaction_rollback(db->sqlite, NULL);
			return (EPKG_FATAL);
+
		}

-
		if (sql_exec(db->sqlite, "COMMIT;") != EPKG_OK)
+
		if (pkgdb_transaction_commit(db->sqlite, NULL) != EPKG_OK)
			return (EPKG_FATAL);
	}

@@ -852,6 +856,118 @@ pkgdb_close(struct pkgdb *db)
	free(db);
}

+
/* How many times to try COMMIT or ROLLBACK if the DB is busy */ 
+
#define NTRIES	3
+

+
int
+
pkgdb_transaction_begin(sqlite3 *sqlite, const char *savepoint)
+
{
+
	int		 ret;
+
	sqlite3_stmt	*stmt;
+

+
	assert(sqlite != NULL);
+

+
	if (savepoint == NULL || savepoint[0] == '\0') {
+
		const char sql[] = "BEGIN IMMEDIATE TRANSACTION";
+
		
+
		ret = sqlite3_prepare_v2(sqlite, sql, sizeof(sql), &stmt, NULL);
+
	} else {
+
		const char sql[] = "SAVEPOINT ?1";
+

+
		ret = sqlite3_prepare_v2(sqlite, sql, sizeof(sql), &stmt, NULL);
+
		if (ret == SQLITE_OK) 
+
			ret = sqlite3_bind_text(stmt, 1, savepoint, -1,
+
						SQLITE_STATIC);
+
	}
+

+
	if (ret == SQLITE_OK)
+
		ret = sqlite3_step(stmt);
+

+
	sqlite3_finalize(stmt);
+

+
	if (ret != SQLITE_OK && ret != SQLITE_DONE)
+
		ERROR_SQLITE(sqlite);
+

+
	return (ret == SQLITE_OK || ret == SQLITE_DONE ? EPKG_OK : EPKG_FATAL);
+
}
+

+
int
+
pkgdb_transaction_commit(sqlite3 *sqlite, const char *savepoint)
+
{
+
	int		 ret;
+
	int		 tries;
+
	sqlite3_stmt	*stmt;
+

+
	assert(sqlite != NULL);
+

+
	if (savepoint == NULL || savepoint[0] == '\0') {
+
		const char sql[] = "COMMIT TRANSACTION";
+

+
		ret = sqlite3_prepare_v2(sqlite, sql, sizeof(sql), &stmt, NULL);
+
	} else {
+
		const char sql[] = "ROLLBACK TO SAVEPOINT ?1";
+

+
		ret = sqlite3_prepare_v2(sqlite, sql, sizeof(sql), &stmt, NULL);
+
		if (ret == SQLITE_OK) 
+
			ret = sqlite3_bind_text(stmt, 1, savepoint, -1,
+
						SQLITE_STATIC);
+
	}
+

+
	if (ret == SQLITE_OK)
+
		for (tries = 0; tries < NTRIES; tries++) {
+
			ret = sqlite3_step(stmt);
+
			if (ret != SQLITE_BUSY)
+
				break;
+
			sqlite3_sleep(250);
+
		}
+

+
	sqlite3_finalize(stmt);
+

+
	if (ret != SQLITE_OK && ret != SQLITE_DONE)
+
		ERROR_SQLITE(sqlite);
+

+
	return (ret == SQLITE_OK || ret == SQLITE_DONE ? EPKG_OK : EPKG_FATAL);
+
}
+

+
int
+
pkgdb_transaction_rollback(sqlite3 *sqlite, const char *savepoint)
+
{
+
	int		 ret;
+
	int		 tries;
+
	sqlite3_stmt	*stmt;
+

+
	assert(sqlite != NULL);
+

+
	if (savepoint == NULL || savepoint[0] == '\0') {
+
		const char sql[] = "ROLLBACK TRANSACTION";
+

+
		ret = sqlite3_prepare_v2(sqlite, sql, sizeof(sql), &stmt, NULL);
+
	} else {
+
		const char sql[] = "RELEASE SAVEPOINT ?1";
+

+
		ret = sqlite3_prepare_v2(sqlite, sql, sizeof(sql), &stmt, NULL);
+
		if (ret == SQLITE_OK) 
+
			ret = sqlite3_bind_text(stmt, 1, savepoint, -1,
+
						SQLITE_STATIC);
+
	}
+

+
	if (ret == SQLITE_OK)
+
		for (tries = 0; tries < NTRIES; tries++) {
+
			ret = sqlite3_step(stmt);
+
			if (ret != SQLITE_BUSY)
+
				break;
+
			sqlite3_sleep(250);
+
		}
+

+
	sqlite3_finalize(stmt);
+

+
	if (ret != SQLITE_OK && ret != SQLITE_DONE)
+
		ERROR_SQLITE(sqlite);
+

+
	return (ret == SQLITE_OK || ret == SQLITE_DONE ? EPKG_OK : EPKG_FATAL);
+
}
+

+

static struct pkgdb_it *
pkgdb_it_new(struct pkgdb *db, sqlite3_stmt *s, int type)
{
@@ -1806,7 +1922,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int complete)

	s = db->sqlite;

-
	if (!complete && sql_exec(s, "BEGIN;") != EPKG_OK)
+
	if (!complete && pkgdb_transaction_begin(s, NULL) != EPKG_OK)
		return (EPKG_FATAL);

	pkg_get(pkg,
@@ -2109,13 +2225,14 @@ pkgdb_reanalyse_shlibs(struct pkgdb *db, struct pkg *pkg)
int
pkgdb_register_finale(struct pkgdb *db, int retcode)
{
-
	int		 ret = EPKG_OK;
-
	const char	*cmd;
+
	int	ret = EPKG_OK;

	assert(db != NULL);

-
	cmd = (retcode == EPKG_OK) ? "COMMIT;" : "ROLLBACK;";
-
	ret = sql_exec(db->sqlite, cmd);
+
	if (retcode == EPKG_OK) 
+
		ret = pkgdb_transaction_commit(db->sqlite, NULL);
+
	else
+
		ret = pkgdb_transaction_rollback(db->sqlite, NULL);

	return (ret);
}
modified libpkg/private/pkgdb.h
@@ -45,6 +45,17 @@ struct pkgdb_it {
	int		 type;
};

+

+
/**
+
 * Transaction/savepoint handling.
+
 * @param savepoint -- if NULL or an empty string, use BEGIN, ROLLBACK, COMMIT
+
 * otherwise use SAVEPOINT, ROLLBACK TO, RELEASE.
+
 * @return an error code.
+
 */
+
int pkgdb_transaction_begin(sqlite3 *sqlite, const char *savepoint);
+
int pkgdb_transaction_commit(sqlite3 *sqlite, const char *savepoint);
+
int pkgdb_transaction_rollback(sqlite3 *sqlite, const char *savepoint);
+

int pkgdb_lock(struct pkgdb *db);
int pkgdb_unlock(struct pkgdb *db);