Commit 1c8f5500 authored by unknown's avatar unknown
Browse files

InnoDB: Optimize rec_get_offsets(), rec_copy_prefix_to_buf() and

other rec_ functions based on OProfile measurements on GNU/Linux x86.


innobase/include/rem0rec.h:
  Replace FALSE/TRUE ibool comp with zero/nonzero ulint comp.
  Remove rec_set_node_ptr_flag().
innobase/include/rem0rec.ic:
  Replace FALSE/TRUE ibool comp with zero/nonzero ulint comp.
  Remove rec_set_node_ptr_flag().
  Add UNIV_LIKELY and UNIV_UNLIKELY hints.
  Correct a spelling error in comment.
  Simplify rec_get_deleted_flag().
innobase/rem/rem0rec.c:
  Add UNIV_LIKELY and UNIV_UNLIKELY hints.
  rec_init_offsets(), rec_get_offsets_func(): Optimize for x86.
  rec_set_field_extern_bits(): Move "comp" flag outside the loop.
  rec_copy_prefix_to_buf(): Add UNIV_PREFETCH hints.
parent 33d5b13b
Loading
Loading
Loading
Loading
+13 −21
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ rec_get_next_offs(
			/* out: the page offset of the next 
			chained record */
	rec_t*	rec,	/* in: physical record */
	ibool	comp);	/* in: TRUE=compact page format */
	ulint	comp);	/* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the next record offset field
of the record. */
@@ -60,7 +60,7 @@ void
rec_set_next_offs(
/*==============*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	next);	/* in: offset of the next record */
/**********************************************************
The following function is used to get the number of fields
@@ -90,7 +90,7 @@ rec_get_n_owned(
/*============*/
			/* out: number of owned records */
	rec_t*	rec,	/* in: physical record */
	ibool	comp);	/* in: TRUE=compact page format */
	ulint	comp);	/* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the number of owned
records. */
@@ -99,7 +99,7 @@ void
rec_set_n_owned(
/*============*/
	rec_t*	rec,		/* in: physical record */
	ibool	comp,		/* in: TRUE=compact page format */
	ulint	comp,		/* in: nonzero=compact page format */
	ulint	n_owned);	/* in: the number of owned */
/**********************************************************
The following function is used to retrieve the info bits of
@@ -110,7 +110,7 @@ rec_get_info_bits(
/*==============*/
			/* out: info bits */
	rec_t*	rec,	/* in: physical record */
	ibool	comp);	/* in: TRUE=compact page format */
	ulint	comp);	/* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the info bits of a record. */
UNIV_INLINE
@@ -118,7 +118,7 @@ void
rec_set_info_bits(
/*==============*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	bits);	/* in: info bits */
/**********************************************************
The following function retrieves the status bits of a new-style record. */
@@ -147,7 +147,7 @@ rec_get_info_and_status_bits(
/*=========================*/
			/* out: info bits */
	rec_t*	rec,	/* in: physical record */
	ibool	comp);	/* in: TRUE=compact page format */
	ulint	comp);	/* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the info and status
bits of a record.  (Only compact records have status bits.) */
@@ -156,7 +156,7 @@ void
rec_set_info_and_status_bits(
/*=========================*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	bits);	/* in: info bits */

/**********************************************************
@@ -167,7 +167,7 @@ rec_get_deleted_flag(
/*=================*/
			/* out: TRUE if delete marked */
	rec_t*	rec,	/* in: physical record */
	ibool	comp);	/* in: TRUE=compact page format */
	ulint	comp);	/* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the deleted bit. */
