Exemple #1
0
VOID CMutexRWLock::WaitToRead()
{
	BOOL bWait = FALSE;

	{
		CSpinLock locallock(m_cs);

		if(m_nActive > 0)
			++m_nActive;
		else if(m_nActive == 0)
		{
			if(m_mtx.try_lock_shared())
			{
				++m_nReadCount;
				++m_nActive;
			}
			else
				bWait = TRUE;
		}
		else if(!IsOwner())
			bWait = TRUE;
	}

	if(bWait)
	{
		m_mtx.lock_shared();

		CSpinLock locallock(m_cs);

		{
			++m_nReadCount;
			++m_nActive;
		}
	}
}
PIDFile::~PIDFile()
{
	if (IsOwner())
	{
		Remove();
	}
}
// release write lock on a tuple.
// one example usage of this method is when a tuple is acquired, but operation
// (insert,update,delete) can't proceed, the executor needs to yield the
// ownership before return false to upper layer.
// It should not be called if the tuple is in the write set as commit and abort
// will release the write lock anyway.
void TimestampOrderingTransactionManager::YieldOwnership(
    UNUSED_ATTRIBUTE TransactionContext *const current_txn,
    const storage::TileGroupHeader *const tile_group_header,
    const oid_t &tuple_id) {
  PL_ASSERT(IsOwner(current_txn, tile_group_header, tuple_id));
  tile_group_header->SetTransactionId(tuple_id, INITIAL_TXN_ID);
}
bool PessimisticTxnManager::AcquireOwnership(
    const storage::TileGroupHeader *const tile_group_header,
    const oid_t &tile_group_id, const oid_t &tuple_id) {
  LOG_TRACE("AcquireOwnership");
  assert(IsOwner(tile_group_header, tuple_id) == false);

  // acquire write lock.
  // No writer, release read lock that is acquired before
  // Must success
  ReleaseReadLock(tile_group_header, tuple_id);
  
  pessimistic_released_rdlock[tile_group_id].insert(tuple_id);

  // Try get write lock
  auto current_txn_id = current_txn->GetTransactionId();
  bool res = tile_group_header->SetAtomicTransactionId(tuple_id, PACK_TXNID(current_txn_id, 0));

  if (res) {
    return true;
  } else {
    LOG_INFO("Fail to acquire write lock. Set txn failure.");
    // SetTransactionResult(Result::RESULT_FAILURE);
    return false;
  }
}
Exemple #5
0
VOID CRWLock::WaitToRead()
{
	BOOL bWait = FALSE;

	{
		CCriSecLock locallock(m_cs);

		if(m_nActive > 0)
			++m_nActive;
		else if(m_nActive == 0)
		{
			if(m_nWaitingWriters == 0)
				++m_nActive;
			else
			{
				++m_nWaitingReaders;
				bWait = TRUE;
			}
		}
		else
		{
			if(!IsOwner())
			{
				++m_nWaitingReaders;
				bWait = TRUE;
			}
		}
	}

	if(bWait)
	{
		m_smRead.Wait();
	}
}
Exemple #6
0
VOID CRWLock::WaitToWrite()
{
	BOOL bWait = FALSE;

	{
		CCriSecLock locallock(m_cs);

		if(m_nActive > 0)
		{
			++m_nWaitingWriters;
			bWait = TRUE;
		}
		else if(m_nActive == 0)
		{
			--m_nActive;
			SetOwner();
		}
		else
		{
			if(IsOwner())
				--m_nActive;
			else
			{
				++m_nWaitingWriters;
				bWait = TRUE;
			}
		}
	}

	if(bWait)
	{
		m_smWrite.Wait();
		SetOwner();
	}
}
Exemple #7
0
void StackAsArray::Purge ()
{
    if (IsOwner ())
    {
	for (unsigned int i = 0; i < count; ++i)
	    {
	    delete array [i];
	    #ifdef DPRINT
	    fprintf(stderr, " delete array[%d]@ count =%d\n", i, count);
	    #endif
	    }
	    
    }
   #ifdef DPRINT
    fprintf(stderr, " Stack.Purge() is called  & IsOwner()  == %d\n", IsOwner());
    #endif
    count = 0;
}
/**
 * Remove
 *
 * After calling Create this function can be used to remove the pid file
 * If the PIDFile is invalid and is not currently owner by the process
 * calling Remove will call abort.
 */
