Commit b3d6f517 authored by marko@hundin.mysql.fi's avatar marko@hundin.mysql.fi

InnoDB: Performance optimizations based on OProfile analysis

parent ee7ed763
This diff is collapsed.
This diff is collapsed.
......@@ -78,6 +78,7 @@ btr_pcur_store_position(
rec_t* rec;
dict_tree_t* tree;
page_t* page;
ulint offs;
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
......@@ -87,7 +88,8 @@ btr_pcur_store_position(
page_cursor = btr_pcur_get_page_cur(cursor);
rec = page_cur_get_rec(page_cursor);
page = buf_frame_align(rec);
page = ut_align_down(rec, UNIV_PAGE_SIZE);
offs = ut_align_offset(rec, UNIV_PAGE_SIZE);
ut_ad(mtr_memo_contains(mtr, buf_block_align(page),
MTR_MEMO_PAGE_S_FIX)
......@@ -95,35 +97,33 @@ btr_pcur_store_position(
MTR_MEMO_PAGE_X_FIX));
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
if (page_get_n_recs(page) == 0) {
if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
/* It must be an empty index tree; NOTE that in this case
we do not store the modify_clock, but always do a search
if we restore the cursor position */
ut_a(btr_page_get_next(page, mtr) == FIL_NULL
&& btr_page_get_prev(page, mtr) == FIL_NULL);
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
if (rec == page_get_supremum_rec(page)) {
cursor->old_stored = BTR_PCUR_OLD_STORED;
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
cursor->old_stored = BTR_PCUR_OLD_STORED;
if (page_rec_is_supremum_low(offs)) {
return;
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
} else {
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
}
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
cursor->old_stored = BTR_PCUR_OLD_STORED;
return;
}
if (rec == page_get_supremum_rec(page)) {
if (page_rec_is_supremum_low(offs)) {
rec = page_rec_get_prev(rec);
cursor->rel_pos = BTR_PCUR_AFTER;
} else if (rec == page_get_infimum_rec(page)) {
} else if (page_rec_is_infimum_low(offs)) {
rec = page_rec_get_next(rec);
......@@ -139,7 +139,8 @@ btr_pcur_store_position(
&cursor->buf_size);
cursor->block_when_stored = buf_block_align(page);
cursor->modify_clock = buf_frame_get_modify_clock(page);
cursor->modify_clock = buf_block_get_modify_clock(
cursor->block_when_stored);
}
/******************************************************************
......@@ -202,12 +203,11 @@ btr_pcur_restore_position(
dtuple_t* tuple;
ulint mode;
ulint old_mode;
ibool from_left;
mem_heap_t* heap;
ut_a(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
|| cursor->pos_state == BTR_PCUR_IS_POSITIONED);
if (cursor->old_stored != BTR_PCUR_OLD_STORED) {
if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)) {
ut_print_buf(stderr, (const byte*)cursor, sizeof(btr_pcur_t));
if (cursor->trx_if_known) {
trx_print(stderr, cursor->trx_if_known);
......@@ -216,19 +216,14 @@ btr_pcur_restore_position(
ut_a(0);
}
if (cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
if (UNIV_UNLIKELY(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
/* In these cases we do not try an optimistic restoration,
but always do a search */
if (cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE) {
from_left = TRUE;
} else {
from_left = FALSE;
}
btr_cur_open_at_index_side(from_left,
btr_cur_open_at_index_side(
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
btr_pcur_get_btr_cur(cursor)->index, latch_mode,
btr_pcur_get_btr_cur(cursor), mtr);
......@@ -238,17 +233,18 @@ btr_pcur_restore_position(
return(FALSE);
}
ut_a(cursor->old_rec);
ut_a(cursor->old_n_fields);
ut_ad(cursor->old_rec);
ut_ad(cursor->old_n_fields);
page = btr_cur_get_page(btr_pcur_get_btr_cur(cursor));
if (latch_mode == BTR_SEARCH_LEAF || latch_mode == BTR_MODIFY_LEAF) {
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
/* Try optimistic restoration */
if (buf_page_optimistic_get(latch_mode,
if (UNIV_LIKELY(buf_page_optimistic_get(latch_mode,
cursor->block_when_stored, page,
cursor->modify_clock, mtr)) {
cursor->modify_clock, mtr))) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
#ifdef UNIV_SYNC_DEBUG
buf_page_dbg_add_level(page, SYNC_TREE_NODE);
......@@ -297,7 +293,7 @@ btr_pcur_restore_position(
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
if (cursor->rel_pos == BTR_PCUR_ON) {
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
mode = PAGE_CUR_LE;
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
mode = PAGE_CUR_G;
......@@ -323,12 +319,10 @@ btr_pcur_restore_position(
the cursor can now be on a different page! But we can retain
the value of old_rec */
cursor->modify_clock =
buf_frame_get_modify_clock(btr_pcur_get_page(cursor));
cursor->block_when_stored =
buf_block_align(btr_pcur_get_page(cursor));
cursor->modify_clock =
buf_block_get_modify_clock(cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
mem_heap_free(heap);
......
This diff is collapsed.
......@@ -736,7 +736,7 @@ dict_truncate_index_tree(
dulint index_id;
byte* ptr;
ulint len;
ibool comp;
ulint comp;
dict_index_t* index;
#ifdef UNIV_SYNC_DEBUG
......
......@@ -1889,7 +1889,7 @@ ibuf_get_merge_page_nos(
contract the tree, FALSE if this is called
when a single page becomes full and we look
if it pays to read also nearby pages */
rec_t* first_rec,/* in: record from which we read up and down
rec_t* rec, /* in: record from which we read up and down
in the chain of records */
ulint* space_ids,/* in/out: space id's of the pages */
ib_longlong* space_versions,/* in/out: tablespace version
......@@ -1907,47 +1907,42 @@ ibuf_get_merge_page_nos(
ulint first_space_id;
ulint rec_page_no;
ulint rec_space_id;
rec_t* rec;
ulint sum_volumes;
ulint volume_for_page;
ulint rec_volume;
ulint limit;
page_t* page;
ulint n_pages;
*n_stored = 0;
limit = ut_min(IBUF_MAX_N_PAGES_MERGED, buf_pool->curr_size / 4);
page = buf_frame_align(first_rec);
if (first_rec == page_get_supremum_rec(page)) {
if (page_rec_is_supremum(rec)) {
first_rec = page_rec_get_prev(first_rec);
rec = page_rec_get_prev(rec);
}
if (first_rec == page_get_infimum_rec(page)) {
if (page_rec_is_infimum(rec)) {
first_rec = page_rec_get_next(first_rec);
rec = page_rec_get_next(rec);
}
if (first_rec == page_get_supremum_rec(page)) {
if (page_rec_is_supremum(rec)) {
return(0);
}
rec = first_rec;
first_page_no = ibuf_rec_get_page_no(first_rec);
first_space_id = ibuf_rec_get_space(first_rec);
first_page_no = ibuf_rec_get_page_no(rec);
first_space_id = ibuf_rec_get_space(rec);
n_pages = 0;
prev_page_no = 0;
prev_space_id = 0;
/* Go backwards from the first_rec until we reach the border of the
/* Go backwards from the first rec until we reach the border of the
'merge area', or the page start or the limit of storeable pages is
reached */
while ((rec != page_get_infimum_rec(page)) && (n_pages < limit)) {
while (!page_rec_is_infimum(rec) && UNIV_LIKELY(n_pages < limit)) {
rec_page_no = ibuf_rec_get_page_no(rec);
rec_space_id = ibuf_rec_get_space(rec);
......@@ -1982,7 +1977,7 @@ ibuf_get_merge_page_nos(
volume_for_page = 0;
while (*n_stored < limit) {
if (rec == page_get_supremum_rec(page)) {
if (page_rec_is_supremum(rec)) {
/* When no more records available, mark this with
another 'impossible' pair of space id, page no */
rec_page_no = 1;
......@@ -2311,12 +2306,12 @@ ibuf_get_volume_buffered(
page = buf_frame_align(rec);
if (rec == page_get_supremum_rec(page)) {
if (page_rec_is_supremum(rec)) {
rec = page_rec_get_prev(rec);
}
for (;;) {
if (rec == page_get_infimum_rec(page)) {
if (page_rec_is_infimum(rec)) {
break;
}
......@@ -2351,7 +2346,7 @@ ibuf_get_volume_buffered(
rec = page_rec_get_prev(rec);
for (;;) {
if (rec == page_get_infimum_rec(prev_page)) {
if (page_rec_is_infimum(rec)) {
/* We cannot go to yet a previous page, because we
do not have the x-latch on it, and cannot acquire one
......@@ -2374,12 +2369,12 @@ ibuf_get_volume_buffered(
count_later:
rec = btr_pcur_get_rec(pcur);
if (rec != page_get_supremum_rec(page)) {
if (!page_rec_is_supremum(rec)) {
rec = page_rec_get_next(rec);
}
for (;;) {
if (rec == page_get_supremum_rec(page)) {
if (page_rec_is_supremum(rec)) {
break;
}
......@@ -2414,7 +2409,7 @@ ibuf_get_volume_buffered(
rec = page_rec_get_next(rec);
for (;;) {
if (rec == page_get_supremum_rec(next_page)) {
if (page_rec_is_supremum(rec)) {
/* We give up */
......@@ -2815,7 +2810,7 @@ ibuf_insert_to_index_page(
ut_ad(ibuf_inside());
ut_ad(dtuple_check_typed(entry));
if (index->table->comp != page_is_comp(page)) {
if (UNIV_UNLIKELY(index->table->comp != !!page_is_comp(page))) {
fputs(
"InnoDB: Trying to insert a record from the insert buffer to an index page\n"
"InnoDB: but the 'compact' flag does not match!\n", stderr);
......@@ -2824,7 +2819,8 @@ ibuf_insert_to_index_page(
rec = page_rec_get_next(page_get_infimum_rec(page));
if (rec_get_n_fields(rec, index) != dtuple_get_n_fields(entry)) {
if (UNIV_UNLIKELY(rec_get_n_fields(rec, index)
!= dtuple_get_n_fields(entry))) {
fputs(
"InnoDB: Trying to insert a record from the insert buffer to an index page\n"
"InnoDB: but the number of fields does not match!\n", stderr);
......@@ -2861,8 +2857,8 @@ ibuf_insert_to_index_page(
PAGE_CUR_LE, &page_cur);
/* This time the record must fit */
if (!page_cur_tuple_insert(&page_cur, entry,
index, mtr)) {
if (UNIV_UNLIKELY(!page_cur_tuple_insert(
&page_cur, entry, index, mtr))) {
ut_print_timestamp(stderr);
......
......@@ -168,7 +168,7 @@ btr_create(
ulint type, /* in: type of the index */
ulint space, /* in: space where created */
dulint index_id,/* in: index id */
ibool comp, /* in: TRUE=compact page format */
ulint comp, /* in: nonzero=compact page format */
mtr_t* mtr); /* in: mini-transaction handle */
/****************************************************************
Frees a B-tree except the root page, which MUST be freed after this
......@@ -276,7 +276,7 @@ void
btr_set_min_rec_mark(
/*=================*/
rec_t* rec, /* in: record */
ibool comp, /* in: TRUE=compact page format */
ulint comp, /* in: nonzero=compact page format */
mtr_t* mtr); /* in: mtr */
/*****************************************************************
Deletes on the upper level the node pointer to a page. */
......@@ -336,7 +336,7 @@ btr_parse_set_min_rec_mark(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
ibool comp, /* in: TRUE=compact page format */
ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
/***************************************************************
......
......@@ -382,10 +382,10 @@ Returns the value of the modify clock. The caller must have an s-lock
or x-lock on the block. */
UNIV_INLINE
dulint
buf_frame_get_modify_clock(
buf_block_get_modify_clock(
/*=======================*/
/* out: value */
buf_frame_t* frame); /* in: pointer to a frame */
buf_block_t* block); /* in: block */
/************************************************************************
Calculates a page checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value
......
......@@ -481,17 +481,11 @@ Returns the value of the modify clock. The caller must have an s-lock
or x-lock on the block. */
UNIV_INLINE
dulint
buf_frame_get_modify_clock(
buf_block_get_modify_clock(
/*=======================*/
/* out: value */
buf_frame_t* frame) /* in: pointer to a frame */
buf_block_t* block) /* in: block */
{
buf_block_t* block;
ut_ad(frame);
block = buf_block_align(frame);
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&(block->lock), RW_LOCK_SHARED)
|| rw_lock_own(&(block->lock), RW_LOCK_EXCLUSIVE));
......
......@@ -216,6 +216,7 @@ actual record is being moved. */
void
lock_rec_store_on_page_infimum(
/*===========================*/
page_t* page, /* in: page containing the record */
rec_t* rec); /* in: record whose lock state is stored
on the infimum record of the same page; lock
bits are reset on the record */
......
......@@ -52,6 +52,27 @@ mach_read_from_2(
/*=============*/
/* out: ulint integer, >= 0, < 64k */
byte* b); /* in: pointer to two bytes */
/************************************************************
The following function is used to convert a 16-bit data item
to the canonical format, for fast bytewise equality test
against memory. */
UNIV_INLINE
uint16
mach_encode_2(
/*==========*/
/* out: 16-bit integer in canonical format */
ulint n); /* in: integer in machine-dependent format */
/************************************************************
The following function is used to convert a 16-bit data item
from the canonical format, for fast bytewise equality test
against memory. */
UNIV_INLINE
ulint
mach_decode_2(
/*==========*/
/* out: integer in machine-dependent format */
uint16 n); /* in: 16-bit integer in canonical format */
/***********************************************************
The following function is used to store data in 3 consecutive
bytes. We store the most significant byte to the lowest address. */
......
......@@ -68,6 +68,37 @@ mach_read_from_2(
);
}
/************************************************************
The following function is used to convert a 16-bit data item
to the canonical format, for fast bytewise equality test
against memory. */
UNIV_INLINE
uint16
mach_encode_2(
/*==========*/
/* out: 16-bit integer in canonical format */
ulint n) /* in: integer in machine-dependent format */
{
uint16 ret;
ut_ad(2 == sizeof ret);
mach_write_to_2((byte*) &ret, n);
return(ret);
}
/************************************************************
The following function is used to convert a 16-bit data item
from the canonical format, for fast bytewise equality test
against memory. */
UNIV_INLINE
ulint
mach_decode_2(
/*==========*/
/* out: integer in machine-dependent format */
uint16 n) /* in: 16-bit integer in canonical format */
{
ut_ad(2 == sizeof n);
return(mach_read_from_2((byte*) &n));
}
/***********************************************************
The following function is used to store data in 3 consecutive
bytes. We store the most significant byte to the lowest address. */
......
......@@ -78,16 +78,16 @@ UNIV_INLINE
ibool
page_cur_is_before_first(
/*=====================*/
/* out: TRUE if at start */
page_cur_t* cur); /* in: cursor */
/* out: TRUE if at start */
const page_cur_t* cur); /* in: cursor */
/*************************************************************
Returns TRUE if the cursor is after last user record. */
UNIV_INLINE
ibool
page_cur_is_after_last(
/*===================*/
/* out: TRUE if at end */
page_cur_t* cur); /* in: cursor */
/* out: TRUE if at end */
const page_cur_t* cur); /* in: cursor */
/**************************************************************
Positions the cursor on the given record. */
UNIV_INLINE
......
......@@ -69,15 +69,10 @@ UNIV_INLINE
ibool
page_cur_is_before_first(
/*=====================*/
/* out: TRUE if at start */
page_cur_t* cur) /* in: cursor */
/* out: TRUE if at start */
const page_cur_t* cur) /* in: cursor */
{
if (page_get_infimum_rec(page_cur_get_page(cur)) == cur->rec) {
return(TRUE);
}
return(FALSE);
return(page_rec_is_infimum(cur->rec));
}
/*************************************************************
......@@ -86,15 +81,10 @@ UNIV_INLINE
ibool
page_cur_is_after_last(
/*===================*/
/* out: TRUE if at end */
page_cur_t* cur) /* in: cursor */
/* out: TRUE if at end */
const page_cur_t* cur) /* in: cursor */
{
if (page_get_supremum_rec(page_cur_get_page(cur)) == cur->rec) {
return(TRUE);
}
return(FALSE);
return(page_rec_is_supremum(cur->rec));
}
/**************************************************************
......
......@@ -373,13 +373,21 @@ page_dir_find_owner_slot(
/****************************************************************
Determine whether the page is in new-style compact format. */
UNIV_INLINE
ibool
ulint
page_is_comp(
/*=========*/
/* out: TRUE if the page is in compact format
FALSE if it is in old-style format */
/* out: nonzero if the page is in compact
format, zero if it is in old-style format */
page_t* page); /* in: index page */
/****************************************************************
TRUE if the record is on a page in compact format. */
UNIV_INLINE
ulint
page_rec_is_comp(
/*=============*/
/* out: nonzero if in compact format */
const rec_t* rec); /* in: record */
/****************************************************************
Gets the pointer to the next record on the page. */
UNIV_INLINE
rec_t*
......@@ -407,47 +415,55 @@ page_rec_get_prev(
/* out: pointer to previous record */
rec_t* rec); /* in: pointer to record,
must not be page infimum */
/****************************************************************
TRUE if the record is a user record on the page. */
UNIV_INLINE
ibool
page_rec_is_user_rec(
/*=================*/
page_rec_is_user_rec_low(
/*=====================*/
/* out: TRUE if a user record */
rec_t* rec); /* in: record */
ulint offset);/* in: record offset on page */
/****************************************************************
TRUE if the record is the supremum record on a page. */
UNIV_INLINE
ibool
page_rec_is_supremum(
/*=================*/
page_rec_is_supremum_low(
/*=====================*/
/* out: TRUE if the supremum record */
rec_t* rec); /* in: record */
ulint offset);/* in: record offset on page */
/****************************************************************
TRUE if the record is the infimum record on a page. */
UNIV_INLINE
ibool
page_rec_is_infimum(
/*================*/
page_rec_is_infimum_low(
/*=====================*/
/* out: TRUE if the infimum record */
rec_t* rec); /* in: record */
ulint offset);/* in: record offset on page */
/****************************************************************
TRUE if the record is the first user record on the page. */
TRUE if the record is a user record on the page. */
UNIV_INLINE
ibool
page_rec_is_first_user_rec(
/*=======================*/
/* out: TRUE if first user record */
rec_t* rec); /* in: record */
page_rec_is_user_rec(
/*=================*/
/* out: TRUE if a user record */
const rec_t* rec); /* in: record */
/****************************************************************
TRUE if the record is the last user record on the page. */
TRUE if the record is the supremum record on a page. */
UNIV_INLINE
ibool
page_rec_is_last_user_rec(
/*======================*/
/* out: TRUE if last user record */
rec_t* rec); /* in: record */
page_rec_is_supremum(
/*=================*/
/* out: TRUE if the supremum record */
const rec_t* rec); /* in: record */
/****************************************************************
TRUE if the record is the infimum record on a page. */
UNIV_INLINE
ibool
page_rec_is_infimum(
/*================*/
/* out: TRUE if the infimum record */
const rec_t* rec); /* in: record */
/*******************************************************************
Looks for the record which owns the given record. */
UNIV_INLINE
......@@ -495,7 +511,7 @@ ulint
page_get_free_space_of_empty(
/*=========================*/
/* out: free space */
ibool comp) /* in: TRUE=compact page format */
ulint comp) /* in: nonzero=compact page format */
__attribute__((const));
/****************************************************************
Returns the sum of the sizes of the records in the record list
......@@ -539,7 +555,7 @@ page_create(
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
mtr_t* mtr, /* in: mini-transaction handle */
ibool comp); /* in: TRUE=compact page format */
ulint comp); /* in: nonzero=compact page format */
/*****************************************************************
Differs from page_copy_rec_list_end, because this function does not
touch the lock table and max trx id on page. */
......@@ -673,7 +689,7 @@ page_parse_create(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr,/* in: buffer end */
ibool comp, /* in: TRUE=compact page format */
ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr); /* in: mtr or NULL */
/****************************************************************
......
This diff is collapsed.
......@@ -929,14 +929,14 @@ rec_get_nth_field(
Determine if the offsets are for a record in the new
compact format. */
UNIV_INLINE
ibool
ulint
rec_offs_comp(
/*==========*/
/* out: TRUE if compact format */
/* out: nonzero if compact format */
const ulint* offsets)/* in: array returned by rec_get_offsets() */
{
ut_ad(rec_offs_validate(NULL, NULL, offsets));
return((*rec_offs_base(offsets) & REC_OFFS_COMPACT) != 0);
return(*rec_offs_base(offsets) & REC_OFFS_COMPACT);
}
/**********************************************************
......
......@@ -110,7 +110,7 @@ row_mysql_store_col_in_innobase_format(
necessarily the length of the actual
payload data; if the column is a true
VARCHAR then this is irrelevant */
ibool comp); /* in: TRUE = compact format */
ulint comp); /* in: nonzero=compact format */
/********************************************************************
Handles user errors and lock waits detected by the database engine. */
......
This diff is collapsed.
......@@ -15,6 +15,7 @@ Created 12/7/1995 Heikki Tuuri
#include "buf0buf.h"
#include "dict0boot.h"
#include "log0recv.h"
#include "page0page.h"
/************************************************************
Catenates n bytes to the mtr log. */
......@@ -405,7 +406,9 @@ mlog_open_and_write_index(
const byte* log_start;
const byte* log_end;
if (!index->table->comp) {
ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
if (!page_rec_is_comp(rec)) {
log_start = log_ptr = mlog_open(mtr, 11 + size);
if (!log_ptr) {
return(NULL); /* logging is disabled */
......@@ -498,6 +501,8 @@ mlog_parse_index(
dict_table_t* table;
dict_index_t* ind;
ut_ad(comp == FALSE || comp == TRUE);
if (comp) {
if (end_ptr < ptr + 4) {
return(NULL);
......
......@@ -515,8 +515,12 @@ page_cur_insert_rec_write_log(
byte* log_ptr;
byte* log_end;
ulint i;
ulint comp;
ut_a(rec_size < UNIV_PAGE_SIZE);
ut_ad(buf_frame_align(insert_rec) == buf_frame_align(cursor_rec));
ut_ad(!page_rec_is_comp(insert_rec) == !index->table->comp);
comp = page_rec_is_comp(insert_rec);
{
mem_heap_t* heap = NULL;
......@@ -565,7 +569,7 @@ page_cur_insert_rec_write_log(
ins_ptr++;
cur_ptr++;
} else if ((i < extra_size)
&& (i >= extra_size - (index->table->comp
&& (i >= extra_size - (comp
? REC_N_NEW_EXTRA_BYTES
: REC_N_OLD_EXTRA_BYTES))) {
i = extra_size;
......@@ -580,7 +584,7 @@ page_cur_insert_rec_write_log(
if (mtr_get_log_mode(mtr) != MTR_LOG_SHORT_INSERTS) {
log_ptr = mlog_open_and_write_index(mtr, insert_rec, index,
index->table->comp
comp
? MLOG_COMP_REC_INSERT : MLOG_REC_INSERT,
2 + 5 + 1 + 5 + 5 + MLOG_BUF_MARGIN);
......@@ -605,8 +609,8 @@ page_cur_insert_rec_write_log(
log_end = &log_ptr[5 + 1 + 5 + 5 + MLOG_BUF_MARGIN];
}
if ((rec_get_info_and_status_bits(insert_rec, index->table->comp) !=
rec_get_info_and_status_bits(cursor_rec, index->table->comp))
if ((rec_get_info_and_status_bits(insert_rec, comp) !=
rec_get_info_and_status_bits(cursor_rec, comp))
|| (extra_size != cur_extra_size)
|| (rec_size != cur_rec_size)) {
......@@ -622,8 +626,7 @@ page_cur_insert_rec_write_log(
if (extra_info_yes) {
/* Write the info bits */
mach_write_to_1(log_ptr,
rec_get_info_and_status_bits(insert_rec,
index->table->comp));
rec_get_info_and_status_bits(insert_rec, comp));
log_ptr++;
/* Write the record origin offset */
......@@ -757,6 +760,8 @@ page_cur_parse_insert_rec(
return(ptr + end_seg_len);
}
ut_ad(!!page_is_comp(page) == index->table->comp);
/* Read from the log the inserted index record end segment which
differs from the cursor record */
......@@ -771,7 +776,7 @@ page_cur_parse_insert_rec(
if (extra_info_yes == 0) {
info_and_status_bits = rec_get_info_and_status_bits(
cursor_rec, index->table->comp);
cursor_rec, page_is_comp(page));
origin_offset = rec_offs_extra_size(offsets);
mismatch_index = rec_offs_size(offsets) - end_seg_len;
}
......@@ -807,7 +812,7 @@ page_cur_parse_insert_rec(
ut_memcpy(buf, rec_get_start(cursor_rec, offsets), mismatch_index);
ut_memcpy(buf + mismatch_index, ptr, end_seg_len);
rec_set_info_and_status_bits(buf + origin_offset, index->table->comp,
rec_set_info_and_status_bits(buf + origin_offset, page_is_comp(page),
info_and_status_bits);
page_cur_position(cursor_rec, &cursor);
......@@ -861,7 +866,7 @@ page_cur_insert_rec_low(
rec_t* owner_rec;
ulint n_owned;
mem_heap_t* heap = NULL;
ibool comp = index->table->comp;
ulint comp;
ut_ad(cursor && mtr);
ut_ad(tuple || rec);
......@@ -869,8 +874,8 @@ page_cur_insert_rec_low(
ut_ad(rec || dtuple_check_typed(tuple));
page = page_cur_get_page(cursor);
ut_ad(page_is_comp(page) == comp);
comp = page_is_comp(page);
ut_ad(index->table->comp == !!comp);
ut_ad(cursor->rec != page_get_supremum_rec(page));
......@@ -1000,8 +1005,10 @@ page_copy_rec_list_to_created_page_write_log(
{
byte* log_ptr;
ut_ad(!!page_is_comp(page) == index->table->comp);
log_ptr = mlog_open_and_write_index(mtr, page, index,
index->table->comp
page_is_comp(page)
? MLOG_COMP_LIST_END_COPY_CREATED
: MLOG_LIST_END_COPY_CREATED, 4);
ut_a(log_ptr);
......@@ -1084,7 +1091,7 @@ page_copy_rec_list_end_to_created_page(
ulint log_mode;
byte* log_ptr;
ulint log_data_len;
ibool comp = page_is_comp(page);
ulint comp = page_is_comp(page);
mem_heap_t* heap = NULL;
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
......@@ -1230,8 +1237,10 @@ page_cur_delete_rec_write_log(
{
byte* log_ptr;
ut_ad(!!page_rec_is_comp(rec) == index->table->comp);
log_ptr = mlog_open_and_write_index(mtr, rec, index,
index->table->comp
page_rec_is_comp(rec)
? MLOG_COMP_REC_DELETE
: MLOG_REC_DELETE, 2);
......@@ -1242,7 +1251,7 @@ page_cur_delete_rec_write_log(
}
/* Write the cursor rec offset as a 2-byte ulint */
mach_write_to_2(log_ptr, rec - buf_frame_align(rec));
mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
mlog_close(mtr, log_ptr + 2);
}
......@@ -1320,6 +1329,7 @@ page_cur_delete_rec(
page = page_cur_get_page(cursor);
current_rec = cursor->rec;
ut_ad(rec_offs_validate(current_rec, index, offsets));
ut_ad(!!page_is_comp(page) == index->table->comp);
/* The record must not be the supremum or infimum record. */
ut_ad(current_rec != page_get_supremum_rec(page));
......
......@@ -72,65 +72,70 @@ page_dir_find_owner_slot(
/* out: the directory slot number */
rec_t* rec) /* in: the physical record */
{
ulint i;
ulint steps = 0;
page_t* page;
page_dir_slot_t* slot;
rec_t* original_rec = rec;
ibool comp;
page_t* page;
register uint16 rec_offs_bytes;
register page_dir_slot_t* slot;
register const page_dir_slot_t* first_slot;
register rec_t* r = rec;
ut_ad(page_rec_check(rec));
page = buf_frame_align(rec);
comp = page_is_comp(page);
while (rec_get_n_owned(rec, comp) == 0) {
steps++;
rec = page_rec_get_next(rec);
first_slot = page_dir_get_nth_slot(page, 0);
slot = page_dir_get_nth_slot(page, page_dir_get_n_slots(page) - 1);
if (page_is_comp(page)) {
while (rec_get_n_owned(r, TRUE) == 0) {
r = page + rec_get_next_offs(r, TRUE);
ut_ad(r >= page + PAGE_NEW_SUPREMUM);
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
}
} else {
while (rec_get_n_owned(r, FALSE) == 0) {
r = page + rec_get_next_offs(r, FALSE);
ut_ad(r >= page + PAGE_OLD_SUPREMUM);
ut_ad(r < page + (UNIV_PAGE_SIZE - PAGE_DIR));
}
}
page = buf_frame_align(rec);
i = page_dir_get_n_slots(page) - 1;
slot = page_dir_get_nth_slot(page, i);
rec_offs_bytes = mach_encode_2(r - page);
while (page_dir_slot_get_rec(slot) != rec) {
while (UNIV_LIKELY(*(uint16*) slot != rec_offs_bytes)) {
if (i == 0) {
if (UNIV_UNLIKELY(slot == first_slot)) {
fprintf(stderr,
"InnoDB: Probable data corruption on page %lu\n"
"InnoDB: Original record ",
(ulong) buf_frame_get_page_no(page));
if (comp) {
if (page_is_comp(page)) {
fputs("(compact record)", stderr);
} else {
rec_print_old(stderr, original_rec);
rec_print_old(stderr, rec);
}
fprintf(stderr, "\n"
"InnoDB: on that page. Steps %lu.\n", (ulong) steps);
fputs(
fputs("\n"
"InnoDB: on that page.\n"
"InnoDB: Cannot find the dir slot for record ",
stderr);
if (comp) {
if (page_is_comp(page)) {
fputs("(compact record)", stderr);
} else {
rec_print_old(stderr, rec);
rec_print_old(stderr, page
+ mach_decode_2(rec_offs_bytes));
}
fputs("\n"
"InnoDB: on that page!\n", stderr);
buf_page_print(page);
ut_error;
}
ut_error;
}
i--;
slot = page_dir_get_nth_slot(page, i);
slot += PAGE_DIR_SLOT_SIZE;
}
return(i);
return(((ulint) (first_slot - slot)) / PAGE_DIR_SLOT_SIZE);
}
/******************************************************************
......@@ -290,7 +295,7 @@ page_create_write_log(
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
mtr_t* mtr, /* in: mini-transaction handle */
ibool comp) /* in: TRUE=compact page format */
ulint comp) /* in: nonzero=compact page format */
{
mlog_write_initial_log_record(frame,
comp ? MLOG_COMP_PAGE_CREATE : MLOG_PAGE_CREATE, mtr);
......@@ -305,7 +310,7 @@ page_parse_create(
/* out: end of log record or NULL */
byte* ptr, /* in: buffer */
byte* end_ptr __attribute__((unused)), /* in: buffer end */
ibool comp, /* in: TRUE=compact page format */
ulint comp, /* in: nonzero=compact page format */
page_t* page, /* in: page or NULL */
mtr_t* mtr) /* in: mtr or NULL */
{
......@@ -330,7 +335,7 @@ page_create(
buf_frame_t* frame, /* in: a buffer frame where the page is
created */
mtr_t* mtr, /* in: mini-transaction handle */
ibool comp) /* in: TRUE=compact page format */
ulint comp) /* in: nonzero=compact page format */
{
page_dir_slot_t* slot;
mem_heap_t* heap;
......@@ -396,9 +401,9 @@ page_create(
dtuple_set_info_bits(tuple, REC_STATUS_SUPREMUM);
field = dtuple_get_nth_field(tuple, 0);
dfield_set_data(field, "supremum", 9 - comp);
dfield_set_data(field, "supremum", comp ? 8 : 9);
dtype_set(dfield_get_type(field),
DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, 9 - comp, 0);
DATA_VARCHAR, DATA_ENGLISH | DATA_NOT_NULL, comp ? 8 : 9, 0);
supremum_rec = rec_convert_dtuple_to_rec(heap_top, index, tuple);
......@@ -478,10 +483,11 @@ page_copy_rec_list_end_no_locks(
page_cur_move_to_next(&cur1);
}
ut_a(index->table->comp == page_is_comp(page));
ut_a(index->table->comp == page_is_comp(new_page));
ut_a(!!page_is_comp(new_page) == index->table->comp);
ut_a(page_is_comp(new_page) == page_is_comp(page));
ut_a(mach_read_from_2(new_page + UNIV_PAGE_SIZE - 10) == (ulint)
(index->table->comp ? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
(page_is_comp(new_page)
? PAGE_NEW_INFIMUM : PAGE_OLD_INFIMUM));
page_cur_set_before_first(new_page, &cur2);
......@@ -489,12 +495,15 @@ page_copy_rec_list_end_no_locks(
sup = page_get_supremum_rec(page);
while (sup != page_cur_get_rec(&cur1)) {
for (;;) {
rec_t* cur1_rec = page_cur_get_rec(&cur1);
if (cur1_rec == sup) {
break;
}
offsets = rec_get_offsets(cur1_rec, index, offsets,
ULINT_UNDEFINED, &heap);
if (!page_cur_rec_insert(&cur2, cur1_rec, index,
offsets, mtr)) {
if (UNIV_UNLIKELY(!page_cur_rec_insert(&cur2, cur1_rec, index,
offsets, mtr))) {
/* Track an assertion failure reported on the mailing
list on June 18th, 2003 */
......@@ -619,7 +628,6 @@ UNIV_INLINE
void
page_delete_rec_list_write_log(
/*===========================*/
page_t* page, /* in: index page */
rec_t* rec, /* in: record on page */
dict_index_t* index, /* in: record descriptor */
byte type, /* in: operation type:
......@@ -632,10 +640,10 @@ page_delete_rec_list_write_log(
|| type == MLOG_COMP_LIST_END_DELETE
|| type == MLOG_COMP_LIST_START_DELETE);
log_ptr = mlog_open_and_write_index(mtr, page, index, type, 2);
log_ptr = mlog_open_and_write_index(mtr, rec, index, type, 2);
if (log_ptr) {
/* Write the parameter as a 2-byte ulint */
mach_write_to_2(log_ptr, rec - page);
mach_write_to_2(log_ptr, ut_align_offset(rec, UNIV_PAGE_SIZE));
mlog_close(mtr, log_ptr + 2);
}
}
......@@ -679,6 +687,8 @@ page_parse_delete_rec_list(
return(ptr);
}
ut_ad(!!page_is_comp(page) == index->table->comp);
if (type == MLOG_LIST_END_DELETE
|| type == MLOG_COMP_LIST_END_DELETE) {
page_delete_rec_list_end(page, page + offset, index,
......@@ -716,7 +726,7 @@ page_delete_rec_list_end(
ulint count;
ulint n_owned;
rec_t* sup;
ibool comp;
ulint comp;
/* Reset the last insert info in the page header and increment
the modify clock for the frame */
......@@ -731,12 +741,12 @@ page_delete_rec_list_end(
sup = page_get_supremum_rec(page);
if (rec == page_get_infimum_rec(page)) {
comp = page_is_comp(page);
if (page_rec_is_infimum_low(rec - page)) {
rec = page_rec_get_next(rec);
}
comp = page_is_comp(page);
page_delete_rec_list_write_log(page, rec, index,
page_delete_rec_list_write_log(rec, index,
comp ? MLOG_COMP_LIST_END_DELETE : MLOG_LIST_END_DELETE, mtr);
if (rec == sup) {
......@@ -841,13 +851,15 @@ page_delete_rec_list_start(
byte type;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
if (index->table->comp) {
ut_ad(!!page_is_comp(page) == index->table->comp);
if (page_is_comp(page)) {
type = MLOG_COMP_LIST_START_DELETE;
} else {
type = MLOG_LIST_START_DELETE;
}
page_delete_rec_list_write_log(page, rec, index, type, mtr);
page_delete_rec_list_write_log(rec, index, type, mtr);
page_cur_set_before_first(page, &cur1);
......@@ -1221,7 +1233,7 @@ page_rec_get_n_recs_before(
rec_t* slot_rec;
page_t* page;
ulint i;
ibool comp;
ulint comp;
lint n = 0;
ut_ad(page_rec_check(rec));
......@@ -1264,9 +1276,9 @@ page_rec_print(
rec_t* rec, /* in: physical record */
const ulint* offsets)/* in: record descriptor */
{
ibool comp = page_is_comp(buf_frame_align(rec));
ulint comp = page_is_comp(buf_frame_align(rec));
ut_a(comp == rec_offs_comp(offsets));
ut_a(!comp == !rec_offs_comp(offsets));
rec_print_new(stderr, rec, offsets);
fprintf(stderr,
" n_owned: %lu; heap_no: %lu; next rec: %lu\n",
......@@ -1335,7 +1347,7 @@ page_print_list(
ulint* offsets = offsets_;
*offsets_ = (sizeof offsets_) / sizeof *offsets_;
ut_a(page_is_comp(page) == index->table->comp);
ut_a(!!page_is_comp(page) == index->table->comp);
fprintf(stderr,
"--------------------------------\n"
......@@ -1447,11 +1459,11 @@ page_rec_validate(
ulint n_owned;
ulint heap_no;
page_t* page;
ibool comp;
ulint comp;
page = buf_frame_align(rec);
comp = page_is_comp(page);
ut_a(comp == rec_offs_comp(offsets));
ut_a(!comp == !rec_offs_comp(offsets));
page_rec_check(rec);
rec_validate(rec, offsets);
......@@ -1528,7 +1540,7 @@ page_simple_validate(
ulint count;
ulint own_count;
ibool ret = FALSE;
ibool comp = page_is_comp(page);
ulint comp = page_is_comp(page);
/* Check first that the record heap and the directory do not
overlap. */
......@@ -1725,11 +1737,11 @@ page_validate(
ulint n_slots;
ibool ret = FALSE;
ulint i;
ibool comp = page_is_comp(page);
ulint comp = page_is_comp(page);
ulint* offsets = NULL;
ulint* old_offsets = NULL;
if (comp != index->table->comp) {
if (!!comp != index->table->comp) {
fputs("InnoDB: 'compact format' flag mismatch\n", stderr);
goto func_exit2;
}
......@@ -1810,8 +1822,7 @@ page_validate(
}
}
if ((rec != page_get_supremum_rec(page))
&& (rec != page_get_infimum_rec(page))) {
if (page_rec_is_user_rec(rec)) {
data_size += rec_offs_size(offsets);
}
......
......@@ -727,7 +727,7 @@ cmp_rec_rec_with_match(
ulint cur_bytes; /* number of already matched bytes in current
field */
int ret = 3333; /* return value */
ibool comp;
ulint comp;
ut_ad(rec1 && rec2 && index);
ut_ad(rec_offs_validate(rec1, index, offsets1));
......
......@@ -1255,9 +1255,11 @@ row_ins_check_foreign_constraint(
/* Scan index records and check if there is a matching record */
for (;;) {
page_t* page;
rec = btr_pcur_get_rec(&pcur);
page = buf_frame_align(rec);
if (rec == page_get_infimum_rec(buf_frame_align(rec))) {
if (rec == page_get_infimum_rec(page)) {
goto next_rec;
}
......@@ -1265,7 +1267,7 @@ row_ins_check_foreign_constraint(
offsets = rec_get_offsets(rec, check_index,
offsets, ULINT_UNDEFINED, &heap);
if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
if (rec == page_get_supremum_rec(page)) {
err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec,
check_index, offsets, thr);
......@@ -1529,12 +1531,7 @@ row_ins_dupl_error_with_rec(
}
}
if (!rec_get_deleted_flag(rec, index->table->comp)) {
return(TRUE);
}
return(FALSE);
return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
}
/*******************************************************************
......@@ -1629,7 +1626,7 @@ row_ins_scan_sec_index_for_duplicate(
break;
}
if (rec == page_get_supremum_rec(buf_frame_align(rec))) {
if (page_rec_is_supremum(rec)) {
goto next_rec;
}
......@@ -1697,7 +1694,6 @@ row_ins_duplicate_error_in_clust(
#ifndef UNIV_HOTBACKUP
ulint err;
rec_t* rec;
page_t* page;
ulint n_unique;
trx_t* trx = thr_get_trx(thr);
mem_heap_t*heap = NULL;
......@@ -1728,9 +1724,8 @@ row_ins_duplicate_error_in_clust(
if (cursor->low_match >= n_unique) {
rec = btr_cur_get_rec(cursor);
page = buf_frame_align(rec);
if (rec != page_get_infimum_rec(page)) {
if (!page_rec_is_infimum(rec)) {
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
......@@ -1772,9 +1767,8 @@ row_ins_duplicate_error_in_clust(
if (cursor->up_match >= n_unique) {
rec = page_rec_get_next(btr_cur_get_rec(cursor));
page = buf_frame_align(rec);
if (rec != page_get_supremum_rec(page)) {
if (!page_rec_is_supremum(rec)) {
offsets = rec_get_offsets(rec, cursor->index, offsets,
ULINT_UNDEFINED, &heap);
......@@ -1842,7 +1836,6 @@ row_ins_must_modify(
{
ulint enough_match;
rec_t* rec;
page_t* page;
/* NOTE: (compare to the note in row_ins_duplicate_error) Because node
pointers on upper levels of the B-tree may match more to entry than
......@@ -1856,9 +1849,8 @@ row_ins_must_modify(
if (cursor->low_match >= enough_match) {
rec = btr_cur_get_rec(cursor);
page = buf_frame_align(rec);
if (rec != page_get_infimum_rec(page)) {
if (!page_rec_is_infimum(rec)) {
return(ROW_INS_PREV);
}
......@@ -1897,7 +1889,6 @@ row_ins_index_entry_low(
ulint modify = 0; /* remove warning */
rec_t* insert_rec;
rec_t* rec;
rec_t* first_rec;
ulint err;
ulint n_unique;
big_rec_t* big_rec = NULL;
......@@ -1932,15 +1923,20 @@ row_ins_index_entry_low(
err = DB_SUCCESS;
goto function_exit;
}
first_rec = page_rec_get_next(page_get_infimum_rec(
buf_frame_align(btr_cur_get_rec(&cursor))));
}
if (!page_rec_is_supremum(first_rec)) {
ut_a(rec_get_n_fields(first_rec, index)
#ifdef UNIV_DEBUG
{
page_t* page = btr_cur_get_page(&cursor);
rec_t* first_rec = page_rec_get_next(
page_get_infimum_rec(page));
if (UNIV_LIKELY(first_rec != page_get_supremum_rec(page))) {
ut_a(rec_get_n_fields(first_rec, index)
== dtuple_get_n_fields(entry));
}
}
#endif
n_unique = dict_index_get_n_unique(index);
......
......@@ -265,7 +265,7 @@ row_mysql_store_col_in_innobase_format(
necessarily the length of the actual
payload data; if the column is a true
VARCHAR then this is irrelevant */
ibool comp) /* in: TRUE = compact format */
ulint comp) /* in: nonzero=compact format */
{
byte* ptr = mysql_data;
dtype_t* dtype;
......
......@@ -616,7 +616,6 @@ row_search_on_row_ref(
ulint low_match;
rec_t* rec;
dict_index_t* index;
page_t* page;
ut_ad(dtuple_check_typed(ref));
......@@ -629,9 +628,8 @@ row_search_on_row_ref(
low_match = btr_pcur_get_low_match(pcur);
rec = btr_pcur_get_rec(pcur);
page = buf_frame_align(rec);
if (rec == page_get_infimum_rec(page)) {
if (page_rec_is_infimum(rec)) {
return(FALSE);
}
......@@ -702,7 +700,6 @@ row_search_index_entry(
{
ulint n_fields;
ulint low_match;
page_t* page;
rec_t* rec;
ut_ad(dtuple_check_typed(entry));
......@@ -711,11 +708,10 @@ row_search_index_entry(
low_match = btr_pcur_get_low_match(pcur);
rec = btr_pcur_get_rec(pcur);
page = buf_frame_align(rec);
n_fields = dtuple_get_n_fields(entry);
if (rec == page_get_infimum_rec(page)) {
if (page_rec_is_infimum(rec)) {
return(FALSE);
}
......
This diff is collapsed.
......@@ -61,7 +61,7 @@ row_vers_impl_x_locked_off_kernel(
ibool rec_del;
ulint err;
mtr_t mtr;
ibool comp;
ulint comp;
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
......@@ -121,10 +121,10 @@ row_vers_impl_x_locked_off_kernel(
goto exit_func;
}
comp = index->table->comp;
comp = page_rec_is_comp(rec);
ut_ad(index->table == clust_index->table);
ut_ad(comp == page_is_comp(buf_frame_align(rec)));
ut_ad(comp == page_is_comp(buf_frame_align(clust_rec)));
ut_ad(!!comp == index->table->comp);
ut_ad(!comp == !page_rec_is_comp(clust_rec));
/* We look up if some earlier version, which was modified by the trx_id
transaction, of the clustered index record would require rec to be in
......@@ -310,7 +310,7 @@ row_vers_old_has_index_entry(
dtuple_t* row;
dtuple_t* entry;
ulint err;
ibool comp;
ulint comp;
ut_ad(mtr_memo_contains(mtr, buf_block_align(rec), MTR_MEMO_PAGE_X_FIX)
|| mtr_memo_contains(mtr, buf_block_align(rec),
......@@ -322,8 +322,8 @@ row_vers_old_has_index_entry(
clust_index = dict_table_get_first_index(index->table);
comp = index->table->comp;
ut_ad(comp == page_is_comp(buf_frame_align(rec)));
comp = page_rec_is_comp(rec);
ut_ad(!index->table->comp == !comp);
heap = mem_heap_create(1024);
clust_offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &heap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment