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.