]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Factor out ulog serial number status check
authorGreg Hudson <ghudson@mit.edu>
Mon, 20 Jan 2014 23:46:52 +0000 (18:46 -0500)
committerGreg Hudson <ghudson@mit.edu>
Thu, 20 Feb 2014 20:55:48 +0000 (15:55 -0500)
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.

src/include/kdb_log.h
src/kadmin/dbutil/dump.c
src/lib/kdb/kdb_log.c
src/lib/kdb/libkdb5.exports

index c61b285a4cf71b7212079fb1c367be80256c4668..35b9d55655704d406068310793f8825e8096153d 100644 (file)
@@ -82,6 +82,8 @@ krb5_error_code ulog_conv_2dbentry(krb5_context context, krb5_db_entry **entry,
 void ulog_free_entries(kdb_incr_update_t *updates, int no_of_updates);
 krb5_error_code ulog_set_role(krb5_context ctx, iprop_role role);
 krb5_error_code ulog_lock(krb5_context ctx, int mode);
+update_status_t ulog_get_sno_status(krb5_context context,
+                                    const kdb_last_t *last);
 
 typedef struct kdb_hlog {
     uint32_t        kdb_hmagic;     /* Log header magic # */
index ab96ca724f6e3d9b88235b492b0b2a79ebfbef6e..a94fb31303f4693b51d7e6f7be7b02e6a6b70dc3 100644 (file)
@@ -1146,8 +1146,7 @@ dump_version ipropx_1_version = {
 /* Read the dump header.  Return 1 on success, 0 if the file is not a
  * recognized iprop dump format. */
 static int
-parse_iprop_header(char *buf, dump_version **dv, uint32_t *last_sno,
-                   uint32_t *last_seconds, uint32_t *last_useconds)
+parse_iprop_header(char *buf, dump_version **dv, kdb_last_t *last)
 {
     char head[128];
     int nread;
@@ -1180,25 +1179,23 @@ parse_iprop_header(char *buf, dump_version **dv, uint32_t *last_sno,
         return 0;
     }
 
-    *last_sno = *up++;
-    *last_seconds = *up++;
-    *last_useconds = *up++;
+    last->last_sno = *up++;
+    last->last_time.seconds = *up++;
+    last->last_time.useconds = *up++;
     return 1;
 }
 
-/* Return 1 if the {sno, timestamp} in an existing dump file is in the
- * ulog, else return 0. */
-static int
-current_dump_sno_in_ulog(char *ifile, kdb_hlog_t *ulog)
+/* Return true if the serial number and timestamp in an existing dump file is
+ * in the ulog. */
+static krb5_boolean
+current_dump_sno_in_ulog(krb5_context context, const char *ifile)
 {
+    update_status_t status;
     dump_version *junk;
-    uint32_t last_sno, last_seconds, last_useconds;
+    kdb_last_t last;
     char buf[BUFSIZ];
     FILE *f;
 
-    if (ulog->kdb_last_sno == 0)
-        return 0;              /* nothing in ulog */
-
     f = fopen(ifile, "r");
     if (f == NULL)
         return 0;              /* aliasing other errors to ENOENT here is OK */
@@ -1207,17 +1204,11 @@ current_dump_sno_in_ulog(char *ifile, kdb_hlog_t *ulog)
         return errno ? -1 : 0;
     fclose(f);
 
-    if (!parse_iprop_header(buf, &junk, &last_sno, &last_seconds,
-                            &last_useconds))
+    if (!parse_iprop_header(buf, &junk, &last))
         return 0;
 
-    if (ulog->kdb_first_sno > last_sno ||
-        ulog->kdb_first_time.seconds > last_seconds ||
-        (ulog->kdb_first_time.seconds == last_seconds &&
-        ulog->kdb_first_time.useconds > last_useconds))
-        return 0;
-
-    return 1;
+    status = ulog_get_sno_status(context, &last);
+    return status == UPDATE_OK || status == UPDATE_NIL;
 }
 
 /*
@@ -1316,7 +1307,7 @@ dump_db(int argc, char **argv)
                       "use only for iprop dumps"));
             goto error;
         }
-        if (current_dump_sno_in_ulog(ofile, log_ctx->ulog))
+        if (current_dump_sno_in_ulog(util_context, ofile))
             return;
     }
 
@@ -1483,9 +1474,9 @@ load_db(int argc, char **argv)
     dump_version *load = NULL;
     int aindex;
     kdb_log_context *log_ctx;
+    kdb_last_t last;
     krb5_boolean db_locked = FALSE, temp_db_created = FALSE;
     krb5_boolean verbose = FALSE, update = FALSE, iprop_load = FALSE;
-    uint32_t last_sno, last_seconds, last_useconds;
 
     /* Parse the arguments. */
     dbname = global_params.dbname;
@@ -1629,8 +1620,7 @@ load_db(int argc, char **argv)
         log_ctx->iproprole = IPROP_SLAVE;
         if (iprop_load) {
             /* Parse the iprop header information. */
-            if (!parse_iprop_header(buf, &load, &last_sno, &last_seconds,
-                                    &last_useconds))
+            if (!parse_iprop_header(buf, &load, &last))
                 goto error;
         }
     }
@@ -1666,9 +1656,8 @@ load_db(int argc, char **argv)
              * record the iprop state if we received it. */
             ulog_init_header(util_context);
             if (iprop_load) {
-                log_ctx->ulog->kdb_last_sno = last_sno;
-                log_ctx->ulog->kdb_last_time.seconds = last_seconds;
-                log_ctx->ulog->kdb_last_time.useconds = last_useconds;
+                log_ctx->ulog->kdb_last_sno = last.last_sno;
+                log_ctx->ulog->kdb_last_time = last.last_time;
                 ulog_sync_header(log_ctx->ulog);
             }
         }
index ca40a4fe52202dc58da09844f5b4099a5d1a2261..dcc1bcf447b1e3c2ffe86d3591836929ad758733 100644 (file)
@@ -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;
+}
index e1c462efe56ac0e4d46973dd83e1cc231348b0f8..67d4336ef1fb8131af94426864cead1a4467f033 100644 (file)
@@ -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