[pacman-dev] [PATCH] Enhance and utilize database status flags

Dan McGee dan at archlinux.org
Wed Aug 17 22:13:15 EDT 2011


* Move is_local standalone field to status enum
* Create VALID/INVALID flag pair
* Create EXISTS/MISSING flag pair

With these additional fields, we can be more intelligent with database
loading and messages to the user. We now only warn once if a sync
database does not exist and do not continue to try to load it once we
have marked it as missing.

The reason for the flags existing in pairs is so the unknown case can be
represented. There should never be a time when both flags in the same
group are true, but if they are both false, it represents the unknown
case. Care is taken to always manipulate both flags at the same time.

Signed-off-by: Dan McGee <dan at archlinux.org>
---

Allan, this should fix your problem. Some sample output from this patch:

dmcgee at galway ~/projects/pacman (master)
$ sudo rm /var/lib/pacman/sync/community.db

dmcgee at galway ~/projects/pacman (master)
$ sudo ./src/pacman/pacman -Su
warning: database file for 'community' does not exist
:: Starting full system upgrade...
warning: emacs: local (23.3-1) is newer than extra (23.3a-1)
warning: git: local (1.7.6-2) is newer than extra (1.7.6-1)
error: failed to prepare transaction (could not find database)

dmcgee at galway ~/projects/pacman (master)
$ sudo rm /var/lib/pacman/sync/*

dmcgee at galway ~/projects/pacman (master)
$ sudo ./src/pacman/pacman -Syu
warning: database file for 'testing' does not exist
warning: database file for 'core' does not exist
warning: database file for 'extra' does not exist
warning: database file for 'community-testing' does not exist
warning: database file for 'multilib' does not exist
warning: database file for 'community' does not exist
warning: database file for 'bogusrepo' does not exist
:: Synchronizing package databases...
 testing                                                         15.5K  329.3K/s 00:00:00 [####################################################] 100%
 core                                                            35.6K  259.1K/s 00:00:00 [####################################################] 100%
 extra                                                          474.1K  900.9K/s 00:00:01 [####################################################] 100%
 community-testing                                                5.1K 1624.3K/s 00:00:00 [####################################################] 100%
 multilib                                                        26.5K  313.0K/s 00:00:00 [####################################################] 100%
 community                                                      448.7K  859.9K/s 00:00:01 [####################################################] 100%
 bogusrepo                                                        2.9K 1418.8K/s 00:00:00 [####################################################] 100%
:: Starting full system upgrade...
warning: emacs: local (23.3-1) is newer than extra (23.3a-1)
warning: git: local (1.7.6-2) is newer than extra (1.7.6-1)
warning: scorched3d: local (43.2-1) is newer than community (43.2a-1)
resolving dependencies...
looking for inter-conflicts...

Targets (3):

Name        Old Version  New Version        Size

alsa-utils  1.0.24.2-2   1.0.24.2-3     0.90 MiB
lib32-attr  2.4.44-4     2.4.46-1       0.01 MiB
usbutils    003-1        004-1          0.17 MiB

Total Download Size:    1.08 MiB
Total Installed Size:   2.80 MiB
Net Upgrade Size:       0.04 MiB

Proceed with installation? [Y/n] n


 lib/libalpm/be_local.c |   20 ++++++++++++++++++++
 lib/libalpm/be_sync.c  |   48 +++++++++++++++++++++++++++++++++++-------------
 lib/libalpm/db.c       |    8 ++++++--
 lib/libalpm/db.h       |   18 ++++++++++--------
 lib/libalpm/package.c  |    2 +-
 lib/libalpm/sync.c     |    5 ++++-
 6 files changed, 76 insertions(+), 25 deletions(-)

diff --git a/lib/libalpm/be_local.c b/lib/libalpm/be_local.c
index a874504..5b69f62 100644
--- a/lib/libalpm/be_local.c
+++ b/lib/libalpm/be_local.c
@@ -318,6 +318,9 @@ static int local_db_validate(alpm_db_t *db)
 	if(db->status & DB_STATUS_VALID) {
 		return 0;
 	}
+	if(db->status & DB_STATUS_INVALID) {
+		return -1;
+	}
 
 	dbpath = _alpm_db_path(db);
 	if(dbpath == NULL) {
@@ -328,11 +331,16 @@ static int local_db_validate(alpm_db_t *db)
 		if(errno == ENOENT) {
 			/* database dir doesn't exist yet */
 			db->status |= DB_STATUS_VALID;
+			db->status &= ~DB_STATUS_INVALID;
+			db->status &= ~DB_STATUS_EXISTS;
+			db->status |= DB_STATUS_MISSING;
 			return 0;
 		} else {
 			RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
 		}
 	}
