|
|
/*****************************************************************************
Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the Free SoftwareFoundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUTANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESSFOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along withthis program; if not, write to the Free Software Foundation, Inc.,51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
/******************************************************************//**@file include/mach0data.icUtilities for converting data from the database fileto the machine format.
Created 11/28/1995 Heikki Tuuri***********************************************************************/
#ifndef UNIV_INNOCHECKSUM
#include "ut0mem.h"
/*******************************************************//**The following function is used to store data in one byte. */UNIV_INLINEvoidmach_write_to_1(/*============*/ byte* b, /*!< in: pointer to byte where to store */ ulint n) /*!< in: ulint integer to be stored, >= 0, < 256 */{ ut_ad(b); ut_ad((n | 0xFFUL) <= 0xFFUL);
b[0] = (byte) n;}
/********************************************************//**The following function is used to fetch data from one byte.@return ulint integer, >= 0, < 256 */UNIV_INLINEulintmach_read_from_1(/*=============*/ const byte* b) /*!< in: pointer to byte */{ ut_ad(b); return((ulint)(b[0]));}
/*******************************************************//**The following function is used to store data in two consecutivebytes. We store the most significant byte to the lowest address. */UNIV_INLINEvoidmach_write_to_2(/*============*/ byte* b, /*!< in: pointer to two bytes where to store */ ulint n) /*!< in: ulint integer to be stored */{ ut_ad(b); ut_ad((n | 0xFFFFUL) <= 0xFFFFUL);
b[0] = (byte)(n >> 8); b[1] = (byte)(n);}
/********************************************************//**The following function is used to convert a 16-bit data itemto the canonical format, for fast bytewise equality testagainst memory.@return 16-bit integer in canonical format */UNIV_INLINEuint16mach_encode_2(/*==========*/ 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 itemfrom the canonical format, for fast bytewise equality testagainst memory.@return integer in machine-dependent format */UNIV_INLINEulintmach_decode_2(/*==========*/ uint16 n) /*!< in: 16-bit integer in canonical format */{ ut_ad(2 == sizeof n); return(mach_read_from_2((const byte*) &n));}
/*******************************************************//**The following function is used to store data in 3 consecutivebytes. We store the most significant byte to the lowest address. */UNIV_INLINEvoidmach_write_to_3(/*============*/ byte* b, /*!< in: pointer to 3 bytes where to store */ ulint n) /*!< in: ulint integer to be stored */{ ut_ad(b); ut_ad((n | 0xFFFFFFUL) <= 0xFFFFFFUL);
b[0] = (byte)(n >> 16); b[1] = (byte)(n >> 8); b[2] = (byte)(n);}
/********************************************************//**The following function is used to fetch data from 3 consecutivebytes. The most significant byte is at the lowest address.@return ulint integer */UNIV_INLINEulintmach_read_from_3(/*=============*/ const byte* b) /*!< in: pointer to 3 bytes */{ ut_ad(b); return( ((ulint)(b[0]) << 16) | ((ulint)(b[1]) << 8) | (ulint)(b[2]) );}
/*******************************************************//**The following function is used to store data in four consecutivebytes. We store the most significant byte to the lowest address. */UNIV_INLINEvoidmach_write_to_4(/*============*/ byte* b, /*!< in: pointer to four bytes where to store */ ulint n) /*!< in: ulint integer to be stored */{ ut_ad(b);
b[0] = (byte)(n >> 24); b[1] = (byte)(n >> 16); b[2] = (byte)(n >> 8); b[3] = (byte) n;}
#endif /* !UNIV_INNOCHECKSUM */
/********************************************************//**The following function is used to fetch data from 2 consecutivebytes. The most significant byte is at the lowest address.@return ulint integer */UNIV_INLINEulintmach_read_from_2(/*=============*/ const byte* b) /*!< in: pointer to 2 bytes */{ return(((ulint)(b[0]) << 8) | (ulint)(b[1]));}
/********************************************************//**The following function is used to fetch data from 4 consecutivebytes. The most significant byte is at the lowest address.@return ulint integer */UNIV_INLINEulintmach_read_from_4(/*=============*/ const byte* b) /*!< in: pointer to four bytes */{ ut_ad(b); return( ((ulint)(b[0]) << 24) | ((ulint)(b[1]) << 16) | ((ulint)(b[2]) << 8) | (ulint)(b[3]) );}
#ifndef UNIV_INNOCHECKSUM
/*********************************************************//**Writes a ulint in a compressed form where the first byte codes thelength of the stored ulint. We look at the most significant bits ofthe byte. If the most significant bit is zero, it means 1-byte storage,else if the 2nd bit is 0, it means 2-byte storage, else if 3rd is 0,it means 3-byte storage, else if 4th is 0, it means 4-byte storage,else the storage is 5-byte.@return compressed size in bytes */UNIV_INLINEulintmach_write_compressed(/*==================*/ byte* b, /*!< in: pointer to memory where to store */ ulint n) /*!< in: ulint integer (< 2^32) to be stored */{ ut_ad(b);
if (n < 0x80UL) { mach_write_to_1(b, n); return(1); } else if (n < 0x4000UL) { mach_write_to_2(b, n | 0x8000UL); return(2); } else if (n < 0x200000UL) { mach_write_to_3(b, n | 0xC00000UL); return(3); } else if (n < 0x10000000UL) { mach_write_to_4(b, n | 0xE0000000UL); return(4); } else { mach_write_to_1(b, 0xF0UL); mach_write_to_4(b + 1, n); return(5); }}
/*********************************************************//**Returns the size of a ulint when written in the compressed form.@return compressed size in bytes */UNIV_INLINEulintmach_get_compressed_size(/*=====================*/ ulint n) /*!< in: ulint integer (< 2^32) to be stored */{ if (n < 0x80UL) { return(1); } else if (n < 0x4000UL) { return(2); } else if (n < 0x200000UL) { return(3); } else if (n < 0x10000000UL) { return(4); } else { return(5); }}
/*********************************************************//**Reads a ulint in a compressed form.@return read integer (< 2^32) */UNIV_INLINEulintmach_read_compressed(/*=================*/ const byte* b) /*!< in: pointer to memory from where to read */{ ulint flag;
ut_ad(b);
flag = mach_read_from_1(b);
if (flag < 0x80UL) { return(flag); } else if (flag < 0xC0UL) { return(mach_read_from_2(b) & 0x7FFFUL); } else if (flag < 0xE0UL) { return(mach_read_from_3(b) & 0x3FFFFFUL); } else if (flag < 0xF0UL) { return(mach_read_from_4(b) & 0x1FFFFFFFUL); } else { ut_ad(flag == 0xF0UL); return(mach_read_from_4(b + 1)); }}
/*******************************************************//**The following function is used to store data in 8 consecutivebytes. We store the most significant byte to the lowest address. */UNIV_INLINEvoidmach_write_to_8(/*============*/ void* b, /*!< in: pointer to 8 bytes where to store */ ib_uint64_t n) /*!< in: 64-bit integer to be stored */{ ut_ad(b);
mach_write_to_4(static_cast<byte*>(b), (ulint) (n >> 32)); mach_write_to_4(static_cast<byte*>(b) + 4, (ulint) n);}
/********************************************************//**The following function is used to fetch data from 8 consecutivebytes. The most significant byte is at the lowest address.@return 64-bit integer */UNIV_INLINEib_uint64_tmach_read_from_8(/*=============*/ const byte* b) /*!< in: pointer to 8 bytes */{ ib_uint64_t ull;
ull = ((ib_uint64_t) mach_read_from_4(b)) << 32; ull |= (ib_uint64_t) mach_read_from_4(b + 4);
return(ull);}
/*******************************************************//**The following function is used to store data in 7 consecutivebytes. We store the most significant byte to the lowest address. */UNIV_INLINEvoidmach_write_to_7(/*============*/ byte* b, /*!< in: pointer to 7 bytes where to store */ ib_uint64_t n) /*!< in: 56-bit integer */{ ut_ad(b);
mach_write_to_3(b, (ulint) (n >> 32)); mach_write_to_4(b + 3, (ulint) n);}
/********************************************************//**The following function is used to fetch data from 7 consecutivebytes. The most significant byte is at the lowest address.@return 56-bit integer */UNIV_INLINEib_uint64_tmach_read_from_7(/*=============*/ const byte* b) /*!< in: pointer to 7 bytes */{ ut_ad(b);
return(ut_ull_create(mach_read_from_3(b), mach_read_from_4(b + 3)));}
/*******************************************************//**The following function is used to store data in 6 consecutivebytes. We store the most significant byte to the lowest address. */UNIV_INLINEvoidmach_write_to_6(/*============*/ byte* b, /*!< in: pointer to 6 bytes where to store */ ib_uint64_t n) /*!< in: 48-bit integer */{ ut_ad(b);
mach_write_to_2(b, (ulint) (n >> 32)); mach_write_to_4(b + 2, (ulint) n);}
/********************************************************//**The following function is used to fetch data from 6 consecutivebytes. The most significant byte is at the lowest address.@return 48-bit integer */UNIV_INLINEib_uint64_tmach_read_from_6(/*=============*/ const byte* b) /*!< in: pointer to 6 bytes */{ ut_ad(b);
return(ut_ull_create(mach_read_from_2(b), mach_read_from_4(b + 2)));}
/*********************************************************//**Writes a 64-bit integer in a compressed form (5..9 bytes).@return size in bytes */UNIV_INLINEulintmach_ull_write_compressed(/*======================*/ byte* b, /*!< in: pointer to memory where to store */ ib_uint64_t n) /*!< in: 64-bit integer to be stored */{ ulint size;
ut_ad(b);
size = mach_write_compressed(b, (ulint) (n >> 32)); mach_write_to_4(b + size, (ulint) n);
return(size + 4);}
/*********************************************************//**Returns the size of a 64-bit integer when written in the compressed form.@return compressed size in bytes */UNIV_INLINEulintmach_ull_get_compressed_size(/*=========================*/ ib_uint64_t n) /*!< in: 64-bit integer to be stored */{ return(4 + mach_get_compressed_size((ulint) (n >> 32)));}
/*********************************************************//**Reads a 64-bit integer in a compressed form.@return the value read */UNIV_INLINEib_uint64_tmach_ull_read_compressed(/*=====================*/ const byte* b) /*!< in: pointer to memory from where to read */{ ib_uint64_t n; ulint size;
ut_ad(b);
n = (ib_uint64_t) mach_read_compressed(b);
size = mach_get_compressed_size((ulint) n);
n <<= 32; n |= (ib_uint64_t) mach_read_from_4(b + size);
return(n);}
/*********************************************************//**Writes a 64-bit integer in a compressed form (1..11 bytes).@return size in bytes */UNIV_INLINEulintmach_ull_write_much_compressed(/*===========================*/ byte* b, /*!< in: pointer to memory where to store */ ib_uint64_t n) /*!< in: 64-bit integer to be stored */{ ulint size;
ut_ad(b);
if (!(n >> 32)) { return(mach_write_compressed(b, (ulint) n)); }
*b = (byte)0xFF; size = 1 + mach_write_compressed(b + 1, (ulint) (n >> 32));
size += mach_write_compressed(b + size, (ulint) n & 0xFFFFFFFF);
return(size);}
/*********************************************************//**Returns the size of a 64-bit integer when written in the compressed form.@return compressed size in bytes */UNIV_INLINEulintmach_ull_get_much_compressed_size(/*==============================*/ ib_uint64_t n) /*!< in: 64-bit integer to be stored */{ if (!(n >> 32)) { return(mach_get_compressed_size((ulint) n)); }
return(1 + mach_get_compressed_size((ulint) (n >> 32)) + mach_get_compressed_size((ulint) n & ULINT32_MASK));}
/*********************************************************//**Reads a 64-bit integer in a compressed form.@return the value read */UNIV_INLINEib_uint64_tmach_ull_read_much_compressed(/*==========================*/ const byte* b) /*!< in: pointer to memory from where to read */{ ib_uint64_t n; ulint size;
ut_ad(b);
if (*b != (byte)0xFF) { n = 0; size = 0; } else { n = (ib_uint64_t) mach_read_compressed(b + 1);
size = 1 + mach_get_compressed_size((ulint) n); n <<= 32; }
n |= mach_read_compressed(b + size);
return(n);}
/*********************************************************//**Reads a 64-bit integer in a compressed formif the log record fully contains it.@return pointer to end of the stored field, NULL if not complete */UNIV_INLINEbyte*mach_ull_parse_compressed(/*======================*/ byte* ptr, /* in: pointer to buffer from where to read */ byte* end_ptr,/* in: pointer to end of the buffer */ ib_uint64_t* val) /* out: read value */{ ulint size;
ut_ad(ptr); ut_ad(end_ptr); ut_ad(val);
if (end_ptr < ptr + 5) {
return(NULL); }
*val = mach_read_compressed(ptr);
size = mach_get_compressed_size((ulint) *val);
ptr += size;
if (end_ptr < ptr + 4) {
return(NULL); }
*val <<= 32; *val |= mach_read_from_4(ptr);
return(ptr + 4);}#ifndef UNIV_HOTBACKUP/*********************************************************//**Reads a double. It is stored in a little-endian format.@return double read */UNIV_INLINEdoublemach_double_read(/*=============*/ const byte* b) /*!< in: pointer to memory from where to read */{ double d; ulint i; byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(double); i++) {#ifdef WORDS_BIGENDIAN ptr[sizeof(double) - i - 1] = b[i];#else ptr[i] = b[i];#endif }
return(d);}
/*********************************************************//**Writes a double. It is stored in a little-endian format. */UNIV_INLINEvoidmach_double_write(/*==============*/ byte* b, /*!< in: pointer to memory where to write */ double d) /*!< in: double */{ ulint i; byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(double); i++) {#ifdef WORDS_BIGENDIAN b[i] = ptr[sizeof(double) - i - 1];#else b[i] = ptr[i];#endif }}
/*********************************************************//**Reads a float. It is stored in a little-endian format.@return float read */UNIV_INLINEfloatmach_float_read(/*============*/ const byte* b) /*!< in: pointer to memory from where to read */{ float d; ulint i; byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(float); i++) {#ifdef WORDS_BIGENDIAN ptr[sizeof(float) - i - 1] = b[i];#else ptr[i] = b[i];#endif }
return(d);}
/*********************************************************//**Writes a float. It is stored in a little-endian format. */UNIV_INLINEvoidmach_float_write(/*=============*/ byte* b, /*!< in: pointer to memory where to write */ float d) /*!< in: float */{ ulint i; byte* ptr;
ptr = (byte*) &d;
for (i = 0; i < sizeof(float); i++) {#ifdef WORDS_BIGENDIAN b[i] = ptr[sizeof(float) - i - 1];#else b[i] = ptr[i];#endif }}
/*********************************************************//**Reads a ulint stored in the little-endian format.@return unsigned long int */UNIV_INLINEulintmach_read_from_n_little_endian(/*===========================*/ const byte* buf, /*!< in: from where to read */ ulint buf_size) /*!< in: from how many bytes to read */{ ulint n = 0; const byte* ptr;
ut_ad(buf_size > 0);
ptr = buf + buf_size;
for (;;) { ptr--;
n = n << 8;
n += (ulint)(*ptr);
if (ptr == buf) { break; } }
return(n);}
/*********************************************************//**Writes a ulint in the little-endian format. */UNIV_INLINEvoidmach_write_to_n_little_endian(/*==========================*/ byte* dest, /*!< in: where to write */ ulint dest_size, /*!< in: into how many bytes to write */ ulint n) /*!< in: unsigned long int to write */{ byte* end;
ut_ad(dest_size <= sizeof(ulint)); ut_ad(dest_size > 0);
end = dest + dest_size;
for (;;) { *dest = (byte)(n & 0xFF);
n = n >> 8;
dest++;
if (dest == end) { break; } }
ut_ad(n == 0);}
/*********************************************************//**Reads a ulint stored in the little-endian format.@return unsigned long int */UNIV_INLINEulintmach_read_from_2_little_endian(/*===========================*/ const byte* buf) /*!< in: from where to read */{ return((ulint)(buf[0]) | ((ulint)(buf[1]) << 8));}
/*********************************************************//**Writes a ulint in the little-endian format. */UNIV_INLINEvoidmach_write_to_2_little_endian(/*==========================*/ byte* dest, /*!< in: where to write */ ulint n) /*!< in: unsigned long int to write */{ ut_ad(n < 256 * 256);
*dest = (byte)(n & 0xFFUL);
n = n >> 8; dest++;
*dest = (byte)(n & 0xFFUL);}
/*********************************************************//**Convert integral type from storage byte order (big endian) tohost byte order.@return integer value */UNIV_INLINEib_uint64_tmach_read_int_type(/*===============*/ const byte* src, /*!< in: where to read from */ ulint len, /*!< in: length of src */ ibool unsigned_type) /*!< in: signed or unsigned flag */{ /* XXX this can be optimized on big-endian machines */
ullint ret; uint i;
if (unsigned_type || (src[0] & 0x80)) {
ret = 0x0000000000000000ULL; } else {
ret = 0xFFFFFFFFFFFFFF00ULL; }
if (unsigned_type) {
ret |= src[0]; } else {
ret |= src[0] ^ 0x80; }
for (i = 1; i < len; i++) { ret <<= 8; ret |= src[i]; }
return(ret);}/*********************************************************//**Swap byte ordering. */UNIV_INLINEvoidmach_swap_byte_order(/*=================*/ byte* dest, /*!< out: where to write */ const byte* from, /*!< in: where to read from */ ulint len) /*!< in: length of src */{ ut_ad(len > 0); ut_ad(len <= 8);
dest += len;
switch (len & 0x7) { case 0: *--dest = *from++; case 7: *--dest = *from++; case 6: *--dest = *from++; case 5: *--dest = *from++; case 4: *--dest = *from++; case 3: *--dest = *from++; case 2: *--dest = *from++; case 1: *--dest = *from; }}
/*************************************************************Convert integral type from host byte order (big-endian) storagebyte order. */UNIV_INLINEvoidmach_write_int_type(/*================*/ byte* dest, /*!< in: where to write */ const byte* src, /*!< in: where to read from */ ulint len, /*!< in: length of src */ bool usign) /*!< in: signed or unsigned flag */{#ifdef WORDS_BIGENDIAN memcpy(dest, src, len);#else mach_swap_byte_order(dest, src, len);#endif /* WORDS_BIGENDIAN */
if (!usign) { *dest ^= 0x80; }}
/*************************************************************Convert a ulonglong integer from host byte order to (big-endian)storage byte order. */UNIV_INLINEvoidmach_write_ulonglong(/*=================*/ byte* dest, /*!< in: where to write */ ulonglong src, /*!< in: where to read from */ ulint len, /*!< in: length of dest */ bool usign) /*!< in: signed or unsigned flag */{ byte* ptr = reinterpret_cast<byte*>(&src);
ut_ad(len <= sizeof(ulonglong));
#ifdef WORDS_BIGENDIAN memcpy(dest, ptr + (sizeof(src) - len), len);#else mach_swap_byte_order(dest, reinterpret_cast<byte*>(ptr), len);#endif /* WORDS_BIGENDIAN */
if (!usign) { *dest ^= 0x80; }}
/********************************************************//**Reads 1 - 4 bytes from a file page buffered in the buffer pool.@return value read */UNIV_INLINEulintmach_read_ulint(/*============*/ const byte* ptr, /*!< in: pointer from where to read */ ulint type) /*!< in: 1,2 or 4 bytes */{ switch (type) { case 1: return(mach_read_from_1(ptr)); case 2: return(mach_read_from_2(ptr)); case 4: return(mach_read_from_4(ptr)); default: ut_error; }
return(0);}
#endif /* !UNIV_HOTBACKUP */#endif /* !UNIV_INNOCHECKSUM */
|