UNIV_INLINE
@@ -175,7 +175,7 @@ void
rec_set_deleted_flag(
/*=================*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ibool	flag);	/* in: TRUE if delete marked */
/**********************************************************
The following function tells if a new-style record is a node pointer. */
@@ -186,14 +186,6 @@ rec_get_node_ptr_flag(
			/* out: TRUE if node pointer */
	rec_t*	rec);	/* in: physical record */
/**********************************************************
The following function is used to flag a record as a node pointer. */
UNIV_INLINE
void
rec_set_node_ptr_flag(
/*=================*/
	rec_t*	rec,	/* in: physical record */
	ibool	flag);	/* in: TRUE if the record is a node pointer */
/**********************************************************
The following function is used to get the order number
of the record in the heap of the index page. */
UNIV_INLINE
@@ -202,7 +194,7 @@ rec_get_heap_no(
/*=============*/
			/* out: heap order number */
	rec_t*	rec,	/* in: physical record */
	ibool	comp);	/* in: TRUE=compact page format */
	ulint	comp);	/* in: nonzero=compact page format */
/**********************************************************
The following function is used to set the heap number
field in the record. */
@@ -211,7 +203,7 @@ void
rec_set_heap_no(
/*=============*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	heap_no);/* in: the heap number */
/**********************************************************
The following function is used to test whether the data offsets
@@ -305,7 +297,7 @@ 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 */
+30 −50
Original line number Diff line number Diff line
@@ -265,7 +265,7 @@ rec_get_next_offs(
			/* out: the page offset of the next chained record, or
			0 if none */
	rec_t*	rec,	/* in: physical record */
	ibool	comp)	/* in: TRUE=compact page format */
	ulint	comp)	/* in: nonzero=compact page format */
{	
	ulint	field_value;
		
@@ -312,7 +312,7 @@ void
rec_set_next_offs(
/*==============*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	next)	/* in: offset of the next record, or 0 if none */
{
	ut_ad(rec);
@@ -414,7 +414,7 @@ rec_get_n_fields(
{
	ut_ad(rec);
	ut_ad(index);
	if (!index->table->comp) {
	if (UNIV_UNLIKELY(!index->table->comp)) {
		return(rec_get_n_fields_old(rec));
	}
	switch (rec_get_status(rec)) {
@@ -440,7 +440,7 @@ rec_get_n_owned(
/*============*/
			/* out: number of owned records */
	rec_t*	rec,	/* in: physical record */
	ibool	comp)	/* in: TRUE=compact page format */
	ulint	comp)	/* in: nonzero=compact page format */
{
	ulint	ret;

@@ -461,7 +461,7 @@ void
rec_set_n_owned(
/*============*/
	rec_t*	rec,		/* in: physical record */
	ibool	comp,		/* in: TRUE=compact page format */
	ulint	comp,		/* in: nonzero=compact page format */
	ulint	n_owned)	/* in: the number of owned */
{
	ut_ad(rec);
@@ -480,7 +480,7 @@ rec_get_info_bits(
/*==============*/
			/* out: info bits */
	rec_t*	rec,	/* in: physical record */
	ibool	comp)	/* in: TRUE=compact page format */
	ulint	comp)	/* in: nonzero=compact page format */
{
	ulint	ret;

@@ -501,7 +501,7 @@ void
rec_set_info_bits(
/*==============*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	bits)	/* in: info bits */
{
	ut_ad(rec);
@@ -537,14 +537,14 @@ rec_get_info_and_status_bits(
/*=========================*/
			/* out: info bits */
	rec_t*	rec,	/* in: physical record */
	ibool	comp)	/* in: TRUE=compact page format */
	ulint	comp)	/* in: nonzero=compact page format */
{
	ulint	bits;
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
& (REC_INFO_BITS_MASK >> REC_INFO_BITS_SHIFT)
# error "REC_NEW_STATUS_MASK and REC_INFO_BITS_MASK overlap"
#endif
	if (comp) {
	if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
		bits = rec_get_info_bits(rec, TRUE) | rec_get_status(rec);
	} else {
		bits = rec_get_info_bits(rec, FALSE);
@@ -560,7 +560,7 @@ void
rec_set_info_and_status_bits(
/*=========================*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	bits)	/* in: info bits */
{
#if (REC_NEW_STATUS_MASK >> REC_NEW_STATUS_SHIFT) \
@@ -583,14 +583,15 @@ rec_get_deleted_flag(
/*=================*/
			/* out: TRUE if delete marked */
	rec_t*	rec,	/* in: physical record */
	ibool	comp)	/* in: TRUE=compact page format */
	ulint	comp)	/* in: nonzero=compact page format */
{
	if (REC_INFO_DELETED_FLAG & rec_get_info_bits(rec, comp)) {

		return(TRUE);
	if (UNIV_EXPECT(comp, REC_OFFS_COMPACT)) {
		return(0 != rec_get_bit_field_1(rec, REC_NEW_INFO_BITS,
				REC_INFO_DELETED_FLAG, REC_INFO_BITS_SHIFT));
	} else {
		return(0 != rec_get_bit_field_1(rec, REC_OLD_INFO_BITS,
				REC_INFO_DELETED_FLAG, REC_INFO_BITS_SHIFT));
	}

	return(FALSE);
}

/**********************************************************
@@ -600,24 +601,23 @@ void
rec_set_deleted_flag(
/*=================*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ibool	flag)	/* in: TRUE if delete marked */
{
	ulint	old_val;
	ulint	new_val;
	ulint	val;

	ut_ad(TRUE == 1);
	ut_ad(flag <= TRUE);

	old_val = rec_get_info_bits(rec, comp);
	val = rec_get_info_bits(rec, comp);
	
	if (flag) {
		new_val = REC_INFO_DELETED_FLAG | old_val;
		val |= REC_INFO_DELETED_FLAG;
	} else {
		new_val = ~REC_INFO_DELETED_FLAG & old_val;
		val &= ~REC_INFO_DELETED_FLAG;
	}

	rec_set_info_bits(rec, comp, new_val);
	rec_set_info_bits(rec, comp, val);
}

/**********************************************************
@@ -632,26 +632,6 @@ rec_get_node_ptr_flag(
	return(REC_STATUS_NODE_PTR == rec_get_status(rec));
}

/**********************************************************
The following function is used to flag a record as a node pointer. */
UNIV_INLINE
void
rec_set_node_ptr_flag(
/*=================*/
	rec_t*	rec,	/* in: physical record */
	ibool	flag)	/* in: TRUE if the record is a node pointer */
{
	ulint	status;
	ut_ad(flag <= TRUE);
	ut_ad(REC_STATUS_NODE_PTR >= rec_get_status(rec));
	if (flag) {
		status = REC_STATUS_NODE_PTR;
	} else {
		status = REC_STATUS_ORDINARY;
	}
	rec_set_status(rec, status);
}

/**********************************************************
The following function is used to get the order number of the record in the
heap of the index page. */
@@ -661,7 +641,7 @@ rec_get_heap_no(
/*=============*/
			/* out: heap order number */
	rec_t*	rec,	/* in: physical record */
	ibool	comp)	/* in: TRUE=compact page format */
	ulint	comp)	/* in: nonzero=compact page format */
{
	ulint	ret;

@@ -682,7 +662,7 @@ void
rec_set_heap_no(
/*=============*/
	rec_t*	rec,	/* in: physical record */
	ibool	comp,	/* in: TRUE=compact page format */
	ulint	comp,	/* in: nonzero=compact page format */
	ulint	heap_no)/* in: the heap number */
{
	ut_ad(heap_no <= REC_MAX_HEAP_NO);
@@ -843,7 +823,7 @@ rec_offs_validate(
{
	ulint	i	= rec_offs_n_fields(offsets);
	ulint	last	= ULINT_MAX;
	ibool	comp	= (*rec_offs_base(offsets) & REC_OFFS_COMPACT) != 0;
	ulint	comp	= *rec_offs_base(offsets) & REC_OFFS_COMPACT;

	if (rec) {
		ut_ad((ulint) rec == offsets[2]);
@@ -926,7 +906,7 @@ rec_get_nth_field(
	ut_ad(n < rec_offs_n_fields(offsets));
	ut_ad(len);

	if (n == 0) {
	if (UNIV_UNLIKELY(n == 0)) {
		field = rec;
	} else {
		field = rec + (rec_offs_base(offsets)[n] & REC_OFFS_MASK);
@@ -1037,7 +1017,7 @@ rec_set_nth_field_extern_bit(
				where rec is, or NULL; in the NULL case
				we do not write to log about the change */
{
	if (index->table->comp) {
	if (UNIV_LIKELY(index->table->comp)) {
		rec_set_nth_field_extern_bit_new(rec, index, i, val, mtr);
	} else {
		rec_set_nth_field_extern_bit_old(rec, i, val, mtr);
@@ -1452,7 +1432,7 @@ rec_get_converted_size(
				? dict_index_get_n_unique_in_tree(index) + 1
				: dict_index_get_n_fields(index)));

	if (index->table->comp) {
	if (UNIV_LIKELY(index->table->comp)) {
		return(rec_get_converted_size_new(index, dtuple));
	}

+93 −53
Original line number Diff line number Diff line
@@ -159,22 +159,20 @@ rec_init_offsets(
	ulint*		offsets)/* in/out: array of offsets;
				in: n=rec_offs_n_fields(offsets) */
{
	ulint	n_fields = rec_offs_n_fields(offsets);
	ulint	i	= 0;
	ulint	offs;

	rec_offs_make_valid(rec, index, offsets);

	if (index->table->comp) {
	if (UNIV_LIKELY(index->table->comp)) {
		const byte*	nulls;
		const byte*	lens;
		dict_field_t*	field;
		dtype_t*	type;
		ulint		null_mask;
		ulint		status = rec_get_status(rec);
		ulint		n_node_ptr_field = ULINT_UNDEFINED;

		switch (status) {
		switch (UNIV_EXPECT(status, REC_STATUS_ORDINARY)) {
		case REC_STATUS_INFIMUM:
		case REC_STATUS_SUPREMUM:
			/* the field is 8 bytes long */
@@ -196,56 +194,74 @@ rec_init_offsets(
		null_mask = 1;

		/* read the lengths of fields 0..n */
		for (; i < n_fields; i++) {
			ibool	is_null = FALSE, is_external = FALSE;
		do {
			ulint	len;
			if (i == n_node_ptr_field) {
				len = 4;
			if (UNIV_UNLIKELY(i == n_node_ptr_field)) {
				len = offs += 4;
				goto resolved;
			}

			field = dict_index_get_nth_field(index, i);
			type = dict_col_get_type(dict_field_get_col(field));
			if (!(dtype_get_prtype(type) & DATA_NOT_NULL)) {
			if (!(dtype_get_prtype(dict_col_get_type(
						dict_field_get_col(field)))
						& DATA_NOT_NULL)) {
				/* nullable field => read the null flag */
				is_null = (*nulls & null_mask) != 0;
				null_mask <<= 1;
				if (null_mask == 0x100) {

				if (UNIV_UNLIKELY(!(byte) null_mask)) {
					nulls--;
					null_mask = 1;
				}

				if (*nulls & null_mask) {
					null_mask <<= 1;
					/* No length is stored for NULL fields.
					We do not advance offs, and we set
					the length to zero and enable the
					SQL NULL flag in offsets[]. */
					len = REC_OFFS_SQL_NULL;
					goto resolved;
				}
				null_mask <<= 1;

			if (is_null) {
				/* No length is stored for NULL fields. */
				len = 0;
			} else if (!field->fixed_len) {
				ut_ad(!field->fixed_len);
				goto variable_length;
			}

			if (UNIV_UNLIKELY(!field->fixed_len)) {
				dtype_t*	type;
			variable_length:
				/* Variable-length field: read the length */
				type = dict_col_get_type(
						dict_field_get_col(field));
				len = *lens--;
				if (dtype_get_len(type) > 255
				    || dtype_get_mtype(type) == DATA_BLOB) {
				if (UNIV_UNLIKELY(dtype_get_len(type) > 255)
				    || UNIV_UNLIKELY(dtype_get_mtype(type)
							== DATA_BLOB)) {
					if (len & 0x80) {
						/* 1exxxxxxx xxxxxxxx */
						is_external = !!(len & 0x40);
						len &= 0x3f;
						len <<= 8;
						len |= *lens--;

						offs += len & 0x3fff;
						if (UNIV_UNLIKELY(len
								& 0x4000)) {
							len = offs
							| REC_OFFS_EXTERNAL;
						} else {
							len = offs;
						}

						goto resolved;
					}
				}

				len = offs += len;
			} else {
				len = field->fixed_len;
				len = offs += field->fixed_len;
			}
		resolved:
			offs += len;
			len = offs;
			if (is_external) {
				len |= REC_OFFS_EXTERNAL;
			}
			if (is_null) {
				len |= REC_OFFS_SQL_NULL;
			}
			rec_offs_base(offsets)[i + 1] = len;
		}
		} while (++i < rec_offs_n_fields(offsets));

		*rec_offs_base(offsets) =
			(rec - (lens + 1)) | REC_OFFS_COMPACT;
@@ -253,22 +269,22 @@ rec_init_offsets(
		/* Old-style record: determine extra size and end offsets */
		offs = REC_N_OLD_EXTRA_BYTES;
		if (rec_get_1byte_offs_flag(rec)) {
			offs += n_fields;
			offs += rec_offs_n_fields(offsets);
			*rec_offs_base(offsets) = offs;
			/* Determine offsets to fields */
			for (; i < n_fields; i++) {
			do {
				offs = rec_1_get_field_end_info(rec, i);
				if (offs & REC_1BYTE_SQL_NULL_MASK) {
					offs &= ~REC_1BYTE_SQL_NULL_MASK;
					offs |= REC_OFFS_SQL_NULL;
				}
				rec_offs_base(offsets)[1 + i] = offs;
			}
			} while (++i < rec_offs_n_fields(offsets));
		} else {
			offs += 2 * n_fields;
			offs += 2 * rec_offs_n_fields(offsets);
			*rec_offs_base(offsets) = offs;
			/* Determine offsets to fields */
			for (; i < n_fields; i++) {
			do {
				offs = rec_2_get_field_end_info(rec, i);
				if (offs & REC_2BYTE_SQL_NULL_MASK) {
					offs &= ~REC_2BYTE_SQL_NULL_MASK;
@@ -279,7 +295,7 @@ rec_init_offsets(
					offs |= REC_OFFS_EXTERNAL;
				}
				rec_offs_base(offsets)[1 + i] = offs;
			}
			} while (++i < rec_offs_n_fields(offsets));
		}
	}
}
@@ -310,8 +326,9 @@ rec_get_offsets_func(
	ut_ad(index);
	ut_ad(heap);

	if (index->table->comp) {
		switch (rec_get_status(rec)) {
	if (UNIV_LIKELY(index->table->comp)) {
		switch (UNIV_EXPECT(rec_get_status(rec),
				REC_STATUS_ORDINARY)) {
		case REC_STATUS_ORDINARY:
			n = dict_index_get_n_fields(index);
			break;
@@ -331,13 +348,14 @@ rec_get_offsets_func(
		n = rec_get_n_fields_old(rec);
	}

	if (n_fields < n) {
	if (UNIV_UNLIKELY(n_fields < n)) {
		n = n_fields;
	}

	size = n + (1 + REC_OFFS_HEADER_SIZE);

	if (!offsets || rec_offs_get_n_alloc(offsets) < size) {
	if (UNIV_UNLIKELY(!offsets) ||
			UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
		if (!*heap) {
			*heap = mem_heap_create_func(size * sizeof(ulint),
				NULL, MEM_HEAP_DYNAMIC, file, line);
@@ -653,8 +671,16 @@ rec_set_field_extern_bits(
{
	ulint	i;

	if (UNIV_LIKELY(index->table->comp)) {
		for (i = 0; i < n_fields; i++) {
		rec_set_nth_field_extern_bit(rec, index, vec[i], TRUE, mtr);
			rec_set_nth_field_extern_bit_new(rec, index, vec[i],
								TRUE, mtr);
		}
	} else {
		for (i = 0; i < n_fields; i++) {
			rec_set_nth_field_extern_bit_old(rec, vec[i],
								TRUE, mtr);
		}
	}
}

@@ -949,7 +975,7 @@ rec_convert_dtuple_to_rec(
	ut_ad(dtuple_validate(dtuple));
	ut_ad(dtuple_check_typed(dtuple));

	if (index->table->comp) {
	if (UNIV_LIKELY(index->table->comp)) {
		rec = rec_convert_dtuple_to_rec_new(buf, index, dtuple);
	} else {
		rec = rec_convert_dtuple_to_rec_old(buf, dtuple);
@@ -1078,17 +1104,19 @@ rec_copy_prefix_to_buf(
					for the copied prefix, or NULL */
	ulint*		buf_size)	/* in/out: buffer size */
{
	byte*		nulls	= rec - (REC_N_NEW_EXTRA_BYTES + 1);
	byte*		lens	= nulls - (index->n_nullable + 7) / 8;
	byte*		nulls;
	byte*		lens;
	dict_field_t*	field;
	dtype_t*	type;
	ulint		i;
	ulint		prefix_len	= 0;
	ulint		prefix_len;
	ibool		is_null;
	ulint		null_mask	= 1;
	ulint		null_mask;
	ulint		status;

	if (!index->table->comp) {
	UNIV_PREFETCH_RW(*buf);

	if (UNIV_UNLIKELY(!index->table->comp)) {
		ut_ad(rec_validate_old(rec));
		return(rec_copy_prefix_to_buf_old(rec, n_fields,
			rec_get_field_start_offs(rec, n_fields),
@@ -1109,10 +1137,16 @@ rec_copy_prefix_to_buf(
	case REC_STATUS_SUPREMUM:
		/* infimum or supremum record: no sense to copy anything */
	default:
		ut_a(0);
		ut_error;
		return(NULL);
	}

	nulls = rec - (REC_N_NEW_EXTRA_BYTES + 1);
	lens = nulls - (index->n_nullable + 7) / 8;
	UNIV_PREFETCH_R(lens);
	prefix_len = 0;
	null_mask = 1;

	/* read the lengths of fields 0..n */
	for (i = 0; i < n_fields; i++) {
		field = dict_index_get_nth_field(index, i);
@@ -1122,8 +1156,11 @@ rec_copy_prefix_to_buf(
			/* nullable field => read the null flag */
			is_null = !!(*nulls & null_mask);
			null_mask <<= 1;
			if (null_mask == 0x100)
				nulls--, null_mask = 1;
			if (null_mask == 0x100) {
				--nulls;
				UNIV_PREFETCH_R(nulls);
				null_mask = 1;
			}
		}

		if (is_null) {
@@ -1138,12 +1175,15 @@ rec_copy_prefix_to_buf(
					len &= 0x3f;
					len <<= 8;
					len |= *lens--;
					UNIV_PREFETCH_R(lens);
				}
			}
			prefix_len += len;
		}
	}

	UNIV_PREFETCH_R(rec + prefix_len);

	prefix_len += rec - (lens + 1);

	if ((*buf == NULL) || (*buf_size < prefix_len)) {