Commit 5637695a authored by marko's avatar marko

branches/zip: Improve Valgrind instrumentation of allocated memory.

UNIV_MEM_FREE(): Declare a memory area free.
UNIV_MEM_ALLOC(): Declare a memory area allocated (but uninitialized).
UNIV_MEM_DESC(): Associate a memory area with a control block.
UNIV_MEM_UNDESC(): Unassociate a control block.

trx_sys_create_doublewrite_buf(): Clear the buffer with memset().

buf_page_init(): Add a bogus UNIV_MEM_VALID(block->frame) to silence
valid warnings about InnoDB data pages containing uninitialized data.

buf_LRU_get_free_only(): Add UNIV_MEM_ALLOC(block->frame).

buf_LRU_get_free_block(): Add UNIV_MEM_DESC(block->page.zip.data, block).

buf_LRU_free_block(): Add UNIV_MEM_DESC(b->zip.data, b) when allocating
a compressed-only control block for a compressed page.

buf_LRU_block_free_non_file_page(): Replace UNIV_MEM_INVALID() with
UNIV_MEM_FREE().

buf_LRU_block_remove_hashed_page(): Add UNIV_MEM_UNDESC(bpage) when
deallocating a compressed-only control block.  Add
UNIV_MEM_INVALID(block->frame).  (The frame should be flagged free
by buf_LRU_block_free_non_file_page() moments later.)

