@@ -217,53 +217,56 @@ void txn_metadata_t::update_txn_decision(gaia_txn_id_t commit_ts, bool is_commit
217217 // The commit_ts metadata must be in state TXN_VALIDATING or TXN_DECIDED.
218218 // We allow the latter to enable idempotent concurrent validation.
219219 txn_metadata_t commit_ts_metadata (commit_ts);
220+
220221 common::retail_assert (
221222 commit_ts_metadata.is_validating () || commit_ts_metadata.is_decided (),
222223 " commit_ts metadata must be in validating or decided state!" );
223224
224- uint64_t decided_status_flags
225- = is_committed ? c_txn_status_committed : c_txn_status_aborted;
225+ uint64_t decided_status_flags{is_committed ? c_txn_status_committed : c_txn_status_aborted};
226226
227- // We can just reuse the log fd and begin_ts from the existing metadata.
228- //
229- // REVIEW: This condition is probably rare enough that it's not worth optimizing
230- // and we can just let the CAS fail if another thread validated the txn before we did.
231- //
232- // We may have already been validated by another committing txn.
233- if (commit_ts_metadata.is_decided ())
234- {
235- // If another txn validated before us, they should have reached the same decision.
236- common::retail_assert (
237- commit_ts_metadata.is_committed () == is_committed,
238- " Inconsistent txn decision detected!" );
227+ txn_metadata_t decided_commit_ts_metadata = commit_ts_metadata;
239228
240- return ;
241- }
229+ // This masks out just the commit_ts flag bits.
230+ constexpr uint64_t c_commit_flags_mask = ~(~c_txn_status_commit_ts << c_txn_status_flags_shift);
242231
243- txn_metadata_t expected_metadata = commit_ts_metadata;
232+ // Turn off all commit flag bits before turning on the bits for this decision.
233+ decided_commit_ts_metadata.m_value &= c_commit_flags_mask;
244234
245- // It's safe to just OR in the new flags because the preceding states don't set
246- // any bits not present in the flags.
247- commit_ts_metadata.m_value |= (decided_status_flags << c_txn_status_flags_shift);
235+ // Now set the decision flags.
236+ decided_commit_ts_metadata.m_value |= (decided_status_flags << c_txn_status_flags_shift);
237+
238+ bool has_set_metadata = compare_exchange_strong (commit_ts_metadata, decided_commit_ts_metadata);
248239
249- bool has_set_metadata = compare_exchange_strong (
250- expected_metadata, commit_ts_metadata);
251240 if (!has_set_metadata)
252241 {
253- // NB: expected_metadata is an inout argument holding the previous value on failure!
242+ // The only state transition allowed from TXN_VALIDATING is to TXN_DECIDED.
254243 common::retail_assert (
255- expected_metadata .is_decided (),
244+ commit_ts_metadata .is_decided (),
256245 " commit_ts metadata in validating state can only transition to a decided state!" );
257246
258247 // If another txn validated before us, they should have reached the same decision.
259248 common::retail_assert (
260- expected_metadata .is_committed () == is_committed,
249+ commit_ts_metadata .is_committed () == is_committed,
261250 " Inconsistent txn decision detected!" );
262-
263- return ;
264251 }
265252}
266253
254+ void txn_metadata_t::set_txn_durable (gaia_txn_id_t commit_ts)
255+ {
256+ txn_metadata_t commit_ts_metadata (commit_ts);
257+
258+ txn_metadata_t durable_commit_ts_metadata;
259+ do
260+ {
261+ // NB: commit_ts_metadata is an inout argument holding the previous value
262+ // on failure!
263+ durable_commit_ts_metadata = commit_ts_metadata;
264+
265+ durable_commit_ts_metadata.m_value |= (c_txn_persistence_complete << c_txn_persistence_flags_shift);
266+
267+ } while (!compare_exchange_weak (commit_ts_metadata, durable_commit_ts_metadata));
268+ }
269+
267270bool txn_metadata_t::set_txn_gc_complete (gaia_txn_id_t commit_ts)
268271{
269272 txn_metadata_t commit_ts_metadata (commit_ts);
0 commit comments