void PIDFile::Remove()
{
	if (IsOwner() == false)
		abort(); //Your not the owner

	if (unlink(m_filename.c_str()) < 0)
		abort(); //We should be the owner of this file

	m_IsOwner = false;
}
void StackAsArray::Purge ()
{
    if (IsOwner ())
    {
    	for (unsigned int i = 0; i < count; ++i)
    	{
    		delete array [i];
    	}
    }
    count = 0;
}
Exemple #10
0
VOID CMutexRWLock::WriteDone()
{
	ASSERT(IsOwner());
	ASSERT(m_nActive < 0);

	CSpinLock locallock(m_cs);

	if(++m_nActive == 0)
	{
		DetachOwner();
		m_mtx.unlock();
	}		
}
Exemple #11
0
void OpenScatterTable::Purge ()
{
    for (unsigned int i = 0; i < length; ++i)
    {
	if (array [i].state == Entry::occupied)
	{
	    if (IsOwner ())
		delete array [i].object;
	    array [i] = Entry ();
	}
    }
    count = 0;
}
Exemple #12
0
VOID CRWLock::ReadDone()
{
	CCriSecLock locallock(m_cs);

	ASSERT(m_nActive != 0);

	if(m_nActive > 0)
	{
		if(--m_nActive == 0)
			Done();
	}
	else
		ASSERT(IsOwner());
}
void BagAsLinkedList::Purge ()
{
    if (IsOwner ())
    {
        ListElement<Object*> const* ptr;

        for (ptr = list.Head (); ptr != 0; ptr = ptr->Next ())
        {
            delete ptr->Datum ();
        }
    }
    list.Purge ();
    count = 0;
}
Exemple #14
0
VOID CRWLock::WriteDone()
{
	CCriSecLock locallock(m_cs);

	ASSERT(m_nActive < 0);

	if(++m_nActive == 0)
	{
		DetachOwner();
		Done();
	}
	else
		ASSERT(IsOwner());
}
bool PessimisticTxnManager::PerformRead(const oid_t &tile_group_id,
                                        const oid_t &tuple_id) {
  LOG_TRACE("Perform read");
  auto &manager = catalog::Manager::GetInstance();
  auto tile_group = manager.GetTileGroup(tile_group_id);
  auto tile_group_header = tile_group->GetHeader();

  auto &rw_set = current_txn->GetRWSet();
  auto tuple_map = rw_set.find(tile_group_id);
  if (tuple_map != rw_set.end()) {
    if (tuple_map->second.find(tuple_id) != tuple_map->second.end()) {
      // It was already accessed, don't acquire read lock again
      return true;
    }
  }

  if (IsOwner(tile_group_header, tuple_id)) {
    return true;
  }

  // Try to acquire read lock.
  auto old_txn_id = tile_group_header->GetTransactionId(tuple_id);
  // No one is holding the write lock
  if (EXTRACT_TXNID(old_txn_id) == INITIAL_TXN_ID) {
    LOG_TRACE("No one holding the lock");
    while (true) {
      LOG_TRACE("Current read count is %lu", EXTRACT_READ_COUNT(old_txn_id));
      auto new_read_count = EXTRACT_READ_COUNT(old_txn_id) + 1;
      // Try add read count
      auto new_txn_id = PACK_TXNID(INITIAL_TXN_ID, new_read_count);
      LOG_TRACE("New txn id %lx", new_txn_id);
      txn_id_t real_txn_id = tile_group_header->SetAtomicTransactionId(
          tuple_id, old_txn_id, new_txn_id);
      if (real_txn_id != old_txn_id) {
        // See if there's writer
        if (EXTRACT_TXNID(real_txn_id) != INITIAL_TXN_ID) return false;
      } else {
        break;
      }
    }
  } else {
    // SetTransactionResult(RESULT_FAILURE);
    return false;
  }

  current_txn->RecordRead(tile_group_id, tuple_id);

  return true;
}
void COXRollup::ReleaseRecipient(const CWnd* pRCRequesting, BOOL bCallNotifyFunction)
	{
	// do this only when he is the current owner of the message dispatch system
	if (IsOwner(pRCRequesting)) 
		{
		TRACE1("[RU]Released the owner of the mds. Handle : %ld\n", m_hWndMR);
		
		// if he chose to do some cleanup, do it
		if (bCallNotifyFunction)
			OnRecipientRelease();
		
		m_hWndMR = NULL;
		}
	// else do nothing (somebody else has registered as current user
	}
Exemple #17
0
		void Delete()
		{
			if (IsOwner())
			{
				if (IsArray())
				{
					m_bits &= POINTER_MASK;
					delete [] m_ptr;
				}
				else
				{
					m_bits &= POINTER_MASK;
					delete m_ptr;
				}
			}

			m_ptr = 0;
		}
Exemple #18
0
VOID CSEMRWLock::ReadDone()
{
	ASSERT(m_nActive != 0);

	INT iFlag = 0;

	if(m_nActive > 0)
	{
		CSpinLock locallock(m_cs);

		if(--m_nActive == 0)
			iFlag = Done();
	}
	else
		ASSERT(IsOwner());

	Notify(iFlag);
}
Exemple #19
0
VOID CSEMRWLock::WriteDone()
{
	ASSERT(IsOwner());
	ASSERT(m_nActive < 0);

	INT iFlag = 0;

	{
		CSpinLock locallock(m_cs);

		if(++m_nActive == 0)
		{
			DetachOwner();
			iFlag = Done();
		}
	}

	Notify(iFlag);
}
Exemple #20
0
VOID CMutexRWLock::ReadDone()
{
	ASSERT(m_nActive != 0);

	if(m_nActive > 0)
	{
		ASSERT(m_nReadCount > 0);

		CSpinLock locallock(m_cs);

		if(--m_nActive == 0)
		{
			for(; m_nReadCount > 0; --m_nReadCount)
				m_mtx.unlock_shared();
		}
	}
	else
		ASSERT(IsOwner());
}
Exemple #21
0
Bool_t KVUniqueNameList::checkObjInList(TObject* obj)
{
   // Return kTRUE if 'obj' can be added to list.
   // If fReplace==kFALSE, there must be no object in the list with
   // same name as obj->GetName().
   // If fReplace==kTRUE the previous object is removed from the list.
   // If IsOwner()==kTRUE the previous object is removed AND deleted.
   // In the latter two cases the new object can always be added (returns kTRUE)
   
   TObject* old_obj = FindObject(obj->GetName());
   if(!old_obj) return kTRUE;
   else
   {
      if(fReplace){
	 Remove(old_obj);
	 if(IsOwner()) delete old_obj;
	 return kTRUE;
      }
   }
   return kFALSE;
}
Exemple #22
0
VOID CRWLock::WriteDone()
{
	CSEM* pSem	 = nullptr;
	LONG  lCount = 0;

	{
		CSpinLock locallock(m_cs);

		ASSERT(m_nActive < 0);

		if(++m_nActive == 0)
		{
			DetachOwner();
			Done(&pSem, lCount);
		}
		else
			ASSERT(IsOwner());
	}

	if(pSem != nullptr)
		pSem->Release(lCount);
}
Exemple #23
0
VOID CRWLock::ReadDone()
{
	CSEM* pSem	 = nullptr;
	LONG  lCount = 0;

	{
		CSpinLock locallock(m_cs);

		ASSERT(m_nActive != 0);

		if(m_nActive > 0)
		{
			if(--m_nActive == 0)
				Done(&pSem, lCount);
		}
		else
			ASSERT(IsOwner());
	}

	if(pSem != nullptr)
		pSem->Release(lCount);
}
Exemple #24
0
VOID CMutexRWLock::WaitToWrite()
{
	BOOL bWait = FALSE;

	{
		CSpinLock locallock(m_cs);

		if(m_nActive > 0)
			bWait = TRUE;
		else if(m_nActive == 0)
		{
			if(m_mtx.try_lock())
			{
				SetOwner();
				--m_nActive;
			}
			else
				bWait = TRUE;
		}
		else
		{
			if(IsOwner())
				--m_nActive;
			else
				bWait = TRUE;
		}
	}

	if(bWait)
	{
		m_mtx.lock();

		SetOwner();
		--m_nActive;
	}
}
// transaction.
// this function is called by update/delete executors.
bool EagerWriteTxnManager::IsOwnable(
    const storage::TileGroupHeader *const tile_group_header,
    const oid_t &tuple_id) {
  auto tuple_txn_id = tile_group_header->GetTransactionId(tuple_id);
  auto tuple_end_cid = tile_group_header->GetEndCommitId(tuple_id);
  LOG_INFO("IsOwnable txnid: %lx end_cid: %lx", tuple_txn_id, tuple_end_cid);
  return tuple_txn_id == INITIAL_TXN_ID && tuple_end_cid == MAX_CID;
}

