diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 18e1b23c1c227f677c692f32da7e57fd82d58035..f1c3f126cab8ecd8c8df8e1592b13fd88cad67d8 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -2500,13 +2500,14 @@ vy_index_commit_create(struct vy_env *env, struct vy_index *index) * the index isn't in the recovery context and we * need to retry to log it now. */ - if (vy_recovery_lookup_index(env->recovery, - index->opts.lsn) != NULL) { + if (index->is_committed) { vy_scheduler_add_index(env->scheduler, index); return; } } + index->is_committed = true; + assert(index->range_count == 1); struct vy_range *range = vy_range_tree_first(index->tree); diff --git a/src/box/vy_index.c b/src/box/vy_index.c index 1dc4b465903dd01968bb4647a1e0b134383f73f6..22950e6aa6015d4a5845147b8bb9201d650b5d7e 100644 --- a/src/box/vy_index.c +++ b/src/box/vy_index.c @@ -366,7 +366,7 @@ struct vy_index_recovery_cb_arg { struct mh_i64ptr_t *run_hash; }; -/** Index recovery callback, passed to vy_recovery_iterate_index(). */ +/** Index recovery callback, passed to vy_recovery_load_index(). */ static int vy_index_recovery_cb(const struct vy_log_record *record, void *cb_arg) { @@ -380,6 +380,8 @@ vy_index_recovery_cb(const struct vy_log_record *record, void *cb_arg) struct vy_slice *slice; bool success = false; + assert(record->type == VY_LOG_CREATE_INDEX || index->is_committed); + if (record->type == VY_LOG_INSERT_RANGE || record->type == VY_LOG_INSERT_SLICE) { if (record->begin != NULL) { @@ -397,6 +399,7 @@ vy_index_recovery_cb(const struct vy_log_record *record, void *cb_arg) switch (record->type) { case VY_LOG_CREATE_INDEX: assert(record->index_lsn == index->opts.lsn); + index->is_committed = true; break; case VY_LOG_DUMP_INDEX: assert(record->index_lsn == index->opts.lsn); @@ -478,18 +481,6 @@ vy_index_recover(struct vy_index *index, struct vy_recovery *recovery, { assert(index->range_count == 0); - struct vy_index_recovery_info *ri; - ri = vy_recovery_lookup_index(recovery, index->opts.lsn); - if (ri == NULL) { - if (!allow_missing) { - diag_set(ClientError, ER_INVALID_VYLOG_FILE, - tt_sprintf("Index %lld not found", - (long long)index->opts.lsn)); - return -1; - } - return vy_index_create(index); - } - struct vy_index_recovery_cb_arg arg = { .index = index }; arg.run_hash = mh_i64ptr_new(); if (arg.run_hash == NULL) { @@ -497,27 +488,45 @@ vy_index_recover(struct vy_index *index, struct vy_recovery *recovery, return -1; } - int rc = vy_recovery_iterate_index(ri, false, - vy_index_recovery_cb, &arg); + int rc = vy_recovery_load_index(recovery, index->opts.lsn, + vy_index_recovery_cb, &arg); mh_int_t k; mh_foreach(arg.run_hash, k) { struct vy_run *run = mh_i64ptr_node(arg.run_hash, k)->val; - if (run->refs == 1) { + if (run->refs > 1) + vy_index_add_run(index, run); + if (run->refs == 1 && rc == 0) { diag_set(ClientError, ER_INVALID_VYLOG_FILE, tt_sprintf("Unused run %lld in index %lld", (long long)run->id, (long long)index->opts.lsn)); rc = -1; - } else - vy_index_add_run(index, run); + /* + * Continue the loop to unreference + * all runs in the hash. + */ + } /* Drop the reference held by the hash. */ vy_run_unref(run); } mh_i64ptr_delete(arg.run_hash); - if (rc != 0) + if (rc != 0) { + /* Recovery callback failed. */ return -1; + } + + if (!index->is_committed) { + /* Index was not found in the metadata log. */ + if (!allow_missing) { + diag_set(ClientError, ER_INVALID_VYLOG_FILE, + tt_sprintf("Index %lld not found", + (long long)index->opts.lsn)); + return -1; + } + return vy_index_create(index); + } /* * Account ranges to the index and check that the range tree diff --git a/src/box/vy_index.h b/src/box/vy_index.h index 68227a6ee62b6e1abfdf03179979a1ef9748417c..187b73a77ad32c5c6b06f2dee07e5b4b36af2959 100644 --- a/src/box/vy_index.h +++ b/src/box/vy_index.h @@ -219,6 +219,11 @@ struct vy_index { * been dumped yet. */ int64_t dump_lsn; + /** + * This flag is set if the index creation was + * committed to the metadata log. + */ + bool is_committed; /** * This flag is set if the index was dropped. * It is also set on local recovery if the index diff --git a/src/box/vy_log.c b/src/box/vy_log.c index e2e96a90f063e01e1549cb9f244856ba5732c839..965a83a192e80d34d21f1661511506a4b4e371f4 100644 --- a/src/box/vy_log.c +++ b/src/box/vy_log.c @@ -1227,7 +1227,7 @@ vy_log_write(const struct vy_log_record *record) } /** Lookup a vinyl index in vy_recovery::index_hash map. */ -struct vy_index_recovery_info * +static struct vy_index_recovery_info * vy_recovery_lookup_index(struct vy_recovery *recovery, int64_t index_lsn) { struct mh_i64ptr_t *h = recovery->index_hash; @@ -2007,7 +2007,7 @@ vy_recovery_cb_call(vy_recovery_cb cb, void *cb_arg, return cb(record, cb_arg); } -int +static int vy_recovery_iterate_index(struct vy_index_recovery_info *index, bool include_deleted, vy_recovery_cb cb, void *cb_arg) { @@ -2152,3 +2152,14 @@ vy_recovery_iterate(struct vy_recovery *recovery, bool include_deleted, } return 0; } + +int +vy_recovery_load_index(struct vy_recovery *recovery, int64_t index_lsn, + vy_recovery_cb cb, void *cb_arg) +{ + struct vy_index_recovery_info *index; + index = vy_recovery_lookup_index(recovery, index_lsn); + if (index == NULL) + return 0; + return vy_recovery_iterate_index(index, false, cb, cb_arg); +} diff --git a/src/box/vy_log.h b/src/box/vy_log.h index 1f529af1b4c8f8a67dcd4d0c3de6aa72db3ae68a..06881fcb1aec6ded59ffbba88b9a140fe59558ec 100644 --- a/src/box/vy_log.h +++ b/src/box/vy_log.h @@ -59,7 +59,6 @@ struct vclock; struct key_def; struct vy_recovery; -struct vy_index_recovery_info; /** Type of a metadata log record. */ enum vy_log_record_type { @@ -354,30 +353,18 @@ vy_recovery_new(int64_t signature, bool only_snapshot); void vy_recovery_delete(struct vy_recovery *recovery); -/** - * Lookup a vinyl index in a recovery context. - * - * Returns the index handle that can be used for recovering the - * index structure with the aid of vy_recovery_iterate_index() - * or NULL if the index is not found. - */ -struct vy_index_recovery_info * -vy_recovery_lookup_index(struct vy_recovery *recovery, int64_t index_lsn); - typedef int (*vy_recovery_cb)(const struct vy_log_record *record, void *arg); /** - * Recover a vinyl index from a recovery context. + * Iterate over all objects stored in a recovery context. + * + * This function invokes callback @cb for each object (index, run, etc) + * stored in the given recovery context. The callback is passed a record + * used to log the object and optional argument @cb_arg. If the callback + * returns a value different from 0, iteration stops and -1 is returned, + * otherwise the function returns 0. * - * For each range and run of the index, this function calls @cb passing - * a log record and an optional @cb_arg to it. A log record type is - * either VY_LOG_CREATE_INDEX, VY_LOG_CREATE_RUN, VY_LOG_INSERT_RANGE, - * or VY_LOG_INSERT_SLICE unless the index was dropped. In the latter case, - * a VY_LOG_DROP_INDEX record is issued in the end. - * The callback is supposed to rebuild the index structure and open run - * files. If the callback returns a non-zero value, the function stops - * iteration over ranges and runs and returns error. * To ease the work done by the callback, records corresponding to * slices of a range always go right after the range, in the * chronological order, while an index's runs go after the index @@ -386,22 +373,24 @@ typedef int * If @include_deleted is set, this function will also iterate over * deleted objects, issuing the corresponding "delete" record for each * of them. - * - * Returns 0 on success, -1 on failure. */ int -vy_recovery_iterate_index(struct vy_index_recovery_info *index, - bool include_deleted, vy_recovery_cb cb, void *cb_arg); +vy_recovery_iterate(struct vy_recovery *recovery, bool include_deleted, + vy_recovery_cb cb, void *cb_arg); /** - * Given a recovery context, iterate over all indexes stored in it. - * See vy_recovery_iterate_index() for more details. + * Load an index from a recovery context. * - * Returns 0 on success, -1 on failure. + * Call @cb for each object related to the index. Break the loop and + * return -1 if @cb returned a non-zero value, otherwise return 0. + * Objects are loaded in the same order as by vy_recovery_iterate(). + * + * Note, this function returns 0 if there's no index with the requested + * id in the recovery context. In this case, @cb isn't called at all. */ int -vy_recovery_iterate(struct vy_recovery *recovery, bool include_deleted, - vy_recovery_cb cb, void *cb_arg); +vy_recovery_load_index(struct vy_recovery *recovery, int64_t index_lsn, + vy_recovery_cb cb, void *cb_arg); /** * Initialize a log record with default values.