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