bool EagerWriteTxnManager::AcquireOwnership(
    const storage::TileGroupHeader *const tile_group_header,
    const oid_t &tile_group_id __attribute__((unused)), const oid_t &tuple_id) {
  LOG_INFO("AcquireOwnership");
  assert(IsOwner(tile_group_header, tuple_id) == false);

  // Try to get write lock
  auto current_tid = current_txn->GetTransactionId();
  auto old_tid = INITIAL_TXN_ID;

  GetEwReaderLock(tile_group_header, tuple_id);

  old_tid =
      tile_group_header->SetAtomicTransactionId(tuple_id, old_tid, current_tid);

  // Check if we successfully get the write lock
  bool res = (old_tid == INITIAL_TXN_ID);
  if (!res) {
    LOG_INFO("Fail to acquire write lock. Set txn failure.");
    ReleaseEwReaderLock(tile_group_header, tuple_id);
Exemple #26
0
/**
 * Create
 *
 * Create a new PIDFile using the filename that was specified in the constructor.
 * The function will return true if it was capable of creating a pid file.
 * The function will fail if the pid file already exists and has an active owner
 * An active owner is checked by comaring the current process exe filename with
 * the process who's pid is in the existing pid file
 */
bool PIDFile::Create()
{
	int fd = open(m_filename.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
	FILE *file = NULL;
	int tpid = -1;
	int ret = 0;

	if (IsOwner())
		abort();	//Error with caller attempting to create pidfile twice
	
	if (fd < 0)
	{
		switch(errno)
		{
			case EEXIST: //Lets see if we can fix fd
				file = fopen(m_filename.c_str(), "r");
				if (!file)
					return false;
				
				ret = fscanf(file, "%d", &tpid);
				fclose(file);
				
				if (ret != 1) //Issue here is that we have an unparsable pid file. Should we remove it?
					return false;

				do {
					std::string self;
					std::string pidexe;
					
					if (GetOwnExePath(&self) == false)
						return false;
					
					if (GetPIDExePath(tpid, &pidexe) == true)
					{
						if (self == pidexe)
							return false; //The pid in the file matchs us and is a valid process
					}
					
					if (unlink(m_filename.c_str()) < 0) //Not "us" just overwrite it
							abort();
					
					fd = open(m_filename.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP);
					if (fd < 0)
						return false;
				
				} while(0);

				break;
			default:
				return false;
		}
	}

	FILE *fp = fdopen(fd, "w");
	if (!fp)
		abort();	//Should never happen
	fprintf(fp, "%d\n", getpid());
	fclose(fp);
	m_IsOwner = true;
	return true;
}
// transaction.
// this function is called by update/delete executors.
bool EagerWriteTxnManager::IsOwnable(
    const storage::TileGroupHeader *const tile_group_header,
    const oid_t &tuple_id) {
  auto tuple_txn_id = tile_group_header->GetTransactionId(tuple_id);
  auto tuple_end_cid = tile_group_header->GetEndCommitId(tuple_id);
  LOG_TRACE("IsOwnable txnid: %lx end_cid: %lx", tuple_txn_id, tuple_end_cid);
  return tuple_txn_id == INITIAL_TXN_ID && tuple_end_cid == MAX_CID;
}

bool EagerWriteTxnManager::AcquireOwnership(
    const storage::TileGroupHeader *const tile_group_header,
    const oid_t &tile_group_id UNUSED_ATTRIBUTE, const oid_t &tuple_id) {
  LOG_TRACE("AcquireOwnership");
  PL_ASSERT(IsOwner(tile_group_header, tuple_id) == false);

  // Try to get write lock
  auto current_tid = current_txn->GetTransactionId();
  auto old_tid = INITIAL_TXN_ID;

  GetEwReaderLock(tile_group_header, tuple_id);

  old_tid =
      tile_group_header->SetAtomicTransactionId(tuple_id, old_tid, current_tid);

  // Check if we successfully get the write lock
  bool res = (old_tid == INITIAL_TXN_ID);
  if (!res) {
    LOG_TRACE("Fail to acquire write lock. Set txn failure.");
    ReleaseEwReaderLock(tile_group_header, tuple_id);
Exemple #28
0
bool
Matrix<T>::Viewing() const
{ return !IsOwner( viewType_ ); }
Exemple #29
0
bool
Matrix<T>::Owner() const
{ return IsOwner( viewType_ ); }
bool TimestampOrderingTransactionManager::PerformRead(
    TransactionContext *const current_txn, const ItemPointer &read_location,
    bool acquire_ownership) {
  ItemPointer location = read_location;

  //////////////////////////////////////////////////////////
  //// handle READ_ONLY
  //////////////////////////////////////////////////////////
  if (current_txn->GetIsolationLevel() == IsolationLevelType::READ_ONLY) {
    // do not update read set for read-only transactions.
    return true;
  }  // end READ ONLY

  //////////////////////////////////////////////////////////
  //// handle SNAPSHOT
  //////////////////////////////////////////////////////////

  // TODO: what if we want to read a version that we write?
  else if (current_txn->GetIsolationLevel() == IsolationLevelType::SNAPSHOT) {
    oid_t tile_group_id = location.block;
    oid_t tuple_id = location.offset;

    LOG_TRACE("PerformRead (%u, %u)\n", location.block, location.offset);
    auto &manager = catalog::Manager::GetInstance();
    auto tile_group_header = manager.GetTileGroup(tile_group_id)->GetHeader();

    // Check if it's select for update before we check the ownership
    // and modify the last reader cid
    if (acquire_ownership == true) {
      // get the latest version of this tuple.
      location = *(tile_group_header->GetIndirection(location.offset));

      tile_group_id = location.block;
      tuple_id = location.offset;

      tile_group_header = manager.GetTileGroup(tile_group_id)->GetHeader();

      if (IsOwner(current_txn, tile_group_header, tuple_id) == false) {
        // Acquire ownership if we haven't
        if (IsOwnable(current_txn, tile_group_header, tuple_id) == false) {
          // Cannot own
          return false;
        }
        if (AcquireOwnership(current_txn, tile_group_header, tuple_id) ==
            false) {
          // Cannot acquire ownership
          return false;
        }

        // Record RWType::READ_OWN
        current_txn->RecordReadOwn(location);
      }

      // if we have already owned the version.
      PL_ASSERT(IsOwner(current_txn, tile_group_header, tuple_id) == true);

      // Increment table read op stats
      if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode)) !=
          StatsType::INVALID) {
        stats::BackendStatsContext::GetInstance()->IncrementTableReads(
            location.block);
      }

      return true;

    } else {
      // if it's not select for update, then update read set and return true.

      current_txn->RecordRead(location);

      // Increment table read op stats
      if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode)) !=
          StatsType::INVALID) {
        stats::BackendStatsContext::GetInstance()->IncrementTableReads(
            location.block);
      }
      return true;
    }

  }  // end SNAPSHOT

  //////////////////////////////////////////////////////////
  //// handle READ_COMMITTED
  //////////////////////////////////////////////////////////
  else if (current_txn->GetIsolationLevel() ==
           IsolationLevelType::READ_COMMITTED) {
    oid_t tile_group_id = location.block;
    oid_t tuple_id = location.offset;

    LOG_TRACE("PerformRead (%u, %u)\n", location.block, location.offset);
    auto &manager = catalog::Manager::GetInstance();
    auto tile_group_header = manager.GetTileGroup(tile_group_id)->GetHeader();

    // Check if it's select for update before we check the ownership.
    if (acquire_ownership == true) {
      // acquire ownership.
      if (IsOwner(current_txn, tile_group_header, tuple_id) == false) {
        // Acquire ownership if we haven't
        if (IsOwnable(current_txn, tile_group_header, tuple_id) == false) {
          // Cannot own
          return false;
        }
        if (AcquireOwnership(current_txn, tile_group_header, tuple_id) ==
            false) {
          // Cannot acquire ownership
          return false;
        }

        // Record RWType::READ_OWN
        current_txn->RecordReadOwn(location);
      }
      // if we have already owned the version.
      PL_ASSERT(IsOwner(current_txn, tile_group_header, tuple_id) == true);
      // Increment table read op stats
      if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode)) !=
          StatsType::INVALID) {
        stats::BackendStatsContext::GetInstance()->IncrementTableReads(
            location.block);
      }
      return true;

    } else {
      // a transaction can never read an uncommitted version.
      if (IsOwner(current_txn, tile_group_header, tuple_id) == false) {
        if (IsOwned(current_txn, tile_group_header, tuple_id) == false) {
          current_txn->RecordRead(location);

          // Increment table read op stats
          if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode))
              != StatsType::INVALID) {
            stats::BackendStatsContext::GetInstance()->IncrementTableReads(
                location.block);
          }
          return true;

        } else {
          // if the tuple has been owned by some concurrent transactions,
          // then read fails.
          LOG_TRACE("Transaction read failed");
          return false;
        }

      } else {
        // this version must already be in the read/write set.
        // so no need to update read set.
        // current_txn->RecordRead(location);

        // Increment table read op stats
        if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode))
            != StatsType::INVALID) {
          stats::BackendStatsContext::GetInstance()->IncrementTableReads(
              location.block);
        }
        return true;
      }
    }

  }  // end READ_COMMITTED

  //////////////////////////////////////////////////////////
  //// handle SERIALIZABLE and REPEATABLE_READS
  //////////////////////////////////////////////////////////
  else {
    PL_ASSERT(current_txn->GetIsolationLevel() ==
                  IsolationLevelType::SERIALIZABLE ||
              current_txn->GetIsolationLevel() ==
                  IsolationLevelType::REPEATABLE_READS);

    oid_t tile_group_id = location.block;
    oid_t tuple_id = location.offset;

    LOG_TRACE("PerformRead (%u, %u)\n", location.block, location.offset);
    auto &manager = catalog::Manager::GetInstance();
    auto tile_group_header = manager.GetTileGroup(tile_group_id)->GetHeader();

    // Check if it's select for update before we check the ownership
    // and modify the last reader cid.
    if (acquire_ownership == true) {
      // acquire ownership.
      if (IsOwner(current_txn, tile_group_header, tuple_id) == false) {
        // Acquire ownership if we haven't
        if (IsOwnable(current_txn, tile_group_header, tuple_id) == false) {
          // Cannot own
          return false;
        }
        if (AcquireOwnership(current_txn, tile_group_header, tuple_id) ==
            false) {
          // Cannot acquire ownership
          return false;
        }

        // Record RWType::READ_OWN
        current_txn->RecordReadOwn(location);

        // now we have already obtained the ownership.
        // then attempt to set last reader cid.
        UNUSED_ATTRIBUTE bool ret = SetLastReaderCommitId(
            tile_group_header, tuple_id, current_txn->GetCommitId(), true);

        PL_ASSERT(ret == true);
        // there's no need to maintain read set for timestamp ordering protocol.
        // T/O does not check the read set during commit phase.
      }

      // if we have already owned the version.
      PL_ASSERT(IsOwner(current_txn, tile_group_header, tuple_id) == true);
      PL_ASSERT(GetLastReaderCommitId(tile_group_header, tuple_id) ==
                    current_txn->GetCommitId() ||
                GetLastReaderCommitId(tile_group_header, tuple_id) == 0);
      // Increment table read op stats
      if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode)) !=
          StatsType::INVALID) {
        stats::BackendStatsContext::GetInstance()->IncrementTableReads(
            location.block);
      }
      return true;

    } else {
      if (IsOwner(current_txn, tile_group_header, tuple_id) == false) {
        // if the current transaction does not own this tuple,
        // then attempt to set last reader cid.
        if (SetLastReaderCommitId(tile_group_header, tuple_id,
                                  current_txn->GetCommitId(), false) == true) {
          // update read set.
          current_txn->RecordRead(location);

          // Increment table read op stats
          if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode))
              != StatsType::INVALID) {
            stats::BackendStatsContext::GetInstance()->IncrementTableReads(
                location.block);
          }
          return true;
        } else {
          // if the tuple has been owned by some concurrent transactions,
          // then read fails.
          LOG_TRACE("Transaction read failed");
          return false;
        }

      } else {
        // if the current transaction has already owned this tuple,
        // then perform read directly.
        PL_ASSERT(GetLastReaderCommitId(tile_group_header, tuple_id) ==
                      current_txn->GetCommitId() ||
                  GetLastReaderCommitId(tile_group_header, tuple_id) == 0);

        // this version must already be in the read/write set.
        // so no need to update read set.
        // current_txn->RecordRead(location);

        // Increment table read op stats
        if (static_cast<StatsType>(settings::SettingsManager::GetInt(settings::SettingId::stats_mode))
            != StatsType::INVALID) {
          stats::BackendStatsContext::GetInstance()->IncrementTableReads(
              location.block);
        }
        return true;
      }
    }

  }  // end SERIALIZABLE || REPEATABLE_READS
}