Hi,
On Sat, Aug 11, 2007 at 02:20:22PM +0100, Stephen Gran wrote:
> > works rather well and solves this problem but has one major drawback: we
> > can't specify the DB_RECOVER flag here since this would conflict with
> > the DB_RECOVER flag of nss_updatedb. This could leave us with an
> > inconsistent database in case an applications aborts leaving an
> > "unrecovered" database for all other apps. Any ideas on howto fix this?
Could you please try the attached patch against nss-updatedb on alioth?
Renaming the db via dbenv->rename isn't atomic but keeps us out of the
db_env trouble and is a huge improvement (and as a bouns we don't have
to mess with crappy libnss-db). With this I didn't see any lookup
failures.
Cheers,
 -- Guido
diff --git a/cache.c b/cache.c
index 65f48ff..c8ef3eb 100644
--- a/cache.c
+++ b/cache.c
@@ -32,6 +32,7 @@ struct nss_cache {
 	DB *db;
 	int index;
 #if DB_VERSION_MAJOR >= 4
+	char *tmpname;
 	DB_ENV *dbenv;
 	DB_TXN *dbtxn;
 #endif
@@ -63,6 +64,13 @@ enum nss_status nss_cache_init(const char *filename,
 	cache->dbenv = NULL;
 	cache->dbtxn = NULL;
 
+	rc = asprintf(&cache->tmpname, "%s" TMP_EXT, cache->filename);
+	if (rc == -1) {
+		nss_cache_close(&cache);
+		errno = rc;
+		return NSS_STATUS_TRYAGAIN;
+	}
+
 	rc = db_env_create(&cache->dbenv, 0);
 	if (rc != 0) {
 		nss_cache_close(&cache);
@@ -97,7 +105,7 @@ enum nss_status nss_cache_init(const char *filename,
 	}
 
 	rc = cache->db->open(cache->db,0,
-			     cache->filename,NULL, 
+			     cache->tmpname, NULL,
 			     DB_BTREE,DB_CREATE|DB_AUTO_COMMIT, mode);
 	if (rc != 0) {
 		nss_cache_close(&cache);
@@ -407,6 +415,18 @@ enum nss_status nss_cache_commit(nss_cache_t *cache)
 		return NSS_STATUS_UNAVAIL;
 	}
 
+#if DB_VERSION_MAJOR >= 4
+	cache->db->close(cache->db, 0);
+	cache->db = NULL; /* not usable anymore */
+	unlink(cache->filename);
+	rc = cache->dbenv->dbrename(cache->dbenv, NULL, cache->tmpname,
+	    			    NULL, cache->filename, 0);
+	if (rc != 0) {
+		errno = rc;
+		return NSS_STATUS_UNAVAIL;
+	}
+#endif
+
 	return NSS_STATUS_SUCCESS;
 }
 
@@ -436,6 +456,8 @@ enum nss_status nss_cache_close(nss_cache_t **cache_p)
 			cache->db->close(cache->db, 0);
 		if (cache->dbenv != NULL)
 			cache->dbenv->close(cache->dbenv, 0);
+		if (cache->tmpname != NULL)
+			free(cache->tmpname);
 #endif
 		if (cache->filename != NULL)
 			free(cache->filename);
diff --git a/cache.h b/cache.h
index 871db45..9121c0f 100644
--- a/cache.h
+++ b/cache.h
@@ -20,6 +20,8 @@
 #include <pwd.h>
 #include <grp.h>
 
+#define TMP_EXT ".tmp"
+
 struct nss_cache;
 typedef struct nss_cache nss_cache_t;
 
diff --git a/updatedb.h b/updatedb.h

Reply via email to