summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/kdb_log.h2
-rw-r--r--src/kadmin/dbutil/dump.c47
-rw-r--r--src/lib/kdb/kdb_log.c82
-rw-r--r--src/lib/kdb/libkdb5.exports1
4 files changed, 78 insertions, 54 deletions
diff --git a/src/include/kdb_log.h b/src/include/kdb_log.h
index c61b285a4c..35b9d55655 100644
--- a/src/include/kdb_log.h
+++ b/src/include/kdb_log.h
@@ -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 # */
diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index ab96ca724f..a94fb31303 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -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);
}
}
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