Skip to content

File lockfree_transaction_descriptor.cpp

File List > base > lockfree_transaction_descriptor.cpp

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

#include "lockfree_transaction_descriptor.hpp"

#include "lockfree_transaction_reclaimable.hpp"
#include "lockfree_transaction_table.hpp"

#include <cassert>
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

namespace lockfree
{
  namespace tran
  {
    descriptor::descriptor ()
      : m_table (NULL)
      , m_tranid (INVALID_TRANID)
      , m_last_reclaim_minid (0)
      , m_retired_head (NULL)
      , m_retired_tail (NULL)
      , m_did_incr (false)
      , m_saved_node (NULL)
      , m_retire_count (0)
      , m_reclaim_count (0)
    {
    }

    descriptor::~descriptor ()
    {
      assert (!is_tran_started ());
      while (m_retired_head != NULL)
    {
      reclaim_retired_head ();
    }
      if (m_saved_node != NULL)
    {
      m_saved_node->reclaim ();
    }
    }

    void
    descriptor::set_table (table &tbl)
    {
      m_table = &tbl;
    }

    void
    descriptor::retire_node (reclaimable_node &node)
    {
      bool should_end = !is_tran_started ();
      start_tran_and_increment_id ();

      reclaim_retired_list ();

      node.m_retire_tranid = m_tranid;
      node.m_retired_next = NULL;
      // add to tail to keep delete ids ordered
      if (m_retired_tail == NULL)
    {
      assert (m_retired_head == NULL);
      m_retired_head = m_retired_tail = &node;
    }
      else
    {
      m_retired_tail->m_retired_next = &node;
      m_retired_tail = &node;
    }
      ++m_retire_count;

      if (should_end)
    {
      end_tran ();
    }
    }

    void
    descriptor::start_tran ()
    {
      if (!is_tran_started ())
    {
      m_tranid = m_table->get_current_global_tranid ();
    }
    }

    void
    descriptor::start_tran_and_increment_id ()
    {
      if (!m_did_incr)
    {
      m_tranid = m_table->get_new_global_tranid ();
    }
      assert (m_tranid != INVALID_TRANID);
    }

    bool
    descriptor::is_tran_started () const
    {
      return m_tranid != INVALID_TRANID;
    }

    void
    descriptor::end_tran ()
    {
      assert (is_tran_started ());
      m_tranid = INVALID_TRANID;
      m_did_incr = false;
    }

    id
    descriptor::get_transaction_id () const
    {
      return m_tranid;
    }

    void
    descriptor::reclaim_retired_list ()
    {
      id min_tran_id = m_table->get_min_active_tranid ();
      if (min_tran_id <= m_last_reclaim_minid)
    {
      // nothing changed
      return;
    }
      while (m_retired_head != NULL && m_retired_head->m_retire_tranid < min_tran_id)
    {
      reclaim_retired_head ();
    }
      if (m_retired_head == NULL)
    {
      m_retired_tail = NULL;
    }

      m_last_reclaim_minid = min_tran_id;
    }

    void
    descriptor::reclaim_retired_head ()
    {
      assert (m_retired_head != NULL);
      reclaimable_node *nodep = m_retired_head;
      m_retired_head = m_retired_head->m_retired_next;
      if (m_retired_head == NULL)
    {
      m_retired_tail = NULL;
    }

      nodep->m_retired_next = NULL;
      nodep->reclaim ();
      ++m_reclaim_count;
    }

    void
    descriptor::save_reclaimable (reclaimable_node *&node)
    {
      assert (m_saved_node == NULL);
      m_saved_node = node;
      node = NULL;
    }

    reclaimable_node *
    descriptor::pull_saved_reclaimable ()
    {
      reclaimable_node *ret = m_saved_node;
      m_saved_node = NULL;
      return ret;
    }

    size_t
    descriptor::get_total_retire_count () const
    {
      return m_retire_count;
    }

    size_t
    descriptor::get_total_reclaim_count () const
    {
      return m_reclaim_count;
    }

    size_t
    descriptor::get_current_retire_count () const
    {
      return m_retire_count - m_reclaim_count;
    }
  } // namespace tran
} // namespace lockfree