Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Add PID protection from stale locks.
Vsevolod Stakhov committed 12 years ago
commit ddaaf6e4257a8569c65840aac2774038f00ad302
parent 65c66a6
1 file changed +124 -6
modified libpkg/pkgdb.c
@@ -44,6 +44,7 @@
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
+
#include <signal.h>

#include <sqlite3.h>

@@ -2205,7 +2206,7 @@ pkgdb_load_options(struct pkgdb *db, struct pkg *pkg)
			break;
		}

-
		pkg_debug(1, "Pkgdb> adding option");
+
		pkg_debug(4, "Pkgdb> adding option");
		ret = load_tag_val(db->sqlite, pkg, sql, PKG_LOAD_OPTIONS,
				   pkg_addtagval, PKG_OPTIONS);
		if (ret != EPKG_OK)
@@ -4161,7 +4162,108 @@ pkgshell_open(const char **reponame)
}

static int
-
pkgdb_try_lock (struct pkgdb *db, const char *lock_sql,
+
pkgdb_write_lock_pid(struct pkgdb *db)
+
{
+
	const char lock_pid_sql[] = ""
+
			"INSERT INTO pkg_lock_pid VALUES (?1);";
+
	sqlite3_stmt	*stmt = NULL;
+
	int ret;
+

+
	ret = sqlite3_prepare_v2(db->sqlite, lock_pid_sql, -1, &stmt, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (EPKG_FATAL);
+
	}
+
	sqlite3_bind_int64(stmt, 1, (int64_t)getpid());
+

+
	if (sqlite3_step(stmt) != SQLITE_DONE) {
+
		ERROR_SQLITE(db->sqlite);
+
		sqlite3_finalize(stmt);
+
		return (EPKG_FATAL);
+
	}
+
	sqlite3_finalize(stmt);
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
pkgdb_remove_lock_pid(struct pkgdb *db, int64_t pid)
+
{
+
	const char lock_pid_sql[] = ""
+
			"DELETE FROM pkg_lock_pid WHERE pid = ?1;";
+
	sqlite3_stmt	*stmt = NULL;
+
	int ret;
+

+
	ret = sqlite3_prepare_v2(db->sqlite, lock_pid_sql, -1, &stmt, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (EPKG_FATAL);
+
	}
+
	sqlite3_bind_int64(stmt, 1, pid);
+

+
	if (sqlite3_step(stmt) != SQLITE_DONE) {
+
		ERROR_SQLITE(db->sqlite);
+
		sqlite3_finalize(stmt);
+
		return (EPKG_FATAL);
+
	}
+
	sqlite3_finalize(stmt);
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
pkgdb_check_lock_pid(struct pkgdb *db)
+
{
+
	sqlite3_stmt	*stmt = NULL;
+
	int ret, found = 0;
+
	int64_t pid, lpid;
+

+
	ret = sqlite3_prepare_v2(db->sqlite, "SELECT pid FROM pkg_lock_pid;", -1,
+
			&stmt, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (EPKG_FATAL);
+
	}
+

+
	lpid = getpid();
+

+
	while (sqlite3_step(stmt) != SQLITE_DONE) {
+
		pid = sqlite3_column_int64(stmt, 0);
+
		if (pid != lpid && kill((pid_t)pid, 0) == -1) {
+
			pkg_debug(1, "found stale pid %lld in lock database", pid);
+
			if (pkgdb_remove_lock_pid(db, pid) != EPKG_OK){
+
				sqlite3_finalize(stmt);
+
				return (EPKG_FATAL);
+
			}
+
		}
+
		else {
+
			found ++;
+
		}
+
	}
+

+
	if (found == 0)
+
		return (EPKG_END);
+

+
	return (EPKG_OK);
+
}
+

+
static int
+
pkgdb_reset_lock(struct pkgdb *db)
+
{
+
	const char init_sql[] = ""
+
		"UPDATE pkg_lock SET exclusive=0, advisory=0, read=0;";
+
	int ret;
+

+
	ret = sqlite3_exec(db->sqlite, init_sql, NULL, NULL, NULL);
+

+
	if (ret == SQLITE_OK)
+
		return (EPKG_OK);
+

+
	return (EPKG_FATAL);
+
}
+

+
static int
+
pkgdb_try_lock(struct pkgdb *db, const char *lock_sql,
		double delay, unsigned int retries)
{
	unsigned int tries = 0;
@@ -4173,8 +4275,15 @@ pkgdb_try_lock (struct pkgdb *db, const char *lock_sql,
		if (ret != SQLITE_OK)
			return (EPKG_FATAL);

+
		ret = EPKG_END;
		if (sqlite3_changes(db->sqlite) == 0) {
-
			if (delay > 0) {
+
			if (pkgdb_check_lock_pid(db) == EPKG_END) {
+
				/* No live processes found, so we can safely reset lock */
+
				pkg_debug(1, "no concurrent processes found, cleanup the lock");
+
				pkgdb_reset_lock(db);
+
				continue;
+
			}
+
			else if (delay > 0) {
				ts.tv_sec = (int)delay;
				ts.tv_nsec = (delay - (int)delay) * 1000000000.;
				pkg_debug(1, "waiting for database lock for %d times, "
@@ -4186,7 +4295,7 @@ pkgdb_try_lock (struct pkgdb *db, const char *lock_sql,
			}
		}
		else {
-
			ret = EPKG_OK;
+
			ret = pkgdb_write_lock_pid(db);
			break;
		}
		tries ++;
@@ -4202,7 +4311,10 @@ pkgdb_obtain_lock(struct pkgdb *db, pkgdb_lock_t type,
	int ret;
	const char table_sql[] = ""
			"CREATE TABLE pkg_lock "
-
			"(exclusive INT(1), advisory INT(1), read INT(8));";
+
			"(exclusive INTEGER(1), advisory INTEGER(1), read INTEGER(8));";
+
	const char pid_sql[] = ""
+
			"CREATE TABLE IF NOT EXISTS pkg_lock_pid "
+
			"(pid INTEGER PRIMARY KEY);";
	const char init_sql[] = ""
			"INSERT INTO pkg_lock VALUES(0,0,0);";
	const char readonly_lock_sql[] = ""
@@ -4225,6 +4337,12 @@ pkgdb_obtain_lock(struct pkgdb *db, pkgdb_lock_t type,
		}
	}

+
	ret = sqlite3_exec(db->sqlite, pid_sql, NULL, NULL, NULL);
+
	if (ret != SQLITE_OK) {
+
		ERROR_SQLITE(db->sqlite);
+
		return (EPKG_FATAL);
+
	}
+

	switch (type) {
	case PKGDB_LOCK_READONLY:
		lock_sql = readonly_lock_sql;
@@ -4299,7 +4417,7 @@ pkgdb_release_lock(struct pkgdb *db, pkgdb_lock_t type)
	if (sqlite3_changes(db->sqlite) == 0)
		return (EPKG_END);

-
	return (EPKG_OK);
+
	return pkgdb_remove_lock_pid(db, (int64_t)getpid());
}

int64_t