Skip to content

File mvcc.h

File List > cubrid > src > transaction > mvcc.h

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.
 *
 */

/*
 * mvcc.h - Multi-Version Concurrency Control system (at Server).
 *
 */
#ifndef _MVCC_H_
#define _MVCC_H_

#ident "$Id$"

#include "log_lsa.hpp"
#include "mvcc_active_tran.hpp"
#include "recovery.h"
#include "storage_common.h"
#include "thread_compat.hpp"

#include <vector>

/* MVCC RECORD HEADER */
typedef struct mvcc_rec_header MVCC_REC_HEADER;
struct mvcc_rec_header
{
  INT32 mvcc_flag:8;        /* MVCC flags */
  INT32 repid:24;       /* representation id */
  int chn;          /* cache coherency number */
  MVCCID mvcc_ins_id;       /* MVCC insert id */
  MVCCID mvcc_del_id;       /* MVCC delete id */
  LOG_LSA prev_version_lsa; /* log address of previous version */
};
#define MVCC_REC_HEADER_INITIALIZER \
{ 0, 0, NULL_CHN, MVCCID_NULL, MVCCID_NULL, LSA_INITIALIZER }

/* MVCC Header Macros */
#define MVCC_GET_INSID(header) \
  ((header)->mvcc_ins_id)

#define MVCC_SET_INSID(header, mvcc_id) \
  ((header)->mvcc_ins_id = (mvcc_id))

#define MVCC_GET_DELID(header) \
  ((header)->mvcc_del_id)

#define MVCC_SET_DELID(header, mvcc_id) \
  ((header)->mvcc_del_id = (mvcc_id))

#define MVCC_GET_REPID(header) \
  ((header)->repid)

#define MVCC_SET_REPID(header, rep_id) \
  ((header)->repid = (rep_id))

#define MVCC_GET_CHN(header) \
  ((header)->chn)

#define MVCC_SET_CHN(header, chn_) \
  ((header)->chn = (chn_))

#define MVCC_GET_FLAG(header) \
  ((header)->mvcc_flag)

#define MVCC_SET_FLAG(header, flag) \
  ((header)->mvcc_flag = (flag))

#define MVCC_IS_ANY_FLAG_SET(rec_header_p) \
  (MVCC_IS_FLAG_SET (rec_header_p, OR_MVCC_FLAG_MASK))

#define MVCC_IS_FLAG_SET(rec_header_p, flags) \
  ((rec_header_p)->mvcc_flag & (flags))

#define MVCC_IS_HEADER_DELID_VALID(rec_header_p) \
  (MVCC_IS_FLAG_SET (rec_header_p, OR_MVCC_FLAG_VALID_DELID) \
   && MVCCID_IS_VALID (MVCC_GET_DELID (rec_header_p)))

#define MVCC_IS_HEADER_INSID_NOT_ALL_VISIBLE(rec_header_p) \
  (MVCC_IS_FLAG_SET (rec_header_p, OR_MVCC_FLAG_VALID_INSID) \
   && MVCC_GET_INSID (rec_header_p) != MVCCID_ALL_VISIBLE)

#define MVCC_IS_HEADER_ALL_VISIBLE(rec_header_p) \
  (!MVCC_IS_FLAG_SET (rec_header_p, OR_MVCC_FLAG_VALID_INSID|OR_MVCC_FLAG_VALID_DELID) \
   && MVCC_GET_INSID (rec_header_p) == MVCCID_ALL_VISIBLE)

#define MVCC_SET_FLAG_BITS(rec_header_p, flag) \
  ((rec_header_p)->mvcc_flag |= (flag))

#define MVCC_CLEAR_ALL_FLAG_BITS(rec_header_p) \
  (MVCC_CLEAR_FLAG_BITS (rec_header_p, OR_MVCC_FLAG_MASK))

#define MVCC_CLEAR_FLAG_BITS(rec_header_p, flag) \
  ((rec_header_p)->mvcc_flag &= ~(flag))

/* MVCC Snapshot Macros */
#define MVCC_SNAPSHOT_GET_LOWEST_ACTIVE_ID(snapshot) \
  ((snapshot)->lowest_active_mvccid)

#define MVCC_SNAPSHOT_GET_HIGHEST_COMMITTED_ID(snapshot) \
  ((snapshot)->highest_completed_mvccid)

/* MVCC Record Macros */

