while (cursor->next(cursor) == 0) {
cursor->get_key(cursor, &key);
cursor->get_value(cursor, &value);
/* For now just switch tiers which just does metadata manipulation. */
if (WT_PREFIX_MATCH(key, "tiered:")) {
__wt_verbose(
session, WT_VERB_TIERED, "FLUSH_TIER_ONCE: %s %s 0x%" PRIx32, key, value, flags);
if (!LF_ISSET(WT_FLUSH_TIER_FORCE)) {
/*
* Check the table's last checkpoint time and only flush trees that have a
* checkpoint more recent than the last flush time.
*/
WT_ERR(__wt_meta_checkpoint(session, key, NULL, &ckpt));
/*
* XXX If/when flush tier no longer requires the checkpoint lock, this needs
* consideration.
*/
ckpt_time = ckpt.sec;
__wt_meta_checkpoint_free(session, &ckpt);
WT_ERR(__wt_config_getones(session, value, "flush_time", &cval));
/* If nothing has changed, there's nothing to do. */
if (ckpt_time == 0 || (uint64_t)cval.val > ckpt_time) {
WT_STAT_CONN_INCR(session, flush_tier_skipped);
continue;
}
}
/* Only instantiate the handle if we need to flush. */
WT_ERR(__wt_session_get_dhandle(session, key, NULL, NULL, 0));
/*
* When we call wt_tiered_switch the session->dhandle points to the tiered: entry and
* the arg is the config string that is currently in the metadata.
*/
WT_ERR(__wt_tiered_switch(session, value));
WT_STAT_CONN_INCR(session, flush_tier_switched);
WT_ERR(__wt_session_release_dhandle(session));
}
}
WT_ERR(__wt_metadata_cursor_release(session, &cursor));
return (0);
err:
WT_TRET(__wt_session_release_dhandle(session));
WT_TRET(__wt_metadata_cursor_release(session, &cursor));
return (ret);
The line WT_ERR(__wt_session_get_dhandle(session, key, NULL, NULL, 0)); may fail without locking the dhandle. Therefore, in the error path, we may unlock the dhandle without locking it before.