[pacman-dev] [PATCH] Fully implement database lazy loading

Dan McGee dan at archlinux.org
Mon Sep 14 23:49:14 EDT 2009


Commit 34e1413d75 attempted to implement lazy loading of package databases.
Although it took care of my main complaint (creating the database directory
if it didn't exist), it didn't allow sync repos to be registered before
alpm_option_set_dbpath() had been called.

With this patch, we no longer compute the individual repository DB paths
until necessary, allowing full lazy loading to work as intended, and
allowing us to drop the extra setlibpath() calls from the frontend. This
allows the changes introduced in a2cd48960 (but later reverted) to be added
back in again.

Signed-off-by: Dan McGee <dan at archlinux.org>
---
 lib/libalpm/add.c      |   13 +++++----
 lib/libalpm/be_files.c |   39 +++++++++++++++++++-----------
 lib/libalpm/db.c       |   61 ++++++++++++++++++++++++++++-------------------
 lib/libalpm/db.h       |    8 ++++--
 lib/libalpm/remove.c   |    4 +-
 src/pacman/pacman.c    |    5 +---
 6 files changed, 75 insertions(+), 55 deletions(-)

diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c
index 268ecd7..f035c59 100644
--- a/lib/libalpm/add.c
+++ b/lib/libalpm/add.c
@@ -132,13 +132,13 @@ static int extract_single_file(struct archive *archive,
 
 	if(strcmp(entryname, ".INSTALL") == 0) {
 		/* the install script goes inside the db */
-		snprintf(filename, PATH_MAX, "%s%s-%s/install", db->path,
-				newpkg->name, newpkg->version);
+		snprintf(filename, PATH_MAX, "%s%s-%s/install",
+				_alpm_db_path(db), newpkg->name, newpkg->version);
 		archive_entry_set_perm(entry, 0644);
 	} else if(strcmp(entryname, ".CHANGELOG") == 0) {
 		/* the changelog goes inside the db */
-		snprintf(filename, PATH_MAX, "%s%s-%s/changelog", db->path,
-				newpkg->name, newpkg->version);
+		snprintf(filename, PATH_MAX, "%s%s-%s/changelog",
+				_alpm_db_path(db), newpkg->name, newpkg->version);
 		archive_entry_set_perm(entry, 0644);
 	} else if(*entryname == '.') {
 		/* for now, ignore all files starting with '.' that haven't
@@ -483,8 +483,9 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count,
 
 	ALPM_LOG_FUNC;
 
-	snprintf(scriptlet, PATH_MAX, "%s%s-%s/install", db->path,
-			alpm_pkg_get_name(newpkg), alpm_pkg_get_version(newpkg));
+	snprintf(scriptlet, PATH_MAX, "%s%s-%s/install",
+			_alpm_db_path(db), alpm_pkg_get_name(newpkg),
+			alpm_pkg_get_version(newpkg));
 
 	/* see if this is an upgrade. if so, remove the old package first */
 	pmpkg_t *local = _alpm_db_get_pkgfromcache(db, newpkg->name);
diff --git a/lib/libalpm/be_files.c b/lib/libalpm/be_files.c
index 03a1463..cf51fc0 100644
--- a/lib/libalpm/be_files.c
+++ b/lib/libalpm/be_files.c
@@ -51,10 +51,11 @@
  * Return the last update time as number of seconds from the epoch.
  * Returns 0 if the value is unknown or can't be read.
  */
-static time_t getlastupdate(const pmdb_t *db)
+static time_t getlastupdate(pmdb_t *db)
 {
 	FILE *fp;
 	char *file;
+	const char *dbpath;
 	time_t ret = 0;
 
 	ALPM_LOG_FUNC;
@@ -63,9 +64,10 @@ static time_t getlastupdate(const pmdb_t *db)
 		return(ret);
 	}
 
-	/* db->path + '.lastupdate' + NULL */
-	MALLOC(file, strlen(db->path) + 12, RET_ERR(PM_ERR_MEMORY, ret));
-	sprintf(file, "%s.lastupdate", db->path);
+	dbpath = _alpm_db_path(db);
+	/* dbpath + '.lastupdate' + NULL */
+	MALLOC(file, strlen(dbpath) + 12, RET_ERR(PM_ERR_MEMORY, ret));
+	sprintf(file, "%s.lastupdate", dbpath);
 
 	/* get the last update time, if it's there */
 	if((fp = fopen(file, "r")) == NULL) {
@@ -85,10 +87,11 @@ static time_t getlastupdate(const pmdb_t *db)
 /*
  * writes the dbpath/.lastupdate file with the value in time
  */
-static int setlastupdate(const pmdb_t *db, time_t time)
+static int setlastupdate(pmdb_t *db, time_t time)
 {
 	FILE *fp;
 	char *file;
+	const char *dbpath;
 	int ret = 0;
 
 	ALPM_LOG_FUNC;
@@ -97,9 +100,10 @@ static int setlastupdate(const pmdb_t *db, time_t time)
 		return(-1);
 	}
 
-	/* db->path + '.lastupdate' + NULL */
-	MALLOC(file, strlen(db->path) + 12, RET_ERR(PM_ERR_MEMORY, ret));
-	sprintf(file, "%s.lastupdate", db->path);
+	dbpath = _alpm_db_path(db);
+	/* dbpath + '.lastupdate' + NULL */
+	MALLOC(file, strlen(dbpath) + 12, RET_ERR(PM_ERR_MEMORY, ret));
+	sprintf(file, "%s.lastupdate", dbpath);
 
 	if((fp = fopen(file, "w")) == NULL) {
 		free(file);
@@ -116,7 +120,7 @@ static int setlastupdate(const pmdb_t *db, time_t time)
 static int checkdbdir(pmdb_t *db)
 {
 	struct stat buf;
-	char *path = db->path;
+	const char *path = _alpm_db_path(db);
 
 	if(stat(path, &buf) != 0) {
 		_alpm_log(PM_LOG_DEBUG, "database dir '%s' does not exist, creating it\n",
@@ -224,8 +228,9 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
 		_alpm_log(PM_LOG_DEBUG, "failed to sync db: %s\n", alpm_strerrorlast());
 		return(-1);
 	} else {
+		const char *syncdbpath = _alpm_db_path(db);
 		/* remove the old dir */
-		if(_alpm_rmrf(db->path) != 0) {
+		if(_alpm_rmrf(syncdbpath) != 0) {
 			_alpm_log(PM_LOG_ERROR, _("could not remove database %s\n"), db->treename);
 			RET_ERR(PM_ERR_DB_REMOVE, -1);
 		}
@@ -240,7 +245,7 @@ int SYMEXPORT alpm_db_update(int force, pmdb_t *db)
 
 		/* uncompress the sync database */
 		checkdbdir(db);
-		ret = _alpm_unpack(dbfilepath, db->path, NULL);
+		ret = _alpm_unpack(dbfilepath, syncdbpath, NULL);
 		if(ret) {
 			free(dbfilepath);
 			RET_ERR(PM_ERR_SYSTEM, -1);
@@ -305,13 +310,15 @@ int _alpm_db_populate(pmdb_t *db)
 	struct dirent *ent = NULL;
 	struct stat sbuf;
 	char path[PATH_MAX];
+	const char *dbpath;
 	DIR *dbdir;
 
 	ALPM_LOG_FUNC;
 
 	ASSERT(db != NULL, RET_ERR(PM_ERR_DB_NULL, -1));
 
-	dbdir = opendir(db->path);
+	dbpath = _alpm_db_path(db);
+	dbdir = opendir(dbpath);
 	if(dbdir == NULL) {
 		return(0);
 	}
@@ -323,7 +330,7 @@ int _alpm_db_populate(pmdb_t *db)
 			continue;
 		}
 		/* stat the entry, make sure it's a directory */
-		snprintf(path, PATH_MAX, "%s%s", db->path, name);
+		snprintf(path, PATH_MAX, "%s%s", dbpath, name);
 		if(stat(path, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
 			continue;
 		}
@@ -366,10 +373,12 @@ static char *get_pkgpath(pmdb_t *db, pmpkg_t *info)
 {
 	size_t len;
 	char *pkgpath;
+	const char *dbpath;
 
-	len = strlen(db->path) + strlen(info->name) + strlen(info->version) + 3;
+	dbpath = _alpm_db_path(db);
+	len = strlen(dbpath) + strlen(info->name) + strlen(info->version) + 3;
 	MALLOC(pkgpath, len, RET_ERR(PM_ERR_MEMORY, NULL));
-	sprintf(pkgpath, "%s%s-%s/", db->path, info->name, info->version);
+	sprintf(pkgpath, "%s%s-%s/", dbpath, info->name, info->version);
 	return(pkgpath);
 }
 
diff --git a/lib/libalpm/db.c b/lib/libalpm/db.c
index 62c2e0a..e57ff93 100644
--- a/lib/libalpm/db.c
+++ b/lib/libalpm/db.c
@@ -323,18 +323,15 @@ alpm_list_t SYMEXPORT *alpm_db_search(pmdb_t *db, const alpm_list_t* needles)
 
 /** @} */
 
-pmdb_t *_alpm_db_new(const char *dbpath, const char *treename)
+static pmdb_t *_alpm_db_new(const char *treename, unsigned short is_local)
 {
 	pmdb_t *db;
-	const size_t pathsize = strlen(dbpath) + strlen(treename) + 2;
 
 	ALPM_LOG_FUNC;
 
 	CALLOC(db, 1, sizeof(pmdb_t), RET_ERR(PM_ERR_MEMORY, NULL));
-	CALLOC(db->path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
-
-	sprintf(db->path, "%s%s/", dbpath, treename);
 	STRDUP(db->treename, treename, RET_ERR(PM_ERR_MEMORY, NULL));
+	db->is_local = is_local;
 
 	return(db);
 }
@@ -347,13 +344,44 @@ void _alpm_db_free(pmdb_t *db)
 	_alpm_db_free_pkgcache(db);
 	/* cleanup server list */
 	FREELIST(db->servers);
-	FREE(db->path);
+	FREE(db->_path);
 	FREE(db->treename);
 	FREE(db);
 
 	return;
 }
 
+const char *_alpm_db_path(pmdb_t *db)
+{
+	if(!db) {
+		return(NULL);
+	}
+	if(!db->_path) {
+		const char *dbpath;
+		size_t pathsize;
+
+		dbpath = alpm_option_get_dbpath();
+		if(!dbpath) {
+			_alpm_log(PM_LOG_ERROR, _("database path is undefined\n"));
+			RET_ERR(PM_ERR_DB_OPEN, NULL);
+		}
+
+		if(db->is_local) {
+			pathsize = strlen(dbpath) + strlen(db->treename) + 2;
+			CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
+			sprintf(db->_path, "%s%s/", dbpath, db->treename);
+		} else {
+			pathsize = strlen(dbpath) + 5 + strlen(db->treename) + 2;
+			CALLOC(db->_path, 1, pathsize, RET_ERR(PM_ERR_MEMORY, NULL));
+			/* all sync DBs now reside in the sync/ subdir of the dbpath */
+			sprintf(db->_path, "%ssync/%s/", dbpath, db->treename);
+		}
+		_alpm_log(PM_LOG_DEBUG, "database path for tree %s set to %s\n",
+				db->treename, db->_path);
+	}
+	return(db->_path);
+}
+
 int _alpm_db_cmp(const void *d1, const void *d2)
 {
 	pmdb_t *db1 = (pmdb_t *)d1;
@@ -440,7 +468,6 @@ alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles)
 pmdb_t *_alpm_db_register_local(void)
 {
 	pmdb_t *db;
-	const char *dbpath;
 
 	ALPM_LOG_FUNC;
 
@@ -451,13 +478,7 @@ pmdb_t *_alpm_db_register_local(void)
 
 	_alpm_log(PM_LOG_DEBUG, "registering local database\n");
 
-	dbpath = alpm_option_get_dbpath();
-	if(!dbpath) {
-		_alpm_log(PM_LOG_ERROR, _("database path is undefined\n"));
-			RET_ERR(PM_ERR_DB_OPEN, NULL);
-	}
-
-	db = _alpm_db_new(dbpath, "local");
+	db = _alpm_db_new("local", 1);
 	if(db == NULL) {
 		RET_ERR(PM_ERR_DB_CREATE, NULL);
 	}
@@ -469,8 +490,6 @@ pmdb_t *_alpm_db_register_local(void)
 pmdb_t *_alpm_db_register_sync(const char *treename)
 {
 	pmdb_t *db;
-	const char *dbpath;
-	char path[PATH_MAX];
 	alpm_list_t *i;
 
 	ALPM_LOG_FUNC;
@@ -485,15 +504,7 @@ pmdb_t *_alpm_db_register_sync(const char *treename)
 
 	_alpm_log(PM_LOG_DEBUG, "registering sync database '%s'\n", treename);
 
-	dbpath = alpm_option_get_dbpath();
-	if(!dbpath) {
-		_alpm_log(PM_LOG_ERROR, _("database path is undefined\n"));
-			RET_ERR(PM_ERR_DB_OPEN, NULL);
-	}
-	/* all sync DBs now reside in the sync/ subdir of the dbpath */
-	snprintf(path, PATH_MAX, "%ssync/", dbpath);
-
-	db = _alpm_db_new(path, treename);
+	db = _alpm_db_new(treename, 0);
 	if(db == NULL) {
 		RET_ERR(PM_ERR_DB_CREATE, NULL);
 	}
diff --git a/lib/libalpm/db.h b/lib/libalpm/db.h
index 950ace2..2981603 100644
--- a/lib/libalpm/db.h
+++ b/lib/libalpm/db.h
@@ -40,18 +40,20 @@ typedef enum _pmdbinfrq_t {
 
 /* Database */
 struct __pmdb_t {
-	char *path;
 	char *treename;
+	/* do not access directly, use _alpm_db_path(db) for lazy access */
+	char *_path;
 	unsigned short pkgcache_loaded;
-	alpm_list_t *pkgcache;
 	unsigned short grpcache_loaded;
+	unsigned short is_local;
+	alpm_list_t *pkgcache;
 	alpm_list_t *grpcache;
 	alpm_list_t *servers;
 };
 
 /* db.c, database general calls */
-pmdb_t *_alpm_db_new(const char *dbpath, const char *treename);
 void _alpm_db_free(pmdb_t *db);
+const char *_alpm_db_path(pmdb_t *db);
 int _alpm_db_cmp(const void *d1, const void *d2);
 alpm_list_t *_alpm_db_search(pmdb_t *db, const alpm_list_t *needles);
 pmdb_t *_alpm_db_register_local(void);
diff --git a/lib/libalpm/remove.c b/lib/libalpm/remove.c
index af2ce94..dd54318 100644
--- a/lib/libalpm/remove.c
+++ b/lib/libalpm/remove.c
@@ -386,8 +386,8 @@ int _alpm_remove_packages(pmtrans_t *trans, pmdb_t *db)
 
 		/* get the name now so we can use it after package is removed */
 		pkgname = alpm_pkg_get_name(info);
-		snprintf(scriptlet, PATH_MAX, "%s%s-%s/install", db->path,
-						 pkgname, alpm_pkg_get_version(info));
+		snprintf(scriptlet, PATH_MAX, "%s%s-%s/install",
+				_alpm_db_path(db), pkgname, alpm_pkg_get_version(info));
 
 		EVENT(trans, PM_TRANS_EVT_REMOVE_START, info, NULL);
 		_alpm_log(PM_LOG_DEBUG, "removing package %s-%s\n",
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index 64598b0..76511f4 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -758,11 +758,8 @@ static int _parseconfig(const char *file, const char *givensection,
 				ret = 1;
 				goto cleanup;
 			}
-			/* if we are not looking at the options section, register a db and also
-			 * ensure we have set all of our library paths as the library is too stupid
-			 * at the moment to do lazy opening of the databases */
+			/* if we are not looking at the options section, register a db */
 			if(strcmp(section, "options") != 0) {
-				setlibpaths();
 				db = alpm_db_register_sync(section);
 				if(db == NULL) {
 					pm_printf(PM_LOG_ERROR, _("could not register '%s' database (%s)\n"),
-- 
1.6.4.3



More information about the pacman-dev mailing list