/* Check if record is inserted by current transaction or its children */
#define MVCC_IS_REC_INSERTED_BY_ME(thread_p, rec_header_p)  \
  (logtb_is_current_mvccid (thread_p, (rec_header_p)->mvcc_ins_id))

/* Check if record is deleted by current transaction or its children */
#define MVCC_IS_REC_DELETED_BY_ME(thread_p, rec_header_p)   \
  (logtb_is_current_mvccid (thread_p, (rec_header_p)->mvcc_del_id))

/* Check if record was inserted by the transaction identified by mvcc_id */
#define MVCC_IS_REC_INSERTED_BY(rec_header_p, mvcc_id) \
  ((rec_header_p)->mvcc_ins_id == mvcc_id)

/* Check if record was deleted by the transaction identified by mvcc_id */
#define MVCC_IS_REC_DELETED_BY(rec_header_p, mvcc_id) \
  ((rec_header_p)->delid_chn.mvcc_del_id == mvcc_id)

/* Check if given CHN is up-to-date according to MVCC header:
 * 1. Given CHN must be non-NULL.
 * 2. header CHN matches given CHN.
 */
#define MVCC_IS_CHN_UPTODATE(rec_header_p, chn) \
  (chn != NULL_CHN \
   && (chn == MVCC_GET_CHN (rec_header_p)))

#define MVCC_ID_PRECEDES(id1, id2) ((id1) < (id2))
#define MVCC_ID_FOLLOW_OR_EQUAL(id1, id2) ((id1) >= (id2))

#define MVCC_IS_HEADER_PREV_VERSION_VALID(rec_header_p) \
  (MVCC_IS_FLAG_SET (rec_header_p, OR_MVCC_FLAG_VALID_PREV_VERSION) \
  && !LSA_ISNULL (&MVCC_GET_PREV_VERSION_LSA (rec_header_p)))

#define MVCC_SET_PREVIOUS_VERSION_LSA(header, new_lsa) \
  do \
    { \
      (header)->prev_version_lsa.pageid = (new_lsa)->pageid; \
      (header)->prev_version_lsa.offset = (new_lsa)->offset; \
    } \
  while (0)

#define MVCC_GET_PREV_VERSION_LSA(header) \
  ((header)->prev_version_lsa)

enum mvcc_satisfies_snapshot_result
{
  TOO_OLD_FOR_SNAPSHOT,     /* not visible, deleted by me or deleted by inactive transaction */
  SNAPSHOT_SATISFIED,       /* is visible and valid */
  TOO_NEW_FOR_SNAPSHOT      /* not visible, inserter is still active.
                 * when looking for visible version, if this is the snapshot result, we have to
                 * check previous versions in log (if there are previous versions).
                 */
};              /* Possible results by check versions against snapshots. */
typedef enum mvcc_satisfies_snapshot_result MVCC_SATISFIES_SNAPSHOT_RESULT;
typedef struct mvcc_snapshot MVCC_SNAPSHOT;

typedef MVCC_SATISFIES_SNAPSHOT_RESULT (*MVCC_SNAPSHOT_FUNC) (THREAD_ENTRY * thread_p, MVCC_REC_HEADER * rec_header,
                                  MVCC_SNAPSHOT * snapshot);
struct mvcc_snapshot
{
  MVCCID lowest_active_mvccid;  /* lowest active id */
  MVCCID highest_completed_mvccid;  /* highest mvccid in snapshot */

  mvcc_active_tran m_active_mvccs;

  MVCC_SNAPSHOT_FUNC snapshot_fnc;  /* the snapshot function */

  bool valid;           /* true, if the snapshot is valid */

  // *INDENT-OFF*
  mvcc_snapshot ();
  void reset ();

  mvcc_snapshot &operator= (const mvcc_snapshot& snapshot) = delete;

  void copy_to (mvcc_snapshot & dest) const;
  // *INDENT-ON*
};

/* MVCC INFO - such structure is attached to each active transaction */
typedef struct mvcc_info MVCC_INFO;
struct mvcc_info
{
  MVCC_SNAPSHOT snapshot;   /* MVCC Snapshot */

  /* MVCC ID - increase with each transaction that modified data */
  MVCCID id;

  /* recent_snapshot_lowest_active_mvccid - the lowest active MVCCID computed for the most recent snapshot of current
   * transaction. This field help to know faster whether an MVCCID is active or not. Thus, mvccid older than this field
   * are not active anymore */
  MVCCID recent_snapshot_lowest_active_mvccid;

