krb5 commit: Maintain complete ulog on iprop slaves
Greg Hudson
ghudson at MIT.EDU
Thu Feb 20 21:25:33 EST 2014
https://github.com/krb5/krb5/commit/406c83c835a8ce062d798a2ec4eda2eddd088450
commit 406c83c835a8ce062d798a2ec4eda2eddd088450
Author: Greg Hudson <ghudson at mit.edu>
Date: Sat Jan 25 14:40:41 2014 -0500
Maintain complete ulog on iprop slaves
Factor out most of ulog_add_update into a helper function named
store_update, and make ulog_add_update just responsible for assigning
a serial number and timestamp to the update before storing it. In
ulog_replay, use store_update and ulog_finish_update to add each
update to the ulog in addition to replaying it to the database. Don't
use incr_ret->lastentry to set kdb_last_sno/kdb_last_time, since it
will have been set properly by adding the individual updates; instead,
just reinitialize the ulog on error.
Slave ulogs use serial numbers provided from upstream, and thus do not
always begin at serial number 1 after a header reset. As a result, we
must: (A) in store_update, detect the first update (for which we must
assign kdb_first_sno/kdb_first_time) by comparing kdb_num to 0,
instead of by comparing the serial number to 1; (B) in store_update,
detect that we are overwriting the first update by comparing kdb_num
to ulogentries, instead of comparing the serial number to ulogentries;
and (C) in ulog_map, detect that ulogentries changed by verifying the
first and last serial number and timestamp against the actual ulog
entries, rather than simply comparing kdb_last_sno to kdb_num.
Based on code submitted by Richard Basch.
ticket: 7855
src/lib/kdb/kdb_log.c | 148 ++++++++++++++++++++++++-------------------------
1 files changed, 73 insertions(+), 75 deletions(-)
diff --git a/src/lib/kdb/kdb_log.c b/src/lib/kdb/kdb_log.c
index 6d60429..1a5b1b8 100644
--- a/src/lib/kdb/kdb_log.c
+++ b/src/lib/kdb/kdb_log.c
@@ -232,100 +232,99 @@ unlock_ulog(krb5_context context)
}
/*
- * Add an entry to the update log. The layout of the update log looks like:
+ * Add an update to the log. The update's kdb_entry_sno and kdb_time fields
+ * must already be set. The layout of the update log looks like:
*
* header log -> [ update header -> xdr(kdb_incr_update_t) ], ...
*/
-krb5_error_code
-ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
+static krb5_error_code
+store_update(kdb_log_context *log_ctx, kdb_incr_update_t *upd)
{
XDR xdrs;
- kdbe_time_t ktime;
kdb_ent_header_t *indx_log;
unsigned int i, recsize;
unsigned long upd_size;
krb5_error_code retval;
- kdb_sno_t cur_sno;
- kdb_log_context *log_ctx;
- kdb_hlog_t *ulog = NULL;
- uint32_t ulogentries;
- int ulogfd;
-
- INIT_ULOG(context);
- retval = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
- if (retval)
- return retval;
-
- ulogentries = log_ctx->ulogentries;
- ulogfd = log_ctx->ulogfd;
-
- time_current(&ktime);
+ kdb_hlog_t *ulog = log_ctx->ulog;
+ uint32_t ulogentries = log_ctx->ulogentries;
upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);
recsize = sizeof(kdb_ent_header_t) + upd_size;
if (recsize > ulog->kdb_block) {
- retval = resize(ulog, ulogentries, ulogfd, recsize);
+ retval = resize(ulog, ulogentries, log_ctx->ulogfd, recsize);
if (retval)
- goto cleanup;
+ return retval;
}
- /* If we have reached the last possible serial number, reinitialize the
- * ulog and start over. Slaves will do a full resync. */
- if (ulog->kdb_last_sno == (kdb_sno_t)-1)
- reset_header(ulog);
-
ulog->kdb_state = KDB_UNSTABLE;
- /* Get the next serial number and find its update entry. */
- cur_sno = ulog->kdb_last_sno + 1;
- i = (cur_sno - 1) % ulogentries;
+ i = (upd->kdb_entry_sno - 1) % ulogentries;
indx_log = INDEX(ulog, i);
memset(indx_log, 0, ulog->kdb_block);
indx_log->kdb_umagic = KDB_ULOG_MAGIC;
indx_log->kdb_entry_size = upd_size;
- indx_log->kdb_entry_sno = upd->kdb_entry_sno = cur_sno;
- indx_log->kdb_time = upd->kdb_time = ktime;
- indx_log->kdb_commit = upd->kdb_commit = FALSE;
+ indx_log->kdb_entry_sno = upd->kdb_entry_sno;
+ indx_log->kdb_time = upd->kdb_time;
+ indx_log->kdb_commit = FALSE;
xdrmem_create(&xdrs, (char *)indx_log->entry_data,
indx_log->kdb_entry_size, XDR_ENCODE);
- if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
- retval = KRB5_LOG_CONV;
- goto cleanup;
- }
+ if (!xdr_kdb_incr_update_t(&xdrs, upd))
+ return KRB5_LOG_CONV;
indx_log->kdb_commit = TRUE;
retval = sync_update(ulog, indx_log);
if (retval)
- goto cleanup;
+ return retval;
- if (ulog->kdb_num < ulogentries)
+ /* Modify the ulog header to reflect the new update. */
+ ulog->kdb_last_sno = upd->kdb_entry_sno;
+ ulog->kdb_last_time = upd->kdb_time;
+ if (ulog->kdb_num == 0) {
+ ulog->kdb_num = 1;
+ ulog->kdb_first_sno = upd->kdb_entry_sno;
+ ulog->kdb_first_time = upd->kdb_time;
+ } else if (ulog->kdb_num < ulogentries) {
ulog->kdb_num++;
-
- ulog->kdb_last_sno = cur_sno;
- ulog->kdb_last_time = ktime;
-
- if (cur_sno > ulogentries) {
- /* Once we've circled, kdb_first_sno is the sno of the next entry. */
+ } else {
+ /* We are circling; set kdb_first_sno and time to the next update. */
i = upd->kdb_entry_sno % ulogentries;
indx_log = INDEX(ulog, i);
ulog->kdb_first_sno = indx_log->kdb_entry_sno;
ulog->kdb_first_time = indx_log->kdb_time;
- } else if (cur_sno == 1) {
- /* This is the first update. */
- ulog->kdb_first_sno = 1;
- ulog->kdb_first_time = indx_log->kdb_time;
}
ulog->kdb_state = KDB_STABLE;
-
-cleanup:
sync_header(ulog);
+ return 0;
+}
+
+/* Add an entry to the update log. */
+krb5_error_code
+ulog_add_update(krb5_context context, kdb_incr_update_t *upd)
+{
+ krb5_error_code ret;
+ kdb_log_context *log_ctx;
+ kdb_hlog_t *ulog;
+
+ INIT_ULOG(context);
+ ret = lock_ulog(context, KRB5_LOCKMODE_EXCLUSIVE);
+ if (ret)
+ return ret;
+
+ /* If we have reached the last possible serial number, reinitialize the
+ * ulog and start over. Slaves will do a full resync. */
+ if (ulog->kdb_last_sno == (kdb_sno_t)-1)
+ reset_header(ulog);
+
+ upd->kdb_entry_sno = ulog->kdb_last_sno + 1;
+ time_current(&upd->kdb_time);
+ ret = store_update(log_ctx, upd);
unlock_ulog(context);
- return retval;
+ return ret;
}
/* Used by the slave to update its hash db from the incr update log. */
@@ -337,7 +336,6 @@ ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
int i, no_of_updates;
krb5_error_code retval;
krb5_principal dbprinc;
- kdb_last_t errlast, *last;
char *dbprincstr;
kdb_log_context *log_ctx;
kdb_hlog_t *ulog = NULL;
@@ -362,17 +360,15 @@ ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
upd = incr_ret->updates.kdb_ulog_t_val;
fupd = upd;
- /* We reset last_sno and last_time to 0, if krb5_db2_db_put_principal or
- * krb5_db2_db_delete_principal fail. */
- errlast.last_sno = (unsigned int)0;
- errlast.last_time.seconds = (unsigned int)0;
- errlast.last_time.useconds = (unsigned int)0;
- last = &errlast;
-
for (i = 0; i < no_of_updates; i++) {
if (!upd->kdb_commit)
continue;
+ /* If (unexpectedly) this update does not follow the last one we
+ * stored, discard any previous ulog state. */
+ if (ulog->kdb_num != 0 && upd->kdb_entry_sno != ulog->kdb_last_sno + 1)
+ reset_header(ulog);
+
if (upd->kdb_deleted) {
dbprincstr = k5memdup0(upd->kdb_princ_name.utf8str_t_val,
upd->kdb_princ_name.utf8str_t_len, &retval);
@@ -403,19 +399,20 @@ ulog_replay(krb5_context context, kdb_incr_result_t *incr_ret, char **db_args)
goto cleanup;
}
+ retval = store_update(log_ctx, upd);
+ if (retval)
+ goto cleanup;
+
upd++;
}
- last = &incr_ret->lastentry;
-
cleanup:
if (fupd)
ulog_free_entries(fupd, no_of_updates);
-
- /* Record a new last serial number and timestamp in the ulog header. */
- ulog->kdb_last_sno = last->last_sno;
- ulog->kdb_last_time = last->last_time;
- sync_header(ulog);
+ if (retval) {
+ reset_header(ulog);
+ sync_header(ulog);
+ }
unlock_ulog(context);
krb5_db_unlock(context);
return retval;
@@ -503,16 +500,17 @@ ulog_map(krb5_context context, const char *logname, uint32_t ulogentries)
sync_header(ulog);
}
- /* Reinit ulog if the log is being truncated or expanded after we have
- * circled. */
- if (ulog->kdb_num != ulogentries) {
- if (ulog->kdb_num != 0 &&
- (ulog->kdb_last_sno > ulog->kdb_num ||
- ulog->kdb_num > ulogentries)) {
- reset_header(ulog);
- sync_header(ulog);
- }
+ /* Reinit ulog if ulogentries changed such that we have too many entries or
+ * our first or last entry was written to the wrong location. */
+ if (ulog->kdb_num != 0 &&
+ (ulog->kdb_num > ulogentries ||
+ !check_sno(log_ctx, ulog->kdb_first_sno, &ulog->kdb_first_time) ||
+ !check_sno(log_ctx, ulog->kdb_last_sno, &ulog->kdb_last_time))) {
+ reset_header(ulog);
+ sync_header(ulog);
+ }
+ if (ulog->kdb_num != ulogentries) {
/* Expand the ulog file if it isn't big enough. */
filesize = sizeof(kdb_hlog_t) + ulogentries * ulog->kdb_block;
if (extend_file_to(ulogfd, filesize) < 0) {
More information about the cvs-krb5
mailing list