buf0buddy.c: Disable some extra checks in Valgrind-instrumented builds.
Add UNIV_MEM_VALID(), UNIV_MEM_INVALID(), UNIV_MEM_FREE(), UNIV_MEM_ALLOC()
as necessary.
parent 069514de
......@@ -56,10 +56,14 @@ buf_buddy_alloc_zip(
#endif /* UNIV_SYNC_DEBUG */
ut_a(i < BUF_BUDDY_SIZES);
ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i]));
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing free memory. */
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i]);
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
if (bpage) {
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
......@@ -76,6 +80,7 @@ buf_buddy_alloc_zip(
buddy->state = BUF_BLOCK_ZIP_FREE;
ut_ad(buf_pool->zip_free[i].start != buddy);
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], buddy);
UNIV_MEM_FREE(buddy, BUF_BUDDY_LOW << i);
}
}
......@@ -85,6 +90,8 @@ buf_buddy_alloc_zip(
}
#endif /* UNIV_DEBUG */
UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i);
return(bpage);
}
......@@ -159,6 +166,9 @@ buf_buddy_alloc_from(
/* Add the unused parts of the block to the free lists. */
while (j > i) {
buf_page_t* bpage;
#ifdef UNIV_DEBUG_VALGRIND
buf_page_t* b;
#endif /* UNIV_DEBUG_VALGRIND */
offs >>= 1;
j--;
......@@ -166,10 +176,20 @@ buf_buddy_alloc_from(
bpage = (buf_page_t*) ((byte*) buf + offs);
ut_d(memset(bpage, j, BUF_BUDDY_LOW << j));
bpage->state = BUF_BLOCK_ZIP_FREE;
ut_d(UT_LIST_VALIDATE(list, buf_page_t,
buf_pool->zip_free[j]));
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing free memory. */
UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[j]);
ut_ad(buf_pool->zip_free[j].start != bpage);
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
#ifdef UNIV_DEBUG_VALGRIND
b = UT_LIST_GET_FIRST(buf_pool->zip_free[j]);
if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << j);
#endif /* UNIV_DEBUG_VALGRIND */
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[j], bpage);
#ifdef UNIV_DEBUG_VALGRIND
if (b) UNIV_MEM_FREE(b, BUF_BUDDY_LOW << j);
#endif /* UNIV_DEBUG_VALGRIND */
UNIV_MEM_FREE(bpage, BUF_BUDDY_LOW << j);
}
return(buf);
......@@ -493,6 +513,7 @@ buf_buddy_free_low(
ut_a(!mutex_own(&buf_pool->zip_mutex));
#endif /* UNIV_SYNC_DEBUG */
recombine:
UNIV_MEM_INVALID(buf, BUF_BUDDY_LOW << i);
ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE);
if (i == BUF_BUDDY_SIZES) {
......@@ -508,6 +529,9 @@ recombine:
buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i);
#ifndef UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing free memory. */
if (buddy->state != BUF_BLOCK_ZIP_FREE) {
goto buddy_nonfree;
......@@ -516,9 +540,11 @@ recombine:
/* The field buddy->state can only be trusted for free blocks.
If buddy->state == BUF_BLOCK_ZIP_FREE, the block is free if
it is in the free list. */
#endif /* !UNIV_DEBUG_VALGRIND */
for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
bpage; bpage = UT_LIST_GET_NEXT(list, bpage)) {
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
if (bpage == buddy) {
......@@ -534,11 +560,15 @@ buddy_free2:
goto recombine;
}
UNIV_MEM_FREE(bpage, BUF_BUDDY_LOW << i);
ut_a(bpage != buf);
}
#ifndef UNIV_DEBUG_VALGRIND
buddy_nonfree:
/* Valgrind would complain about accessing free memory. */
ut_d(UT_LIST_VALIDATE(list, buf_page_t, buf_pool->zip_free[i]));
#endif /* UNIV_DEBUG_VALGRIND */
/* The buddy is not free. Is there a free block of this size? */
bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
......@@ -547,6 +577,8 @@ buddy_nonfree:
/* Remove the block from the free list, because a successful
buf_buddy_relocate() will overwrite bpage->list. */
UNIV_MEM_ALLOC(bpage, BUF_BUDDY_LOW << i);
UNIV_MEM_VALID(&bpage->list, sizeof bpage->list);
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
/* Try to relocate the buddy of buf to the free block. */
......@@ -557,12 +589,14 @@ buddy_nonfree:
}
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
UNIV_MEM_FREE(bpage, BUF_BUDDY_LOW << i);
/* Try to relocate the buddy of the free block to buf. */
buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage),
BUF_BUDDY_LOW << i);
#ifdef UNIV_DEBUG
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing free memory. */
{
const buf_page_t* b;
......@@ -574,7 +608,7 @@ buddy_nonfree:
ut_a(b != buddy);
}
}
#endif /* UNIV_DEBUG */
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
if (buf_buddy_relocate(buddy, buf, i)) {
......@@ -598,6 +632,10 @@ buddy_nonfree:
char* c;
# ifndef UNIV_DEBUG_VALGRIND
/* Valgrind would complain about accessing
uninitialized memory. Besides, Valgrind performs a
more exhaustive check, at every memory access. */
const buf_page_t* b = buf;
const buf_page_t* const b_end = (buf_page_t*)
((char*) b + (BUF_BUDDY_LOW << i));
......@@ -616,6 +654,7 @@ buddy_nonfree:
buf, i);
}
}
# endif /* !UNIV_DEBUG_VALGRIND */
/* Scramble the block. This should make any pointers
invalid and trigger a segmentation violation. Because
......@@ -632,7 +671,7 @@ buddy_nonfree:
memset(bpage, i, BUF_BUDDY_LOW << i);
}
#endif /* UNIV_DEBUG */
UNIV_MEM_INVALID(buf, BUF_BUDDY_LOW << i);
UNIV_MEM_FREE(buf, BUF_BUDDY_LOW << i);
bpage->state = BUF_BLOCK_ZIP_FREE;
ut_ad(buf_pool->zip_free[i].start != bpage);
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
......
......@@ -596,6 +596,8 @@ buf_block_init(
buf_block_t* block, /* in: pointer to control block */
byte* frame) /* in: pointer to buffer frame */
{
UNIV_MEM_DESC(frame, UNIV_PAGE_SIZE, block);
block->frame = frame;
block->page.state = BUF_BLOCK_NOT_USED;
......@@ -863,6 +865,7 @@ buf_chunk_free(
#ifdef UNIV_SYNC_DEBUG
rw_lock_free(&block->debug_latch);
#endif /* UNIV_SYNC_DEBUG */
UNIV_MEM_UNDESC(block);
}
os_mem_free_large(chunk->mem, chunk->mem_size);
......@@ -1936,6 +1939,10 @@ buf_page_init(
/* Set the state of the block */
buf_block_set_file_page(block, space, offset);
/* Silence valid Valgrind warnings about uninitialized
data being written to data files. There are some unused
bytes on some pages that InnoDB does not initialize. */
UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
block->check_index_page_at_flush = FALSE;
block->index = NULL;
......@@ -2139,6 +2146,7 @@ buf_page_init_for_read(
mutex_enter(&buf_pool->zip_mutex);
buf_relocate(bpage, &block->page);
UNIV_MEM_DESC(bpage->zip.data, zip_size, block);
if (buf_page_get_state(&block->page)
== BUF_BLOCK_ZIP_PAGE) {
......
......@@ -389,7 +389,7 @@ buf_LRU_get_free_only(void)
mutex_enter(&block->mutex);
buf_block_set_state(block, BUF_BLOCK_READY_FOR_USE);
UNIV_MEM_VALID(block->frame, UNIV_PAGE_SIZE);
UNIV_MEM_ALLOC(block->frame, UNIV_PAGE_SIZE);
mutex_exit(&block->mutex);
}
......@@ -496,6 +496,7 @@ loop:
if (zip_size) {
page_zip_set_size(&block->page.zip, zip_size);
block->page.zip.data = buf_buddy_alloc(zip_size, TRUE);
UNIV_MEM_DESC(block->page.zip.data, zip_size, block);
} else {
page_zip_set_size(&block->page.zip, 0);
block->page.zip.data = NULL;
......@@ -988,6 +989,8 @@ buf_LRU_free_block(
b->state = b->oldest_modification
? BUF_BLOCK_ZIP_DIRTY
: BUF_BLOCK_ZIP_PAGE;
UNIV_MEM_DESC(b->zip.data,
page_zip_get_size(&b->zip), b);
HASH_INSERT(buf_page_t, hash,
buf_pool->page_hash, fold, b);
......@@ -1070,7 +1073,7 @@ buf_LRU_block_free_non_file_page(
UT_LIST_ADD_FIRST(list, buf_pool->free, (&block->page));
ut_d(block->page.in_free_list = TRUE);
UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
UNIV_MEM_FREE(block->frame, UNIV_PAGE_SIZE);
}
/**********************************************************************
......@@ -1183,6 +1186,7 @@ buf_LRU_block_remove_hashed_page(
buf_buddy_free(bpage->zip.data,
page_zip_get_size(&bpage->zip));
buf_buddy_free(bpage, sizeof(*bpage));
UNIV_MEM_UNDESC(bpage);
return(BUF_BLOCK_ZIP_FREE);
case BUF_BLOCK_FILE_PAGE:
......@@ -1190,6 +1194,8 @@ buf_LRU_block_remove_hashed_page(
+ FIL_PAGE_OFFSET, 0xff, 4);
memset(((buf_block_t*) bpage)->frame
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0xff, 4);
UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame,
UNIV_PAGE_SIZE);
buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
if (zip && bpage->zip.data) {
......
......@@ -312,9 +312,17 @@ typedef void* os_thread_ret_t;
# include <valgrind/memcheck.h>
# define UNIV_MEM_VALID(addr, size) VALGRIND_MAKE_MEM_DEFINED(addr, size)
# define UNIV_MEM_INVALID(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
# define UNIV_MEM_FREE(addr, size) VALGRIND_MAKE_MEM_NOACCESS(addr, size)
# define UNIV_MEM_ALLOC(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
# define UNIV_MEM_DESC(addr, size, b) VALGRIND_CREATE_BLOCK(addr, size, b)
# define UNIV_MEM_UNDESC(b) VALGRIND_DISCARD(b)
#else
# define UNIV_MEM_VALID(addr, size) do {} while(0)
# define UNIV_MEM_INVALID(addr, size) do {} while(0)
# define UNIV_MEM_FREE(addr, size) do {} while(0)
# define UNIV_MEM_ALLOC(addr, size) do {} while(0)
# define UNIV_MEM_DESC(addr, size, b) do {} while(0)
# define UNIV_MEM_UNDESC(b) do {} while(0)
#endif
#endif
......@@ -275,6 +275,9 @@ start_again:
SYNC_NO_ORDER_CHECK);
#endif /* UNIV_SYNC_DEBUG */
/* Avoid writing uninitialized memory to disk. */
memset(new_block->frame, 0, UNIV_PAGE_SIZE);
/* Make a dummy change to the page to ensure it will
be written to disk in a flush */
......
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