/* * The index session contains a lock (the request_mutex) which ensures that only one thread can * change the state of its index at a time. The state field indicates the current state of the * index through a set of descriptive flags. The request_mutex must be notified whenever a * non-transient state flag is cleared. The request_mutex is also used to count the number of * requests currently in progress so that they can be drained when suspending or closing the index. * * If the index session is suspended shortly after opening an index, it may have to suspend during * a rebuild. Depending on the size of the index, a rebuild may take a significant amount of time, * so UDS allows the rebuild to be paused in order to suspend the session in a timely manner. When * the index session is resumed, the rebuild can continue from where it left off. If the index * session is shut down with a suspended rebuild, the rebuild progress is abandoned and the rebuild * will start from the beginning the next time the index is loaded. The mutex and status fields in * the index_load_context are used to record the state of any interrupted rebuild.
*/
enum index_session_flag_bit {
IS_FLAG_BIT_START = 8, /* The session has started loading an index but not completed it. */
IS_FLAG_BIT_LOADING = IS_FLAG_BIT_START, /* The session has loaded an index, which can handle requests. */
IS_FLAG_BIT_LOADED, /* The session's index has been permanently disabled. */
IS_FLAG_BIT_DISABLED, /* The session's index is suspended. */
IS_FLAG_BIT_SUSPENDED, /* The session is handling some index state change. */
IS_FLAG_BIT_WAITING, /* The session's index is closing and draining requests. */
IS_FLAG_BIT_CLOSING, /* The session is being destroyed and is draining requests. */
IS_FLAG_BIT_DESTROYING,
};
/* Release a reference to an index session. */ staticvoid release_index_session(struct uds_index_session *index_session)
{
mutex_lock(&index_session->request_mutex); if (--index_session->request_count == 0)
uds_broadcast_cond(&index_session->request_cond);
mutex_unlock(&index_session->request_mutex);
}
/* * Acquire a reference to the index session for an asynchronous index request. The reference must * eventually be released with a corresponding call to release_index_session().
*/ staticint get_index_session(struct uds_index_session *index_session)
{ unsignedint state; int result = UDS_SUCCESS;
mutex_lock(&index_session->request_mutex);
index_session->request_count++;
state = index_session->state;
mutex_unlock(&index_session->request_mutex);
if (state == IS_FLAG_LOADED) { return UDS_SUCCESS;
} elseif (state & IS_FLAG_DISABLED) {
result = UDS_DISABLED;
} elseif ((state & IS_FLAG_LOADING) ||
(state & IS_FLAG_SUSPENDED) ||
(state & IS_FLAG_WAITING)) {
result = -EBUSY;
} else {
result = UDS_NO_INDEX;
}
switch (request->type) { case UDS_DELETE: case UDS_POST: case UDS_QUERY: case UDS_QUERY_NO_UPDATE: case UDS_UPDATE: break; default:
vdo_log_error("received invalid callback type"); return -EINVAL;
}
/* Reset all internal fields before processing. */
memset(&request->internal, 0, sizeof(request->internal));
result = get_index_session(request->session); if (result != UDS_SUCCESS) return result;
case UDS_UPDATE: if (request->found)
count_once(&session_stats->updates_found); else
count_once(&session_stats->updates_not_found); break;
case UDS_DELETE: if (request->found)
count_once(&session_stats->deletions_found); else
count_once(&session_stats->deletions_not_found); break;
case UDS_QUERY: case UDS_QUERY_NO_UPDATE: if (request->found)
count_once(&session_stats->queries_found); else
count_once(&session_stats->queries_not_found); break;
result = uds_make_configuration(&index_session->parameters, &config); if (result != UDS_SUCCESS) {
vdo_log_error_strerror(result, "Failed to allocate config"); return result;
}
memset(&index_session->stats, 0, sizeof(index_session->stats));
result = uds_make_index(config, open_type, &index_session->load_context,
enter_callback_stage, &index_session->index); if (result != UDS_SUCCESS)
vdo_log_error_strerror(result, "Failed to make index"); else
uds_log_configuration(config);
uds_free_configuration(config); return result;
}
staticconstchar *get_open_type_string(enum uds_open_index_type open_type)
{ switch (open_type) { case UDS_CREATE: return"creating index"; case UDS_LOAD: return"loading or rebuilding index"; case UDS_NO_REBUILD: return"loading index"; default: return"unknown open method";
}
}
/* * Open an index under the given session. This operation will fail if the * index session is suspended, or if there is already an open index.
*/ int uds_open_index(enum uds_open_index_type open_type, conststruct uds_parameters *parameters, struct uds_index_session *session)
{ int result; char name[BDEVNAME_SIZE];
/* Wait until the index indicates that it is not replaying. */ while ((session->load_context.status != INDEX_SUSPENDED) &&
(session->load_context.status != INDEX_READY)) {
uds_wait_cond(&session->load_context.cond,
&session->load_context.mutex);
}
break;
case INDEX_READY: /* Index load does not need to be suspended. */ break;
case INDEX_SUSPENDED: case INDEX_SUSPENDING: case INDEX_FREEING: default: /* These cases should not happen. */
VDO_ASSERT_LOG_ONLY(false, "Bad load context state %u",
session->load_context.status); break;
}
mutex_unlock(&session->load_context.mutex);
}
/* * Suspend index operation, draining all current index requests and preventing new index requests * from starting. Optionally saves all index data before returning.
*/ int uds_suspend_index_session(struct uds_index_session *session, bool save)
{ int result = UDS_SUCCESS; bool no_work = false; bool rebuilding = false;
/* Wait for any current index state change to complete. */
mutex_lock(&session->request_mutex); while (session->state & IS_FLAG_CLOSING)
uds_wait_cond(&session->request_cond, &session->request_mutex);
/* * Resume index operation after being suspended. If the index is suspended and the supplied block * device differs from the current backing store, the index will start using the new backing store.
*/ int uds_resume_index_session(struct uds_index_session *session, struct block_device *bdev)
{ int result = UDS_SUCCESS; bool no_work = false; bool resume_replay = false;
mutex_lock(&session->request_mutex); if (session->state & IS_FLAG_WAITING) {
vdo_log_info("Index session is already changing state");
no_work = true;
result = -EBUSY;
} elseif (!(session->state & IS_FLAG_SUSPENDED)) { /* If not suspended, just succeed. */
no_work = true;
result = UDS_SUCCESS;
} else {
session->state |= IS_FLAG_WAITING; if (session->state & IS_FLAG_LOADING)
resume_replay = true;
}
mutex_unlock(&session->request_mutex);
if (no_work) return result;
if ((session->index != NULL) && (bdev != session->parameters.bdev)) {
result = replace_device(session, bdev); if (result != UDS_SUCCESS) {
mutex_lock(&session->request_mutex);
session->state &= ~IS_FLAG_WAITING;
uds_broadcast_cond(&session->request_cond);
mutex_unlock(&session->request_mutex); return uds_status_to_errno(result);
}
}
if (resume_replay) {
mutex_lock(&session->load_context.mutex); switch (session->load_context.status) { case INDEX_SUSPENDED:
session->load_context.status = INDEX_OPENING; /* Notify the index to start replaying again. */
uds_broadcast_cond(&session->load_context.cond); break;
case INDEX_READY: /* There is no index rebuild to resume. */ break;
case INDEX_OPENING: case INDEX_SUSPENDING: case INDEX_FREEING: default: /* These cases should not happen; do nothing. */
VDO_ASSERT_LOG_ONLY(false, "Bad load context state %u",
session->load_context.status); break;
}
mutex_unlock(&session->load_context.mutex);
}
if (!suspended) {
result = uds_save_index(index); if (result != UDS_SUCCESS)
vdo_log_warning_strerror(result, "ignoring error from save_index");
}
uds_free_index(index);
index_session->index = NULL;
/* * Reset all index state that happens to be in the index * session, so it doesn't affect any future index.
*/
mutex_lock(&index_session->load_context.mutex);
index_session->load_context.status = INDEX_OPENING;
mutex_unlock(&index_session->load_context.mutex);
mutex_lock(&index_session->request_mutex); /* Only the suspend bit will remain relevant. */
index_session->state &= IS_FLAG_SUSPENDED;
mutex_unlock(&index_session->request_mutex);
return result;
}
/* Save and close the current index. */ int uds_close_index(struct uds_index_session *index_session)
{ int result = UDS_SUCCESS;
/* Wait for any current index state change to complete. */
mutex_lock(&index_session->request_mutex); while ((index_session->state & IS_FLAG_WAITING) ||
(index_session->state & IS_FLAG_CLOSING)) {
uds_wait_cond(&index_session->request_cond,
&index_session->request_mutex);
}
if (index_session->state & IS_FLAG_SUSPENDED) {
vdo_log_info("Index session is suspended");
result = -EBUSY;
} elseif ((index_session->state & IS_FLAG_DESTROYING) ||
!(index_session->state & IS_FLAG_LOADED)) { /* The index doesn't exist, hasn't finished loading, or is being destroyed. */
result = UDS_NO_INDEX;
} else {
index_session->state |= IS_FLAG_CLOSING;
}
mutex_unlock(&index_session->request_mutex); if (result != UDS_SUCCESS) return uds_status_to_errno(result);
vdo_log_debug("Closing index");
wait_for_no_requests_in_progress(index_session);
result = save_and_free_index(index_session);
vdo_log_debug("Closed index");
/* This will save and close an open index before destroying the session. */ int uds_destroy_index_session(struct uds_index_session *index_session)
{ int result; bool load_pending = false;
vdo_log_debug("Destroying index session");
/* Wait for any current index state change to complete. */
mutex_lock(&index_session->request_mutex); while ((index_session->state & IS_FLAG_WAITING) ||
(index_session->state & IS_FLAG_CLOSING)) {
uds_wait_cond(&index_session->request_cond,
&index_session->request_mutex);
}
if (index_session->state & IS_FLAG_DESTROYING) {
mutex_unlock(&index_session->request_mutex);
vdo_log_info("Index session is already closing"); return -EBUSY;
}
if (load_pending) { /* Tell the index to terminate the rebuild. */
mutex_lock(&index_session->load_context.mutex); if (index_session->load_context.status == INDEX_SUSPENDED) {
index_session->load_context.status = INDEX_FREEING;
uds_broadcast_cond(&index_session->load_context.cond);
}
mutex_unlock(&index_session->load_context.mutex);
/* Wait until the load exits before proceeding. */
mutex_lock(&index_session->request_mutex); while (index_session->state & IS_FLAG_LOADING) {
uds_wait_cond(&index_session->request_cond,
&index_session->request_mutex);
}
mutex_unlock(&index_session->request_mutex);
}
wait_for_no_requests_in_progress(index_session);
result = save_and_free_index(index_session);
uds_request_queue_finish(index_session->callback_queue);
index_session->callback_queue = NULL;
vdo_log_debug("Destroyed index session");
vdo_free(index_session); return uds_status_to_errno(result);
}
/* Wait until all callbacks for index operations are complete. */ int uds_flush_index_session(struct uds_index_session *index_session)
{
wait_for_no_requests_in_progress(index_session);
uds_wait_for_idle_index(index_session->index); return UDS_SUCCESS;
}
/* Statistics collection is intended to be thread-safe. */ staticvoid collect_stats(conststruct uds_index_session *index_session, struct uds_index_stats *stats)
{ conststruct session_stats *session_stats = &index_session->stats;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.