@@ -72,6 +72,12 @@ static gl_mg o_gl_mg;
// validate that no other update transaction comitted before we acquired the
// orec, so we have the most recent timestamp and no other transaction can
// commit until we have committed).
+// However, we therefore cannot use this method for a serial transaction
+// (because shared_state needs to remain at ~0) and we have to be careful
+// when switching to serial mode (see the special handling in trycommit() and
+// rollback()).
+// ??? This sharing adds some complexity wrt. serial mode. Just use a separate
+// state variable?
class gl_wt_dispatch : public abi_dispatch
{
protected:
@@ -202,10 +208,22 @@ public:
virtual bool trycommit(gtm_word& priv_time)
{
- // Release the orec but do not reset shared_state, which will be modified
- // by the serial lock right after our commit anyway.
gtm_thread* tx = gtm_thr();
gtm_word v = tx->shared_state;
+
+ // Special case: If shared_state is ~0, then we have acquired the
+ // serial lock (tx->state is not updated yet). In this case, the previous
+ // value isn't available anymore, so grab it from the global lock, which
+ // must have a meaningful value because no other transactions are active
+ // anymore. In particular, if it is locked, then we are an update
+ // transaction, which is all we care about for commit.
+ if (v == ~(typeof v)0)
+ v = o_gl_mg.orec;
+
+ // Release the orec but do not reset shared_state, which will be modified
+ // by the serial lock right after our commit anyway. Also, resetting
+ // shared state here would interfere with the serial lock's use of this
+ // location.
if (gl_mg::is_locked(v))
{
// Release the global orec, increasing its version number / timestamp.
@@ -228,11 +246,20 @@ public:
if (cp != 0)
return;
+ gtm_thread *tx = gtm_thr();
+ gtm_word v = tx->shared_state;
+ // Special case: If shared_state is ~0, then we have acquired the
+ // serial lock (tx->state is not updated yet). In this case, the previous
+ // value isn't available anymore, so grab it from the global lock, which
+ // must have a meaningful value because no other transactions are active
+ // anymore. In particular, if it is locked, then we are an update
+ // transaction, which is all we care about for rollback.
+ if (v == ~(typeof v)0)
+ v = o_gl_mg.orec;
+
// Release lock and increment version number to prevent dirty reads.
// Also reset shared state here, so that begin_or_restart() can expect a
// value that is correct wrt. privatization safety.
- gtm_thread *tx = gtm_thr();
- gtm_word v = tx->shared_state;
if (gl_mg::is_locked(v))
{
// Release the global orec, increasing its version number / timestamp.
@@ -242,7 +269,11 @@ public:
o_gl_mg.orec = v;
// Also reset the timestamp published via shared_state.
- tx->shared_state = v;
+ // Special case: Only do this if we are not a serial transaction
+ // because otherwise, we would interfere with the serial lock.
+ if (tx->shared_state != ~(typeof tx->shared_state)0)
+ tx->shared_state = v;
+
// We need a store-load barrier after this store to prevent it
// from becoming visible after later data loads because the
// previous value of shared_state has been higher than the actual