+	db->status |= DB_STATUS_EXISTS;
+	db->status &= ~DB_STATUS_MISSING;
 
 	while((ent = readdir(dbdir)) != NULL) {
 		const char *name = ent->d_name;
@@ -348,12 +356,15 @@ static int local_db_validate(alpm_db_t *db)
 		snprintf(path, PATH_MAX, "%s%s/depends", dbpath, name);
 		if(access(path, F_OK) == 0) {
 			/* we found a depends file- bail */
+			db->status &= ~DB_STATUS_VALID;
+			db->status |= DB_STATUS_INVALID;
 			db->handle->pm_errno = ALPM_ERR_DB_VERSION;
 			goto done;
 		}
 	}
 	/* we found no depends file after full scan */
 	db->status |= DB_STATUS_VALID;
+	db->status &= ~DB_STATUS_INVALID;
 	ret = 0;
 
 done:
@@ -373,6 +384,11 @@ static int local_db_populate(alpm_db_t *db)
 	const char *dbpath;
 	DIR *dbdir;
 
+	if(db->status & DB_STATUS_INVALID) {
+		RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
+	}
+	/* note: DB_STATUS_MISSING is not fatal for local database */
+
 	dbpath = _alpm_db_path(db);
 	if(dbpath == NULL) {
 		/* pm_errno set in _alpm_db_path() */
@@ -383,6 +399,8 @@ static int local_db_populate(alpm_db_t *db)
 	if(dbdir == NULL) {
 		if(errno == ENOENT) {
 			/* no database existing yet is not an error */
+			db->status &= ~DB_STATUS_EXISTS;
+			db->status |= DB_STATUS_MISSING;
 			return 0;
 		}
 		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
@@ -390,6 +408,8 @@ static int local_db_populate(alpm_db_t *db)
 	if(fstat(dirfd(dbdir), &buf) != 0) {
 		RET_ERR(db->handle, ALPM_ERR_DB_OPEN, -1);
 	}
+	db->status |= DB_STATUS_EXISTS;
+	db->status &= ~DB_STATUS_MISSING;
 	if(buf.st_nlink >= 2) {
 		est_count = buf.st_nlink;
 	} else {
diff --git a/lib/libalpm/be_sync.c b/lib/libalpm/be_sync.c
index 7f01674..2db7ce5 100644
--- a/lib/libalpm/be_sync.c
+++ b/lib/libalpm/be_sync.c
@@ -70,28 +70,37 @@ static char *get_sync_dir(alpm_handle_t *handle)
 static int sync_db_validate(alpm_db_t *db)
 {
 	alpm_siglevel_t level;
+	const char *dbpath;
 
-	if(db->status & DB_STATUS_VALID) {
+	if(db->status & DB_STATUS_VALID || db->status & DB_STATUS_MISSING) {
 		return 0;
 	}
+	if(db->status & DB_STATUS_INVALID) {
+		return -1;
+	}
+
+	dbpath = _alpm_db_path(db);
+	if(!dbpath) {
+		/* pm_errno set in _alpm_db_path() */
+		return -1;
+	}
+
+	/* we can skip any validation if the database doesn't exist */
+	if(access(dbpath, R_OK) != 0 && errno == ENOENT) {
+		db->status &= ~DB_STATUS_EXISTS;
+		db->status |= DB_STATUS_MISSING;
+		_alpm_log(db->handle, ALPM_LOG_WARNING,
+				"database file for '%s' does not exist\n", db->treename);
+		goto valid;
+	}
+	db->status |= DB_STATUS_EXISTS;
+	db->status &= ~DB_STATUS_MISSING;
 
 	/* this takes into account the default verification level if UNKNOWN
 	 * was assigned to this db */
 	level = alpm_db_get_siglevel(db);
 
 	if(level & ALPM_SIG_DATABASE) {
-		const char *dbpath = _alpm_db_path(db);
-		if(!dbpath) {
-			/* pm_errno set in _alpm_db_path() */
-			return -1;
-		}
-
-		/* we can skip any validation if the database doesn't exist */
-		if(access(dbpath, R_OK) != 0 && errno == ENOENT) {
-			goto valid;
-			return 0;
-		}
-
 		if(_alpm_check_pgp_helper(db->handle, dbpath, NULL,
 					level & ALPM_SIG_DATABASE_OPTIONAL, level & ALPM_SIG_DATABASE_MARGINAL_OK,
 					level & ALPM_SIG_DATABASE_UNKNOWN_OK, ALPM_ERR_DB_INVALID_SIG)) {
@@ -101,6 +110,7 @@ static int sync_db_validate(alpm_db_t *db)
 
 valid:
 	db->status |= DB_STATUS_VALID;
+	db->status &= ~DB_STATUS_INVALID;
 	return 0;
 }
 
@@ -234,7 +244,12 @@ int SYMEXPORT alpm_db_update(int force, alpm_db_t *db)
 	/* Cache needs to be rebuilt */
 	_alpm_db_free_pkgcache(db);
 
+	/* clear all status flags regarding validity/existence */
 	db->status &= ~DB_STATUS_VALID;
+	db->status &= ~DB_STATUS_INVALID;
+	db->status &= ~DB_STATUS_EXISTS;
+	db->status &= ~DB_STATUS_MISSING;
+
 	if(sync_db_validate(db)) {
 		/* pm_errno should be set */
 		ret = -1;
@@ -378,6 +393,13 @@ static int sync_db_populate(alpm_db_t *db)
 	struct archive_entry *entry;
 	alpm_pkg_t *pkg = NULL;
 
+	if(db->status & DB_STATUS_INVALID) {
+		RET_ERR(db->handle, ALPM_ERR_DB_INVALID, -1);
+	}
+	if(db->status & DB_STATUS_MISSING) {
+		RET_ERR(db->handle, ALPM_ERR_DB_NOT_FOUND, -1);
+	}
+
 	if((archive = archive_read_new()) == NULL) {
 		RET_ERR(db->handle, ALPM_ERR_LIBARCHIVE, -1);
 	}
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index ad5f0bc..8a235e2 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -326,7 +326,11 @@ alpm_db_t *_alpm_db_new(const char *treename, int is_local)
 
 	CALLOC(db, 1, sizeof(alpm_db_t), return NULL);
 	STRDUP(db->treename, treename, return NULL);
-	db->is_local = is_local;
+	if(is_local) {
+		db->status |= DB_STATUS_LOCAL;
+	} else {
+		db->status &= ~DB_STATUS_LOCAL;
+	}
 
 	return db;
 }
@@ -359,7 +363,7 @@ const char *_alpm_db_path(alpm_db_t *db)
 			RET_ERR(db->handle, ALPM_ERR_DB_OPEN, NULL);
 		}
 
-		if(db->is_local) {
+		if(db->status & DB_STATUS_LOCAL) {
 			pathsize = strlen(dbpath) + strlen(db->treename) + 2;
 			CALLOC(db->_path, 1, pathsize, RET_ERR(db->handle, ALPM_ERR_MEMORY, NULL));
 			sprintf(db->_path, "%s%s/", dbpath, db->treename);
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index 2938b54..88f6c68 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -47,8 +47,13 @@ typedef enum _alpm_dbinfrq_t {
 /** Database status. Bitflags. */
 enum _alpm_dbstatus_t {
 	DB_STATUS_VALID = (1 << 0),
-	DB_STATUS_PKGCACHE = (1 << 1),
-	DB_STATUS_GRPCACHE = (1 << 2)
+	DB_STATUS_INVALID = (1 << 1),
+	DB_STATUS_EXISTS = (1 << 2),
+	DB_STATUS_MISSING = (1 << 3),
+
+	DB_STATUS_LOCAL = (1 << 10),
+	DB_STATUS_PKGCACHE = (1 << 11),
+	DB_STATUS_GRPCACHE = (1 << 12)
 };
 
 struct db_operations {
@@ -63,16 +68,13 @@ struct __alpm_db_t {
 	char *treename;
 	/* do not access directly, use _alpm_db_path(db) for lazy access */
 	char *_path;
-	/* also indicates whether we are RO or RW */
-	int is_local;
-	/* flags determining validity, loaded caches, etc. */
-	enum _alpm_dbstatus_t status;
 	alpm_pkghash_t *pkgcache;
 	alpm_list_t *grpcache;
 	alpm_list_t *servers;
-	alpm_siglevel_t siglevel;
-
 	struct db_operations *ops;
+	/* flags determining validity, local, loaded caches, etc. */
+	enum _alpm_dbstatus_t status;
+	alpm_siglevel_t siglevel;
 };
 
 
diff --git a/lib/libalpm/package.c b/lib/libalpm/package.c
index 19d2c84..a88af5e 100644
--- a/lib/libalpm/package.c
+++ b/lib/libalpm/package.c
@@ -424,7 +424,7 @@ alpm_list_t SYMEXPORT *alpm_pkg_compute_requiredby(alpm_pkg_t *pkg)
 		/* We have a DB package. if it is a local package, then we should
 		 * only search the local DB; else search all known sync databases. */
 		db = pkg->origin_data.db;
-		if(db->is_local) {
+		if(db->status & DB_STATUS_LOCAL) {
 			find_requiredby(pkg, db, &reqs);
 		} else {
 			for(i = pkg->handle->dbs_sync; i; i = i->next) {
diff --git a/lib/libalpm/sync.c b/lib/libalpm/sync.c
index 1807e70..a5964b9 100644
--- a/lib/libalpm/sync.c
+++ b/lib/libalpm/sync.c
@@ -319,9 +319,12 @@ int _alpm_sync_prepare(alpm_handle_t *handle, alpm_list_t **data)
 	/* ensure all sync database are valid since we will be using them */
 	for(i = handle->dbs_sync; i; i = i->next) {
 		const alpm_db_t *db = i->data;
-		if(!(db->status & DB_STATUS_VALID)) {
+		if(db->status & DB_STATUS_INVALID) {
 			RET_ERR(handle, ALPM_ERR_DB_INVALID, -1);
 		}
+		if(db->status & DB_STATUS_MISSING) {
+			RET_ERR(handle, ALPM_ERR_DB_NOT_FOUND, -1);
+		}
 	}
 
 	if(!(trans->flags & ALPM_TRANS_FLAG_NODEPS)) {
-- 
1.7.6



More information about the pacman-dev mailing list