event_counter m_nInsertFailed; ///< Number of failed \p insert() operations
event_counter m_nInsertRetry; ///< Number of attempts to insert new item
event_counter m_nReuseNode; ///< Number of reusing empty node when inserting/updating
- event_counter m_nReuseNodeFailed; ///< Number of failed attempsof reusing free node when inserting/updating
+ event_counter m_nReuseNodeMarkFailed; ///< Number of unsuccessful marking attempts when we try to reuse node
+ event_counter m_nReuseNodeSeqBreak; ///< Number of breaking sequence of \p prev -> \p next node when we try to reuse \p prev node
event_counter m_nUpdateNew; ///< Number of new item inserted for \p update()
event_counter m_nUpdateExisting; ///< Number of existing item updates
event_counter m_nUpdateFailed; ///< Number of failed \p update() call
void onInsertFailed() { ++m_nInsertFailed; }
void onInsertRetry() { ++m_nInsertRetry; }
void onReuseNode() { ++m_nReuseNode; }
- void onReuseNodeFailed() { ++m_nReuseNodeFailed; }
+ void onReuseNodeMarkFailed(){ ++m_nReuseNodeMarkFailed; }
+ void onReuseNodeSeqBreak() { ++m_nReuseNodeSeqBreak; }
void onUpdateNew() { ++m_nUpdateNew; }
void onUpdateExisting() { ++m_nUpdateExisting; }
void onUpdateFailed() { ++m_nUpdateFailed; }
void onInsertFailed() const {}
void onInsertRetry() const {}
void onReuseNode() const {}
- void onReuseNodeFailed() const {}
+ void onReuseNodeMarkFailed() const {}
+ void onReuseNodeSeqBreak() const {}
void onUpdateNew() const {}
void onUpdateExisting() const {}
void onUpdateFailed() const {}
void onInsertFailed() { m_stat.onInsertFailed(); }
void onInsertRetry() { m_stat.onInsertRetry(); }
void onReuseNode() { m_stat.onReuseNode(); }
- void onReuseNodeFailed() { m_stat.onReuseNodeFailed(); }
+ void onReuseNodeMarkFailed() { m_stat.onReuseNodeMarkFailed(); }
+ void onReuseNodeSeqBreak() { m_stat.onReuseNodeSeqBreak(); }
void onUpdateNew() { m_stat.onUpdateNew(); }
void onUpdateExisting() { m_stat.onUpdateExisting();}
void onUpdateFailed() { m_stat.onUpdateFailed(); }
marked_data_ptr val( pos.pFound );
if ( pos.pCur && !pos.pCur->data.compare_exchange_strong( val, val | 1, memory_model::memory_order_acquire, atomics::memory_order_relaxed )) {
// oops, pos.pCur data has been changed or another thread is setting pos.pPrev data
- m_Stat.onReuseNodeFailed();
+ m_Stat.onReuseNodeMarkFailed();
+ return false;
+ }
+
+ if ( pos.pPrev->next.load( memory_model::memory_order_acquire ) != pos.pCur ) {
+ // sequence pPrev - pCur is broken
+ if ( pos.pCur )
+ pos.pCur->data.store( val, memory_model::memory_order_relaxed );
+ m_Stat.onReuseNodeSeqBreak();
return false;
}
<< CDSSTRESS_STAT_OUT( s, m_nInsertFailed )
<< CDSSTRESS_STAT_OUT( s, m_nInsertRetry )
<< CDSSTRESS_STAT_OUT( s, m_nReuseNode )
- << CDSSTRESS_STAT_OUT( s, m_nReuseNodeFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nReuseNodeMarkFailed )
+ << CDSSTRESS_STAT_OUT( s, m_nReuseNodeSeqBreak )
<< CDSSTRESS_STAT_OUT( s, m_nUpdateNew )
<< CDSSTRESS_STAT_OUT( s, m_nUpdateExisting )
<< CDSSTRESS_STAT_OUT( s, m_nUpdateFailed )