Commit 48a1ffa5 authored by marko's avatar marko

branches/zip: Implement a more compact page format.

Add a hook to buf0flu.c for testing compression and decompression.
TODO: adapt page_zip_write() calls.
parent b0c0c2b3
......@@ -16,6 +16,9 @@ Created 11/11/1995 Heikki Tuuri
#include "ut0byte.h"
#include "ut0lst.h"
#include "page0page.h"
#if 1 /* testing */
# include "page0zip.h"
#endif
#include "fil0fil.h"
#include "buf0buf.h"
#include "buf0lru.h"
......@@ -451,6 +454,10 @@ buf_flush_init_for_writing(
ulint space, /* in: space id */
ulint page_no) /* in: page number */
{
#if 1 /* testing */
byte zip[16384];
page_zip_des_t page_zip = { zip, sizeof zip, 0, 0 };
#endif /* testing */
/* Write the newest modification lsn to the page header and trailer */
mach_write_to_8(page + FIL_PAGE_LSN, newest_lsn);
......@@ -475,6 +482,11 @@ buf_flush_init_for_writing(
mach_write_to_4(page + UNIV_PAGE_SIZE - FIL_PAGE_END_LSN_OLD_CHKSUM,
srv_use_checksums ?
buf_calc_page_old_checksum(page) : BUF_NO_CHECKSUM_MAGIC);
#if 1 /* testing */
if (page_is_comp(page)) {
ut_a(page_zip_compress(&page_zip, page));
}
#endif /* testing */
}
/************************************************************************
......
......@@ -280,14 +280,6 @@ page_rec_get_n_recs_before(
/* out: number of records */
rec_t* rec); /* in: the physical record */
/*****************************************************************
Gets the size of the page trailer. */
UNIV_INLINE
ulint
page_trailer_get_len(
/*=================*/
/* out: length of page trailer, in bytes */
const page_t* page); /* in: index page */
/*****************************************************************
Gets the number of records in the heap. */
UNIV_INLINE
ulint
......
......@@ -438,7 +438,7 @@ page_dir_set_n_slots(
/* Ensure that the modification log will not be overwritten. */
ulint n_slots_old = page_dir_get_n_slots(page);
if (n_slots > n_slots_old) {
ut_ad(page_zip_available(page_zip,
ut_ad(page_zip_available_noninline(page_zip,
(n_slots - n_slots_old)
* PAGE_DIR_SLOT_SIZE));
}
......@@ -447,19 +447,6 @@ page_dir_set_n_slots(
page_header_set_field(page, page_zip, PAGE_N_DIR_SLOTS, n_slots);
}
/*****************************************************************
Gets the size of the page trailer. */
UNIV_INLINE
ulint
page_trailer_get_len(
/*=================*/
/* out: length of page trailer, in bytes */
const page_t* page) /* in: index page */
{
return(PAGE_DIR + PAGE_DIR_SLOT_SIZE
* page_dir_get_n_slots((page_t*) page));
}
/*****************************************************************
Gets the number of records in the heap. */
UNIV_INLINE
......@@ -552,10 +539,11 @@ page_dir_slot_set_rec(
ut_ad(page_rec_check(rec));
mach_write_to_2(slot, ut_align_offset(rec, UNIV_PAGE_SIZE));
#if 0 /* TODO */
if (UNIV_LIKELY_NULL(page_zip)) {
page_zip_write_trailer(page_zip, slot, 2);
}
#endif
}
/*******************************************************************
......@@ -904,22 +892,20 @@ page_mem_free(
page_rec_set_next(rec, free, page_zip);
page_header_set_ptr(page, page_zip, PAGE_FREE, rec);
#if 0 /* It's better not to destroy the user's data. */
/* Clear the data bytes of the deleted record in order to improve
the compression ratio of the page and to make it easier to read
page dumps in corruption reports. The extra bytes of the record
cannot be cleared, because page_mem_alloc() needs them in order
to determine the size of the deleted record. */
memset(rec, 0, rec_offs_data_size(offsets));
if (1||/* TODO: remove testing */UNIV_LIKELY_NULL(page_zip)) {
ut_ad(rec_offs_comp(offsets));
/* If you enable this code, make sure that the callers of
page_mem_free() account for the increased usage of space. */
if (UNIV_LIKELY_NULL(page_zip)) {
page_zip_write(page_zip, page, rec, rec - page,
rec_offs_data_size(offsets));
/* The compression algorithm expects info_bits and n_owned
to be 0 for deleted records. */
rec[-REC_N_NEW_EXTRA_BYTES] = 0; /* info_bits and n_owned */
/* Clear the data bytes of the deleted record in order
to improve the compression ratio of the page. The extra
bytes of the record cannot be cleared, because
page_mem_alloc() needs them in order to determine the size
of the deleted record. */
memset(rec, 0, rec_offs_data_size(offsets));
}
#endif
garbage = page_header_get_field(page, PAGE_GARBAGE);
......
......@@ -59,18 +59,6 @@ page_zip_write_header(
__attribute__((nonnull));
/**************************************************************************
Write data to the uncompressed trailer portion of a page. The data must
already have been written to the uncompressed page. */
UNIV_INLINE
void
page_zip_write_trailer(
/*===================*/
page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* str, /* in: address on the uncompressed page */
ulint length) /* in: length of the data */
__attribute__((nonnull));
#ifdef UNIV_DEBUG
/**************************************************************************
Determine if enough space is available in the modification log. */
......
......@@ -34,7 +34,7 @@ page_zip_compress(
/*==============*/
/* out: TRUE on success, FALSE on failure;
page_zip will be left intact on failure. */
page_zip_des_t* page_zip,/* out: compressed page */
page_zip_des_t* page_zip,/* in: size; out: compressed page */
const page_t* page); /* in: uncompressed page */
/**************************************************************************
......@@ -71,6 +71,45 @@ page_zip_validate(
const page_t* page); /* in: uncompressed page */
#endif /* UNIV_DEBUG */
/*****************************************************************
Gets the size of the compressed page trailer (the dense page directory). */
UNIV_INLINE
ulint
page_zip_dir_size(
/*==============*/
/* out: length of dense page
directory, in bytes */
const page_zip_des_t* page_zip) /* in: compressed page */
__attribute__((pure));
/*****************************************************************
Read a given slot in the dense page directory. */
UNIV_INLINE
ulint
page_zip_dir_get(
/*==============*/
/* out: record offset
on the uncompressed page,
possibly ORed with
PAGE_ZIP_DIR_SLOT_DEL or
PAGE_ZIP_DIR_SLOT_OWNED */
const page_zip_des_t* page_zip, /* in: compressed page */
ulint slot) /* in: slot
(0=first user record) */
__attribute__((pure));
/*****************************************************************
Write a given slot in the dense page directory. */
UNIV_INLINE
void
page_zip_dir_set(
/*==============*/
const page_zip_des_t* page_zip, /* in: compressed page */
ulint slot, /* in: slot
(0=first user record) */
ulint offs) /* in: offset, possibly
ORed with
PAGE_ZIP_DIR_SLOT_DEL or
PAGE_ZIP_DIR_SLOT_OWNED */
__attribute__((pure));
/**************************************************************************
Determine the encoded length of an integer in the modification log. */
UNIV_INLINE
......@@ -144,7 +183,7 @@ page_zip_write(
page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* str, /* in: address on the uncompressed page */
ulint length) /* in: length of the data */
__attribute__((nonnull));
__attribute__((nonnull, deprecated));
/**************************************************************************
Write data to the uncompressed header portion of a page. The data must
......@@ -158,19 +197,6 @@ page_zip_write_header(
ulint length) /* in: length of the data */
__attribute__((nonnull));
/**************************************************************************
Write data to the uncompressed trailer portion of a page. The data must
already have been written to the uncompressed page. */
UNIV_INLINE
void
page_zip_write_trailer(
/*===================*/
page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* str, /* in: address on the uncompressed page */
ulint length) /* in: length of the data */
__attribute__((nonnull));
#ifdef UNIV_MATERIALIZE
# undef UNIV_INLINE
# define UNIV_INLINE UNIV_INLINE_ORIGINAL
......
......@@ -16,20 +16,32 @@ Created June 2005 by Marko Makela
/* The format of compressed pages is as follows.
The header and trailer of the uncompressed pages, including the page
The header and trailer of the uncompressed pages, excluding the page
directory in the trailer, are copied as is to the header and trailer
of the compressed page. Immediately preceding the page trailer,
we store a 32-bit checksum of the compressed data.
The data between PAGE_DATA and the last page directory entry
will be written in compressed format, starting at offset PAGE_DATA.
of the compressed page.
At the end of the compressed page, there is a dense page directory
pointing to every user record contained on the page, including deleted
records on the free list. The dense directory is indexed by the
record heap number. The infimum and supremum records are excluded.
The two most significant bits of the entries are allocated for the
delete-mark and an n_owned flag indicating the last record in a chain
of records pointed to from the sparse page directory on the
uncompressed page.
The data between PAGE_ZIP_START and the last page directory entry will
be written in compressed format, starting at offset PAGE_DATA.
Infimum and supremum records are not stored. We exclude the
REC_N_NEW_EXTRA_BYTES in every record header. These can be recovered
from the dense page directory stored at the end of the compressed
page.
The compressed data stream may be followed by a modification log
covering the compressed portion of the page, as follows.
MODIFICATION LOG ENTRY FORMAT
- length (1..2 bytes), not zero
- offset - PAGE_DATA (1..2 bytes)
- offset - PAGE_ZIP_START (1..2 bytes)
- data bytes
The length and the offset are stored in a variable-length format:
......@@ -39,6 +51,17 @@ The length and the offset are stored in a variable-length format:
The end of the modification log is marked by length=0. */
/* Start offset of the area that will be compressed */
#define PAGE_ZIP_START PAGE_NEW_SUPREMUM_END
/* Size of an compressed page directory entry */
#define PAGE_ZIP_DIR_SLOT_SIZE 2
/* Mask of record offsets */
#define PAGE_ZIP_DIR_SLOT_MASK 0x3fff
/* 'owned' flag */
#define PAGE_ZIP_DIR_SLOT_OWNED 0x4000
/* 'deleted' flag */
#define PAGE_ZIP_DIR_SLOT_DEL 0x8000
/**************************************************************************
Initialize a compressed page descriptor. */
UNIV_INLINE
......@@ -66,7 +89,7 @@ page_zip_ulint_size(
if (num < 16384) { /* 10xxxxxx xxxxxxxx: 0..16383 */
return(2);
}
ut_error;
ut_ad(0);
return(0);
}
......@@ -80,9 +103,10 @@ page_zip_entry_size(
ulint pos, /* in: offset of the uncompressed page */
ulint length) /* in: length of the data */
{
ut_ad(pos >= PAGE_DATA);
ut_ad(pos + length <= UNIV_PAGE_SIZE - PAGE_DATA /* - trailer_len */);
return(page_zip_ulint_size(pos - PAGE_DATA)
ut_ad(pos >= PAGE_ZIP_START);
ut_ad(pos + length <= UNIV_PAGE_SIZE - PAGE_ZIP_START
/* - trailer_len */);
return(page_zip_ulint_size(pos - PAGE_ZIP_START)
+ page_zip_ulint_size(length)
+ length);
}
......@@ -99,15 +123,73 @@ page_zip_simple_validate(
{
ut_ad(page_zip);
ut_ad(page_zip->data);
ut_ad(!(page_zip->size & (page_zip->size - 1)));
ut_ad(page_zip->size < UNIV_PAGE_SIZE);
ut_ad(page_zip->size > PAGE_DATA + PAGE_EMPTY_DIR_START);
ut_ad(!(page_zip->size & (page_zip->size - 1))); /* power of 2 */
ut_ad(page_zip->size <= UNIV_PAGE_SIZE);
ut_ad(page_zip->size > PAGE_DATA + PAGE_ZIP_DIR_SLOT_SIZE);
ut_ad(page_zip->m_start >= PAGE_DATA);
ut_ad(page_zip->m_start <= page_zip->m_end);
ut_ad(page_zip->m_end < page_zip->size);
return(TRUE);
}
#endif /* UNIV_DEBUG */
/*****************************************************************
Gets the size of the compressed page trailer (the dense page directory). */
UNIV_INLINE
ulint
page_zip_dir_size(
/*==============*/
/* out: length of dense page
directory, in bytes */
const page_zip_des_t* page_zip) /* in: compressed page */
{
ulint size = PAGE_ZIP_DIR_SLOT_SIZE
* (page_dir_get_n_heap((page_t*) page_zip->data) - 2);
ut_ad(page_zip->m_end + size < page_zip->size);
return(size);
}
/*****************************************************************
Read a given slot in the dense page directory. */
UNIV_INLINE
ulint
page_zip_dir_get(
/*==============*/
/* out: record offset
on the uncompressed page,
possibly ORed with
PAGE_ZIP_DIR_SLOT_DEL or
PAGE_ZIP_DIR_SLOT_OWNED */
const page_zip_des_t* page_zip, /* in: compressed page */
ulint slot) /* in: slot
(0=first user record) */
{
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(slot + 2 < page_dir_get_n_heap((page_t*) page_zip->data));
return(mach_read_from_2(page_zip->data + page_zip->size
- PAGE_ZIP_DIR_SLOT_SIZE * slot));
}
/*****************************************************************
Write a given slot in the dense page directory. */
UNIV_INLINE
void
page_zip_dir_set(
/*==============*/
const page_zip_des_t* page_zip, /* in: compressed page */
ulint slot, /* in: slot
(0=first user record) */
ulint offs) /* in: offset, possibly
ORed with
PAGE_ZIP_DIR_SLOT_DEL or
PAGE_ZIP_DIR_SLOT_OWNED */
{
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(slot + 2 < page_dir_get_n_heap((page_t*) page_zip->data));
mach_write_to_2(page_zip->data + page_zip->size
- PAGE_ZIP_DIR_SLOT_SIZE * slot,
offs);
}
/**************************************************************************
Ensure that enough space is available in the modification log.
If not, try to compress the page. */
......@@ -122,14 +204,13 @@ page_zip_alloc(
const page_t* page, /* in: uncompressed page */
ulint size) /* in: size of modification log entries */
{
ulint trailer_len = page_trailer_get_len(page_zip->data);
ulint trailer_len = page_zip_dir_size(page_zip);
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip->m_end + trailer_len < page_zip->size);
ut_ad(size >= 3); /* modification log entries are >= 1+1+1 bytes */
ut_ad(size < page_zip->size);
if (size < page_zip->size - page_zip->m_end - trailer_len) {
if (size + page_zip->m_end + trailer_len < page_zip->size) {
return(TRUE);
}
......@@ -154,14 +235,13 @@ page_zip_available(
ulint size) /* in: requested size of
modification log entries */
{
ulint trailer_len = page_trailer_get_len(page_zip->data);
ulint trailer_len = page_zip_dir_size(page_zip);
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip->m_end + trailer_len < page_zip->size);
ut_ad(size < page_zip->size);
return(UNIV_LIKELY(
size < page_zip->size - page_zip->m_end - trailer_len));
size + page_zip->m_end + trailer_len < page_zip->size));
}
/**************************************************************************
......@@ -189,35 +269,6 @@ page_zip_write_header(
ut_ad(page_zip_validate(page_zip, str - pos));
}
/**************************************************************************
Write data to the uncompressed trailer portion of a page. The data must
already have been written to the uncompressed page. */
UNIV_INLINE
void
page_zip_write_trailer(
/*===================*/
page_zip_des_t* page_zip,/* in/out: compressed page */
const byte* str, /* in: address on the uncompressed page */
ulint length) /* in: length of the data */
{
ulint pos;
ut_ad(buf_block_get_page_zip(buf_block_align((byte*)str)) == page_zip);
ut_ad(page_zip_simple_validate(page_zip));
pos = ut_align_offset(str, UNIV_PAGE_SIZE);
ut_ad(pos > PAGE_DATA);
ut_ad(pos < UNIV_PAGE_SIZE
- page_trailer_get_len(buf_frame_align((byte*) str)));
memcpy(page_zip->data + page_zip->size - (UNIV_PAGE_SIZE - pos),
str, length);
ut_ad(page_zip_validate(page_zip, str - pos));
}
#ifdef UNIV_MATERIALIZE
# undef UNIV_INLINE
# define UNIV_INLINE UNIV_INLINE_ORIGINAL
......
......@@ -21,6 +21,9 @@ Created 5/30/1994 Heikki Tuuri
/* Flag denoting the predefined minimum record: this bit is ORed in the 4
info bits of a record */
#define REC_INFO_MIN_REC_FLAG 0x10UL
/* 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 */
/* Number of extra bytes in an old-style record,
in addition to the data and the offsets */
......@@ -35,6 +38,16 @@ in addition to the data and the offsets */
#define REC_STATUS_INFIMUM 2
#define REC_STATUS_SUPREMUM 3
/* The following two constants are needed in page0zip.c in order to
efficiently access heap_no and status when compressing and
decompressing pages. */
/* The offset of heap_no in a compact record */
#define REC_NEW_HEAP_NO 4
/* The shift of heap_no in a compact record.
The status is stored in the low-order bits. */
#define REC_HEAP_NO_SHIFT 3
/* Number of elements that should be initially allocated for the
offsets[] array, first passed to rec_get_offsets() */
#define REC_OFFS_NORMAL_SIZE 100
......
......@@ -84,9 +84,11 @@ and the shift needed to obtain each bit-field of the record. */
#define REC_NEW_STATUS_SHIFT 0
#define REC_OLD_HEAP_NO 5
#define REC_NEW_HEAP_NO 4
#define REC_HEAP_NO_MASK 0xFFF8UL
#if 0 /* defined in rem0rec.h for use of page0zip.c */
#define REC_NEW_HEAP_NO 4
#define REC_HEAP_NO_SHIFT 3
#endif
#define REC_OLD_N_OWNED 6 /* This is single byte bit-field */
#define REC_NEW_N_OWNED 5 /* This is single byte bit-field */
......@@ -98,9 +100,6 @@ and the shift needed to obtain each bit-field of the record. */
#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 from
one-byte and two-byte offsets */
......
This diff is collapsed.
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