summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2014-01-20 18:46:52 -0500
committerGreg Hudson <ghudson@mit.edu>2014-02-20 15:55:48 -0500
commitd1f9aa3737b2b3e62b5c5ed488d6112b7ce8a5ad (patch)
treef5f86bc7a30d0c05db26e9dacc20e875cf9bac9e /src/lib
parent444ef5fe9ec8d64a5db27b3a8aaf6813dd7ef0e0 (diff)
downloadkrb5-d1f9aa3737b2b3e62b5c5ed488d6112b7ce8a5ad.tar.gz
krb5-d1f9aa3737b2b3e62b5c5ed488d6112b7ce8a5ad.tar.xz
krb5-d1f9aa3737b2b3e62b5c5ed488d6112b7ce8a5ad.zip
Factor out ulog serial number status check
Add a new function ulog_get_sno_status, which checks a serial number and timestamp against the ulog for currency. Use it in kdb5_util dump and in ulog_get_entries. Adjust parse_iprop_header's contract in dump.c to better match the ulog_get_sno_status contract. This change causes some minor behavior differences. kadmind will check for an empty ulog unless the last serial number matches exactly, and will never set lastentry when returning UPDATE_FULL_RESYNC_NEEDED (which was pointless). kdb5_util dump will recognize a dump file as current if it exactly matches the last serial number, even if the ulog is empty; it will be more robust in the presence of non-monotonic clocks; and it will properly lock around the ulog access.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/kdb/kdb_log.c82
-rw-r--r--src/lib/kdb/libkdb5.exports1
2 files changed, 58 insertions, 25 deletions
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
index ca40a4fe52..dcc1bcf447 100644
--- a/src/lib/kdb/kdb_log.c
+++ b/src/lib/kdb/kdb_log.c
@@ -85,6 +85,49 @@ ulog_sync_header(kdb_hlog_t *ulog)
}
}
+/* Return true if the ulog entry for sno matches sno and timestamp. */
+static krb5_boolean
+check_sno(kdb_log_context *log_ctx, kdb_sno_t sno,
+ const kdbe_time_t *timestamp)
+{
+ unsigned int indx = (sno - 1) % log_ctx->ulogentries;
+ kdb_ent_header_t *ent = INDEX(log_ctx->ulog, indx);
+
+ return ent->kdb_entry_sno == sno && time_equal(&ent->kdb_time, timestamp);
+}
+
+/*
+ * Check last against our ulog and determine whether it is up to date
+ * (UPDATE_NIL), so far out of date that a full dump is required
+ * (UPDATE_FULL_RESYNC_NEEDED), or okay to update with ulog entries
+ * (UPDATE_OK).
+ */
+static update_status_t
+get_sno_status(kdb_log_context *log_ctx, const kdb_last_t *last)
+{
+ kdb_hlog_t *ulog = log_ctx->ulog;
+
+ /* If last matches the ulog's last serial number and time exactly, it are
+ * up to date even if the ulog is empty. */
+ if (last->last_sno == ulog->kdb_last_sno &&
+ time_equal(&last->last_time, &ulog->kdb_last_time))
+ return UPDATE_NIL;
+
+ /* If our ulog is empty or does not contain last_sno, a full resync is
+ * required. */
+ if (ulog->kdb_num == 0 || last->last_sno > ulog->kdb_last_sno ||
+ last->last_sno < ulog->kdb_first_sno)
+ return UPDATE_FULL_RESYNC_NEEDED;
+
+ /* If the timestamp in our ulog entry does not match last, then sno was
+ * reused and a full resync is required. */
+ if (!check_sno(log_ctx, last->last_sno, &last->last_time))
+ return UPDATE_FULL_RESYNC_NEEDED;
+
+ /* last is not fully up to date, but can be updated using our ulog. */
+ return UPDATE_OK;
+}
+
/* Extend update log file. */
static int
extend_file_to(int fd, unsigned int new_size)
@@ -553,34 +596,11 @@ ulog_get_entries(krb5_context context, const kdb_last_t *last,
if (ulog->kdb_state != KDB_STABLE)
reset_header(ulog);
- /* If we have the same sno and timestamp, return a nil update. If a
- * different timestamp, the sno was reused and we need a full resync. */
- if (last->last_sno == ulog->kdb_last_sno) {
- ulog_handle->ret = time_equal(&last->last_time, &ulog->kdb_last_time) ?
- UPDATE_NIL : UPDATE_FULL_RESYNC_NEEDED;
- goto cleanup;
- }
-
- /* We may have overflowed the update log or shrunk the log, or the client
- * may have created its ulog. */
- if (last->last_sno > ulog->kdb_last_sno ||
- last->last_sno < ulog->kdb_first_sno) {
- ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
- ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
+ ulog_handle->ret = get_sno_status(log_ctx, last);
+ if (ulog_handle->ret != UPDATE_OK)
goto cleanup;
- }
sno = last->last_sno;
- indx = (sno - 1) % ulogentries;
- indx_log = INDEX(ulog, indx);
-
- if (!time_equal(&indx_log->kdb_time, &last->last_time)) {
- /* We have time stamp mismatch or we no longer have the slave's last
- * sno, so we brute force it. */
- ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
- goto cleanup;
- }
-
count = ulog->kdb_last_sno - sno;
upd = calloc(count, sizeof(kdb_incr_update_t));
if (upd == NULL) {
@@ -632,3 +652,15 @@ ulog_set_role(krb5_context ctx, iprop_role role)
ctx->kdblog_context->iproprole = role;
return 0;
}
+
+update_status_t
+ulog_get_sno_status(krb5_context context, const kdb_last_t *last)
+{
+ update_status_t status;
+
+ if (ulog_lock(context, KRB5_LOCKMODE_SHARED) != 0)
+ return UPDATE_ERROR;
+ status = get_sno_status(context->kdblog_context, last);
+ (void)ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return status;
+}
diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports
index e1c462efe5..67d4336ef1 100644
--- a/src/lib/kdb/libkdb5.exports
+++ b/src/lib/kdb/libkdb5.exports
@@ -95,5 +95,6 @@ xdr_kdb_last_t
xdr_kdb_incr_result_t
xdr_kdb_fullresync_result_t
ulog_get_entries
+ulog_get_sno_status
ulog_replay
xdr_kdb_incr_update_t