  // *INDENT-OFF*
  std::vector<MVCCID> sub_ids;      /* MVCC sub-transaction ID array */
  // *INDENT-ON*
  bool is_sub_active;       /* true in case that sub-transaction is running */

  // *INDENT-OFF*
  mvcc_info ();
  void init ();
  void reset ();

  void copy_to (mvcc_info & dest) const;
  // *INDENT-ON*   
};

enum mvcc_satisfies_delete_result
{
  DELETE_RECORD_INSERT_IN_PROGRESS, /* invisible - created after scan started */
  DELETE_RECORD_CAN_DELETE, /* is visible and valid - can be deleted */
  DELETE_RECORD_DELETED,    /* deleted by committed transaction */
  DELETE_RECORD_DELETE_IN_PROGRESS, /* deleted by other in progress transaction */
  DELETE_RECORD_SELF_DELETED    /* deleted by the current transaction */
};              /* Heap record satisfies delete result */
typedef enum mvcc_satisfies_delete_result MVCC_SATISFIES_DELETE_RESULT;

enum mvcc_satisfies_vacuum_result
{
  VACUUM_RECORD_REMOVE,     /* record can be removed completely */
  VACUUM_RECORD_DELETE_INSID_PREV_VER,  /* record insert MVCCID and prev version lsa can be removed */
  VACUUM_RECORD_CANNOT_VACUUM   /* record cannot be vacuumed because: 1. it was already vacuumed. 2. it was recently
                 * inserted. 3. it was recently deleted and has no insert MVCCID. */
};              /* Heap record satisfies vacuum result */
typedef enum mvcc_satisfies_vacuum_result MVCC_SATISFIES_VACUUM_RESULT;

/* Definitions used to identify MVCC log records. */
// TODO - replace with functions

/* Is log record for a heap MVCC operation */
#define LOG_IS_MVCC_HEAP_OPERATION(rcvindex) \
  (((rcvindex) == RVHF_MVCC_DELETE_REC_HOME) \
   || ((rcvindex) == RVHF_MVCC_INSERT) \
   || ((rcvindex) == RVHF_UPDATE_NOTIFY_VACUUM) \
   || ((rcvindex) == RVHF_MVCC_DELETE_MODIFY_HOME) \
   || ((rcvindex) == RVHF_MVCC_NO_MODIFY_HOME) \
   || ((rcvindex) == RVHF_MVCC_REDISTRIBUTE))

/* Is log record for a b-tree MVCC operation */
#define LOG_IS_MVCC_BTREE_OPERATION(rcvindex) \
  ((rcvindex) == RVBT_MVCC_DELETE_OBJECT \
   || (rcvindex) == RVBT_MVCC_INSERT_OBJECT \
   || (rcvindex) == RVBT_MVCC_INSERT_OBJECT_UNQ \
   || (rcvindex) == RVBT_MVCC_NOTIFY_VACUUM)

/* Is log record for a MVCC operation */
#define LOG_IS_MVCC_OPERATION(rcvindex) \
  (LOG_IS_MVCC_HEAP_OPERATION (rcvindex) \
   || LOG_IS_MVCC_BTREE_OPERATION (rcvindex) \
   || ((rcvindex) == RVES_NOTIFY_VACUUM))

extern MVCC_SATISFIES_SNAPSHOT_RESULT mvcc_satisfies_snapshot (THREAD_ENTRY * thread_p, MVCC_REC_HEADER * rec_header,
                                   MVCC_SNAPSHOT * snapshot);
extern MVCC_SATISFIES_SNAPSHOT_RESULT mvcc_is_not_deleted_for_snapshot (THREAD_ENTRY * thread_p,
                                    MVCC_REC_HEADER * rec_header,
                                    MVCC_SNAPSHOT * snapshot);
extern MVCC_SATISFIES_VACUUM_RESULT mvcc_satisfies_vacuum (THREAD_ENTRY * thread_p, MVCC_REC_HEADER * rec_header,
                               MVCCID oldest_mvccid);
extern MVCC_SATISFIES_DELETE_RESULT mvcc_satisfies_delete (THREAD_ENTRY * thread_p, MVCC_REC_HEADER * rec_header);

extern MVCC_SATISFIES_SNAPSHOT_RESULT mvcc_satisfies_dirty (THREAD_ENTRY * thread_p, MVCC_REC_HEADER * rec_header,
                                MVCC_SNAPSHOT * snapshot);
extern bool mvcc_is_mvcc_disabled_class (const OID * class_oid);

#endif /* _MVCC_H_ */