/* * __wt_log_slot_close -- * Close a slot and do not allow any other threads to join this slot. * Remove this from the active slot array and move a new slot from * the pool into its place. Set up the size of this group; * Must be called with the logging spinlock held. */ int __wt_log_slot_close(WT_SESSION_IMPL *session, WT_LOGSLOT *slot) { WT_CONNECTION_IMPL *conn; WT_LOG *log; WT_LOGSLOT *newslot; int64_t old_state; conn = S2C(session); log = conn->log; /* * Find an unused slot in the pool. */ WT_RET(__log_slot_find_free(session, &newslot)); /* * Swap out the slot we're going to use and put a free one in the * slot array in its place so that threads can use it right away. */ WT_STAT_FAST_CONN_INCR(session, log_slot_closes); newslot->slot_state = WT_LOG_SLOT_READY; newslot->slot_index = slot->slot_index; log->slot_array[newslot->slot_index] = newslot; old_state = WT_ATOMIC_STORE8(slot->slot_state, WT_LOG_SLOT_PENDING); slot->slot_group_size = (uint64_t)(old_state - WT_LOG_SLOT_READY); /* * Note that this statistic may be much bigger than in reality, * especially when compared with the total bytes written in * __log_fill. The reason is that this size reflects any * rounding up that is needed and the total bytes in __log_fill * is the amount of user bytes. */ WT_STAT_FAST_CONN_INCRV(session, log_slot_consolidated, (uint64_t)slot->slot_group_size); return (0); }
/* * __wt_log_slot_close -- * Close a slot and do not allow any other threads to join this slot. * Remove this from the active slot array and move a new slot from * the pool into its place. Set up the size of this group; * Must be called with the logging spinlock held. */ int __wt_log_slot_close(WT_SESSION_IMPL *session, WT_LOGSLOT *slot) { WT_CONNECTION_IMPL *conn; WT_LOG *log; WT_LOGSLOT *newslot; int64_t old_state; int32_t yields; uint32_t pool_i, switch_fails; conn = S2C(session); log = conn->log; switch_fails = 0; retry: /* * Find an unused slot in the pool. */ pool_i = log->pool_index; newslot = &log->slot_pool[pool_i]; if (++log->pool_index >= SLOT_POOL) log->pool_index = 0; if (newslot->slot_state != WT_LOG_SLOT_FREE) { WT_STAT_FAST_CONN_INCR(session, log_slot_switch_fails); /* * If it takes a number of attempts to find an available slot * it's likely all slots are waiting to be released. This * churn is used to change how long we pause before closing * the slot - which leads to more consolidation and less churn. */ if (++switch_fails % SLOT_POOL == 0 && switch_fails != 0 && slot->slot_churn < 5) ++slot->slot_churn; __wt_yield(); goto retry; } else if (slot->slot_churn > 0) { --slot->slot_churn; WT_ASSERT(session, slot->slot_churn >= 0); } /* Pause to allow other threads a chance to consolidate. */ for (yields = slot->slot_churn; yields >= 0; yields--) __wt_yield(); /* * Swap out the slot we're going to use and put a free one in the * slot array in its place so that threads can use it right away. */ WT_STAT_FAST_CONN_INCR(session, log_slot_closes); newslot->slot_state = WT_LOG_SLOT_READY; newslot->slot_index = slot->slot_index; log->slot_array[newslot->slot_index] = &log->slot_pool[pool_i]; old_state = WT_ATOMIC_STORE8(slot->slot_state, WT_LOG_SLOT_PENDING); slot->slot_group_size = (uint64_t)(old_state - WT_LOG_SLOT_READY); /* * Note that this statistic may be much bigger than in reality, * especially when compared with the total bytes written in * __log_fill. The reason is that this size reflects any * rounding up that is needed and the total bytes in __log_fill * is the amount of user bytes. */ WT_STAT_FAST_CONN_INCRV(session, log_slot_consolidated, (uint64_t)slot->slot_group_size); return (0); }