diff options
-rw-r--r-- | src/include/kdb_log.h | 2 | ||||
-rw-r--r-- | src/kadmin/dbutil/dump.c | 47 | ||||
-rw-r--r-- | src/lib/kdb/kdb_log.c | 82 | ||||
-rw-r--r-- | src/lib/kdb/libkdb5.exports | 1 |
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 |