📄 rem0rec.ic
字号:
/************************************************************************Record manager(c) 1994-1996 Innobase OyCreated 5/30/1994 Heikki Tuuri*************************************************************************/#include "mach0data.h"#include "ut0byte.h"#include "dict0dict.h"/* Compact flag ORed to the extra size returned by rec_get_offsets() */#define REC_OFFS_COMPACT ((ulint) 1 << 31)/* SQL NULL flag in offsets returned by rec_get_offsets() */#define REC_OFFS_SQL_NULL ((ulint) 1 << 31)/* External flag in offsets returned by rec_get_offsets() */#define REC_OFFS_EXTERNAL ((ulint) 1 << 30)/* Mask for offsets returned by rec_get_offsets() */#define REC_OFFS_MASK (REC_OFFS_EXTERNAL - 1)/* Offsets of the bit-fields in an old-style record. NOTE! In the table themost significant bytes and bits are written below less significant. (1) byte offset (2) bit usage within byte downward from origin -> 1 8 bits pointer to next record 2 8 bits pointer to next record 3 1 bit short flag 7 bits number of fields 4 3 bits number of fields 5 bits heap number 5 8 bits heap number 6 4 bits n_owned 4 bits info bits*//* Offsets of the bit-fields in a new-style record. NOTE! In the table themost significant bytes and bits are written below less significant. (1) byte offset (2) bit usage within byte downward from origin -> 1 8 bits relative offset of next record 2 8 bits relative offset of next record the relative offset is an unsigned 16-bit integer: (offset_of_next_record - offset_of_this_record) mod 64Ki, where mod is the modulo as a non-negative number; we can calculate the the offset of the next record with the formula: relative_offset + offset_of_this_record mod UNIV_PAGE_SIZE 3 3 bits status: 000=conventional record 001=node pointer record (inside B-tree) 010=infimum record 011=supremum record 1xx=reserved 5 bits heap number 4 8 bits heap number 5 4 bits n_owned 4 bits info bits*//* We list the byte offsets from the origin of the record, the mask,and the shift needed to obtain each bit-field of the record. */#define REC_NEXT 2#define REC_NEXT_MASK 0xFFFFUL#define REC_NEXT_SHIFT 0#define REC_OLD_SHORT 3 /* This is single byte bit-field */#define REC_OLD_SHORT_MASK 0x1UL#define REC_OLD_SHORT_SHIFT 0#define REC_OLD_N_FIELDS 4#define REC_OLD_N_FIELDS_MASK 0x7FEUL#define REC_OLD_N_FIELDS_SHIFT 1#define REC_NEW_STATUS 3 /* This is single byte bit-field */#define REC_NEW_STATUS_MASK 0x7UL#define REC_NEW_STATUS_SHIFT 0#define REC_OLD_HEAP_NO 5#define REC_NEW_HEAP_NO 4#define REC_HEAP_NO_MASK 0xFFF8UL#define REC_HEAP_NO_SHIFT 3#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */#define REC_N_OWNED_MASK 0xFUL#define REC_N_OWNED_SHIFT 0#define REC_OLD_INFO_BITS 6 /* This is single byte bit-field */#define REC_NEW_INFO_BITS 5 /* This is single byte bit-field */#define REC_INFO_BITS_MASK 0xF0UL#define REC_INFO_BITS_SHIFT 0/* The deleted flag in info bits */#define REC_INFO_DELETED_FLAG 0x20UL /* when bit is set to 1, it means the record has been delete marked *//* The following masks are used to filter the SQL null bit fromone-byte and two-byte offsets */#define REC_1BYTE_SQL_NULL_MASK 0x80UL#define REC_2BYTE_SQL_NULL_MASK 0x8000UL/* In a 2-byte offset the second most significant bit denotesa field stored to another page: */#define REC_2BYTE_EXTERN_MASK 0x4000UL#if REC_OLD_SHORT_MASK << (8 * (REC_OLD_SHORT - 3)) \ ^ REC_OLD_N_FIELDS_MASK << (8 * (REC_OLD_N_FIELDS - 4)) \ ^ REC_HEAP_NO_MASK << (8 * (REC_OLD_HEAP_NO - 4)) \ ^ REC_N_OWNED_MASK << (8 * (REC_OLD_N_OWNED - 3)) \ ^ REC_INFO_BITS_MASK << (8 * (REC_OLD_INFO_BITS - 3)) \ ^ 0xFFFFFFFFUL# error "sum of old-style masks != 0xFFFFFFFFUL"#endif#if REC_NEW_STATUS_MASK << (8 * (REC_NEW_STATUS - 3)) \ ^ REC_HEAP_NO_MASK << (8 * (REC_NEW_HEAP_NO - 4)) \ ^ REC_N_OWNED_MASK << (8 * (REC_NEW_N_OWNED - 3)) \ ^ REC_INFO_BITS_MASK << (8 * (REC_NEW_INFO_BITS - 3)) \ ^ 0xFFFFFFUL# error "sum of new-style masks != 0xFFFFFFUL"#endif/***************************************************************Sets the value of the ith field SQL null bit of an old-style record. */voidrec_set_nth_field_null_bit(/*=======================*/ rec_t* rec, /* in: record */ ulint i, /* in: ith field */ ibool val); /* in: value to set *//*************************************************************** Sets an old-style record field to SQL null.The physical size of the field is not changed. */voidrec_set_nth_field_sql_null(/*=======================*/ rec_t* rec, /* in: record */ ulint n); /* in: index of the field *//***************************************************************Sets the value of the ith field extern storage bit of an old-style record. */voidrec_set_nth_field_extern_bit_old(/*=============================*/ rec_t* rec, /* in: old-style record */ ulint i, /* in: ith field */ ibool val, /* in: value to set */ mtr_t* mtr); /* in: mtr holding an X-latch to the page where rec is, or NULL; in the NULL case we do not write to log about the change *//***************************************************************Sets the value of the ith field extern storage bit of a new-style record. */voidrec_set_nth_field_extern_bit_new(/*=============================*/ rec_t* rec, /* in: record */ dict_index_t* index, /* in: record descriptor */ ulint ith, /* in: ith field */ ibool val, /* in: value to set */ mtr_t* mtr); /* in: mtr holding an X-latch to the page where rec is, or NULL; in the NULL case we do not write to log about the change *//**********************************************************Gets a bit field from within 1 byte. */UNIV_INLINEulintrec_get_bit_field_1(/*================*/ rec_t* rec, /* in: pointer to record origin */ ulint offs, /* in: offset from the origin down */ ulint mask, /* in: mask used to filter bits */ ulint shift) /* in: shift right applied after masking */{ ut_ad(rec); return((mach_read_from_1(rec - offs) & mask) >> shift);}/**********************************************************Sets a bit field within 1 byte. */UNIV_INLINEvoidrec_set_bit_field_1(/*================*/ rec_t* rec, /* in: pointer to record origin */ ulint val, /* in: value to set */ ulint offs, /* in: offset from the origin down */ ulint mask, /* in: mask used to filter bits */ ulint shift) /* in: shift right applied after masking */{ ut_ad(rec); ut_ad(offs <= REC_N_OLD_EXTRA_BYTES); ut_ad(mask); ut_ad(mask <= 0xFFUL); ut_ad(((mask >> shift) << shift) == mask); ut_ad(((val << shift) & mask) == (val << shift)); mach_write_to_1(rec - offs, (mach_read_from_1(rec - offs) & ~mask) | (val << shift));}/**********************************************************Gets a bit field from within 2 bytes. */UNIV_INLINEulintrec_get_bit_field_2(/*================*/ rec_t* rec, /* in: pointer to record origin */ ulint offs, /* in: offset from the origin down */ ulint mask, /* in: mask used to filter bits */ ulint shift) /* in: shift right applied after masking */{ ut_ad(rec); return((mach_read_from_2(rec - offs) & mask) >> shift);}/**********************************************************Sets a bit field within 2 bytes. */UNIV_INLINEvoidrec_set_bit_field_2(/*================*/ rec_t* rec, /* in: pointer to record origin */ ulint val, /* in: value to set */ ulint offs, /* in: offset from the origin down */ ulint mask, /* in: mask used to filter bits */ ulint shift) /* in: shift right applied after masking */{ ut_ad(rec); ut_ad(offs <= REC_N_OLD_EXTRA_BYTES); ut_ad(mask > 0xFFUL); ut_ad(mask <= 0xFFFFUL); ut_ad((mask >> shift) & 1); ut_ad(0 == ((mask >> shift) & ((mask >> shift) + 1))); ut_ad(((mask >> shift) << shift) == mask); ut_ad(((val << shift) & mask) == (val << shift)); mach_write_to_2(rec - offs, (mach_read_from_2(rec - offs) & ~mask) | (val << shift));}/**********************************************************The following function is used to get the offset of the next chained recordon the same page. */UNIV_INLINEulint rec_get_next_offs(/*==============*/ /* out: the page offset of the next chained record, or 0 if none */ rec_t* rec, /* in: physical record */ ulint comp) /* in: nonzero=compact page format */{ ulint field_value; ut_ad(REC_NEXT_MASK == 0xFFFFUL); ut_ad(REC_NEXT_SHIFT == 0); field_value = mach_read_from_2(rec - REC_NEXT); if (comp) {#if UNIV_PAGE_SIZE <= 32768 /* Note that for 64 KiB pages, field_value can 'wrap around' and the debug assertion is not valid */ /* In the following assertion, field_value is interpreted as signed 16-bit integer in 2's complement arithmetics. If all platforms defined int16_t in the standard headers, the expression could be written simpler as (int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE */ ut_ad((field_value >= 32768 ? field_value - 65536 : field_value) + ut_align_offset(rec, UNIV_PAGE_SIZE) < UNIV_PAGE_SIZE);#endif if (field_value == 0) { return(0); } return(ut_align_offset(rec + field_value, UNIV_PAGE_SIZE)); } else { ut_ad(field_value < UNIV_PAGE_SIZE); return(field_value); }}/**********************************************************The following function is used to set the next record offset field of therecord. */UNIV_INLINEvoidrec_set_next_offs(/*==============*/ rec_t* rec, /* in: physical record */ ulint comp, /* in: nonzero=compact page format */ ulint next) /* in: offset of the next record, or 0 if none */{ ut_ad(rec); ut_ad(UNIV_PAGE_SIZE > next); ut_ad(REC_NEXT_MASK == 0xFFFFUL); ut_ad(REC_NEXT_SHIFT == 0); if (comp) { ulint field_value; if (next) { /* The following two statements calculate next - offset_of_rec mod 64Ki, where mod is the modulo as a non-negative number */ field_value = (ulint)((lint)next - (lint)ut_align_offset(rec, UNIV_PAGE_SIZE)); field_value &= REC_NEXT_MASK; } else { field_value = 0; } mach_write_to_2(rec - REC_NEXT, field_value); } else { mach_write_to_2(rec - REC_NEXT, next); }}/**********************************************************The following function is used to get the number of fieldsin an old-style record. */UNIV_INLINEulintrec_get_n_fields_old(/*=================*/ /* out: number of data fields */ rec_t* rec) /* in: physical record */{ ulint ret; ut_ad(rec); ret = rec_get_bit_field_2(rec, REC_OLD_N_FIELDS, REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT); ut_ad(ret <= REC_MAX_N_FIELDS); ut_ad(ret > 0); return(ret);} /**********************************************************The following function is used to set the number of fieldsin an old-style record. */UNIV_INLINEvoidrec_set_n_fields_old(/*=================*/ rec_t* rec, /* in: physical record */ ulint n_fields) /* in: the number of fields */{ ut_ad(rec); ut_ad(n_fields <= REC_MAX_N_FIELDS); ut_ad(n_fields > 0); rec_set_bit_field_2(rec, n_fields, REC_OLD_N_FIELDS, REC_OLD_N_FIELDS_MASK, REC_OLD_N_FIELDS_SHIFT);}/**********************************************************The following function retrieves the status bits of a new-style record. */UNIV_INLINEulintrec_get_status(/*===========*/ /* out: status bits */ rec_t* rec) /* in: physical record */{ ulint ret; ut_ad(rec); ret = rec_get_bit_field_1(rec, REC_NEW_STATUS, REC_NEW_STATUS_MASK, REC_NEW_STATUS_SHIFT); ut_ad((ret & ~REC_NEW_STATUS_MASK) == 0); return(ret);}/**********************************************************The following function is used to get the number of fieldsin a record. */UNIV_INLINEulintrec_get_n_fields(/*=============*/ /* out: number of data fields */ rec_t* rec, /* in: physical record */ dict_index_t* index) /* in: record descriptor */{ ut_ad(rec); ut_ad(index); if (UNIV_UNLIKELY(!index->table->comp)) { return(rec_get_n_fields_old(rec)); } switch (rec_get_status(rec)) { case REC_STATUS_ORDINARY: return(dict_index_get_n_fields(index)); case REC_STATUS_NODE_PTR: return(dict_index_get_n_unique_in_tree(index) + 1); case REC_STATUS_INFIMUM: case REC_STATUS_SUPREMUM: return(1); default: ut_error; return(ULINT_UNDEFINED); }}/**********************************************************The following function is used to get the number of records owned by theprevious directory record. */UNIV_INLINEulintrec_get_n_owned(/*============*/ /* out: number of owned records */ rec_t* rec, /* in: physical record */ ulint comp) /* in: nonzero=compact page format */{ ulint ret; ut_ad(rec); ret = rec_get_bit_field_1(rec, comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT); ut_ad(ret <= REC_MAX_N_OWNED); return(ret);} /**********************************************************The following function is used to set the number of owned records. */UNIV_INLINEvoidrec_set_n_owned(/*============*/ rec_t* rec, /* in: physical record */ ulint comp, /* in: nonzero=compact page format */ ulint n_owned) /* in: the number of owned */{ ut_ad(rec); ut_ad(n_owned <= REC_MAX_N_OWNED); rec_set_bit_field_1(rec, n_owned, comp ? REC_NEW_N_OWNED : REC_OLD_N_OWNED, REC_N_OWNED_MASK, REC_N_OWNED_SHIFT);}/**********************************************************The following function is used to retrieve the info bits of a record. */UNIV_INLINEulintrec_get_info_bits(/*==============*/ /* out: info bits */ rec_t* rec, /* in: physical record */ ulint comp) /* in: nonzero=compact page format */{ ulint ret; ut_ad(rec); ret = rec_get_bit_field_1(rec, comp ? REC_NEW_INFO_BITS : REC_OLD_INFO_BITS, REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT); ut_ad((ret & ~REC_INFO_BITS_MASK) == 0); return(ret);} /**********************************************************The following function is used to set the info bits of a record. */UNIV_INLINEvoidrec_set_info_bits(/*==============*/ rec_t* rec, /* in: physical record */ ulint comp, /* in: nonzero=compact page format */ ulint bits) /* in: info bits */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -