summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-07-29 14:14:35 +0300
committerSergey Poznyakoff <gray@gnu.org>2021-07-29 15:44:28 +0300
commitbfe92de9ab4eab5001fbca6d2e40ecb8145d805f (patch)
treee42c8c9d76a487c7f56ec3903102d6709992cc77
parent136e9771401ab4c554c5c487023e5609af8aaa93 (diff)
downloadgdbm-bfe92de9ab4eab5001fbca6d2e40ecb8145d805f.tar.gz
Implement snapshot selection by numsync.
* src/gdbm.h.in (GDBM_SNAPSHOT_SUSPICIOUS): New return code. * src/gdbmsync.c (gdbm_latest_snapshot): Take into account numsync when choosing between the two snapshots. (gdbm_sync): Increase numsync.
-rw-r--r--src/gdbm.h.in10
-rw-r--r--src/gdbmsync.c101
2 files changed, 96 insertions, 15 deletions
diff --git a/src/gdbm.h.in b/src/gdbm.h.in
index 4484e0c..c4c8d88 100644
--- a/src/gdbm.h.in
+++ b/src/gdbm.h.in
@@ -133,10 +133,12 @@ extern int gdbm_convert (GDBM_FILE dbf, int flag);
enum gdbm_latest_snapshot_status
{
- GDBM_SNAPSHOT_OK,
- GDBM_SNAPSHOT_BAD,
- GDBM_SNAPSHOT_ERR,
- GDBM_SNAPSHOT_SAME
+ GDBM_SNAPSHOT_OK, /* Selected the right snapshot. */
+ GDBM_SNAPSHOT_BAD, /* Neither snapshot is readable. */
+ GDBM_SNAPSHOT_ERR, /* Error selecting snapshot. Inspect errno. */
+ GDBM_SNAPSHOT_SAME, /* Snapshot numsync and dates are the same. */
+ GDBM_SNAPSHOT_SUSPICIOUS /* Selected snapshot is unreliable: numsyncs
+ differ by more than 1. */
};
extern int gdbm_latest_snapshot (const char *, const char *, const char **);
extern int gdbm_exists (GDBM_FILE, datum);
diff --git a/src/gdbmsync.c b/src/gdbmsync.c
index 80fdbf1..f8562e7 100644
--- a/src/gdbmsync.c
+++ b/src/gdbmsync.c
@@ -230,6 +230,53 @@ stat_snapshot (const char *f, struct stat *st)
return 0;
}
+static int
+gdbm_numsync (const char *dbname, unsigned *numsync)
+{
+ GDBM_FILE dbf;
+ int rc = -1;
+
+ dbf = gdbm_open (dbname, 0, GDBM_READER, S_IRUSR, NULL);
+ if (dbf)
+ {
+ if (dbf->xheader)
+ {
+ *numsync = dbf->xheader->numsync;
+ rc = 0;
+ }
+ gdbm_close (dbf);
+ }
+ return rc;
+}
+
+/*
+ * Return:
+ * 0 both numsyncs equal or result undefined
+ * -1 a's numsync is one less than b's
+ * -2 a's numsync is less than b's
+ * +1 a's numsync is one greater than b's
+ * +2 a's numsync is greater than b's
+ *
+ * Takes into account integer overflow.
+ */
+
+static int
+gdbm_numsync_cmp (const char *a, const char *b)
+{
+ int na, nb;
+
+ if (gdbm_numsync (a, &na) == 0 &&
+ gdbm_numsync (b, &nb) == 0)
+ {
+ na++; nb++;
+ if (na < nb)
+ return na + 1 == nb ? -1 : -2;
+ else if (na > nb)
+ return na == nb + 1 ? 1 : 2;
+ }
+ return 0;
+}
+
/*
* Selects among the two given snapshot files the one to be used for
* post-crash recovery and stores its value in *RET.
@@ -256,31 +303,58 @@ gdbm_latest_snapshot (const char *even, const char *odd, const char **ret)
if (st_even.st_mode & S_IRUSR)
{
+ int rc = GDBM_SNAPSHOT_OK;
+
if (!(st_odd.st_mode & S_IRUSR))
{
*ret = even;
return GDBM_SNAPSHOT_OK;
}
- /*
- * Both readable: check mtime.
- * Select the newer snapshot, i.e. the one whose mtime
- * is greater than the other's
+ /* Both readable: compare numsync value in the extended header.
+ * Select the snapshot with greater numsync value.
*/
- switch (timespec_cmp (&st_even.st_mtim, &st_odd.st_mtim))
+ switch (gdbm_numsync_cmp (even, odd))
{
case -1:
*ret = odd;
break;
+
+ case -2:
+ *ret = odd;
+ rc = GDBM_SNAPSHOT_SUSPICIOUS;
+ break;
case 1:
*ret = even;
break;
-
- case 0:
- /* Shouldn't happen */
- return GDBM_SNAPSHOT_SAME;
+
+ case 2:
+ *ret = even;
+ rc = GDBM_SNAPSHOT_SUSPICIOUS;
+
+ default:
+ /*
+ * Both readable: check mtime.
+ * Select the newer snapshot, i.e. the one whose mtime
+ * is greater than the other's
+ */
+ switch (timespec_cmp (&st_even.st_mtim, &st_odd.st_mtim))
+ {
+ case -1:
+ *ret = odd;
+ break;
+
+ case 1:
+ *ret = even;
+ break;
+
+ case 0:
+ /* Shouldn't happen */
+ rc = GDBM_SNAPSHOT_SAME;
+ }
}
+ return rc;
}
else if (st_odd.st_mode & S_IRUSR)
{
@@ -291,10 +365,9 @@ gdbm_latest_snapshot (const char *even, const char *odd, const char **ret)
{
/* neither readable: this means the crash occurred during
gdbm_failure_atomic() */
- return GDBM_SNAPSHOT_BAD;
}
- return GDBM_SNAPSHOT_OK;
+ return GDBM_SNAPSHOT_BAD;
}
#else
int
@@ -324,6 +397,12 @@ gdbm_sync (GDBM_FILE dbf)
/* Initialize the gdbm_errno variable. */
gdbm_set_errno (dbf, GDBM_NO_ERROR, FALSE);
+ if (dbf->xheader)
+ {
+ dbf->xheader->numsync++;
+ dbf->header_changed = TRUE;
+ }
+
/* Do the sync on the file. */
return gdbm_file_sync (dbf);
}