diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-07-29 14:14:35 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-07-29 15:44:28 +0300 |
commit | bfe92de9ab4eab5001fbca6d2e40ecb8145d805f (patch) | |
tree | e42c8c9d76a487c7f56ec3903102d6709992cc77 | |
parent | 136e9771401ab4c554c5c487023e5609af8aaa93 (diff) | |
download | gdbm-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.in | 10 | ||||
-rw-r--r-- | src/gdbmsync.c | 101 |
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); } |