summaryrefslogtreecommitdiff
path: root/storage/maria/ma_blockrec.c
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2013-06-06 21:32:29 +0200
committerSergei Golubchik <sergii@pisem.net>2013-06-06 21:32:29 +0200
commit72ba95873a6d99def07a4bfecda44fb942165142 (patch)
tree4bcb11afc568c4894f4cb109d57c14968320a58b /storage/maria/ma_blockrec.c
parentfab9a55d077b4f2a511b273d5f51272f1e3dc1ff (diff)
parent4749d40c635634e25e07d28ce1a04e9263bcc375 (diff)
downloadmariadb-git-72ba95873a6d99def07a4bfecda44fb942165142.tar.gz
10.0-base merge
(without InnoDB - all InnoDB changes were ignored)
Diffstat (limited to 'storage/maria/ma_blockrec.c')
-rw-r--r--storage/maria/ma_blockrec.c73
1 files changed, 59 insertions, 14 deletions
diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c
index 16657ba80ae..03fd0200d18 100644
--- a/storage/maria/ma_blockrec.c
+++ b/storage/maria/ma_blockrec.c
@@ -4007,6 +4007,8 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number,
uint length, empty_space;
uchar *dir;
DBUG_ENTER("delete_dir_entry");
+ DBUG_PRINT("enter", ("record_number: %u number_of_records: %u",
+ record_number, number_of_records));
#ifdef SANITY_CHECKS
if (record_number >= number_of_records ||
@@ -4023,7 +4025,8 @@ static int delete_dir_entry(uchar *buff, uint block_size, uint record_number,
check_directory(buff, block_size, 0, (uint) -1);
empty_space= uint2korr(buff + EMPTY_SPACE_OFFSET);
dir= dir_entry_pos(buff, block_size, record_number);
- length= uint2korr(dir + 2);
+ length= uint2korr(dir + 2); /* Length of entry we just deleted */
+ DBUG_ASSERT(uint2korr(dir) != 0 && length < block_size);
if (record_number == number_of_records - 1)
{
@@ -5240,11 +5243,6 @@ void _ma_scan_end_block_record(MARIA_HA *info)
For the moment we can only remember one position, but this is
good enough for MySQL usage
- @Warning
- When this function is called, we assume that the thread is not deleting
- or updating the current row before ma_scan_restore_block_record()
- is called!
-
@return
@retval 0 ok
@retval HA_ERR_WRONG_IN_RECORD Could not allocate memory to hold position
@@ -5264,15 +5262,18 @@ int _ma_scan_remember_block_record(MARIA_HA *info,
info->scan_save->bitmap_buff= ((uchar*) info->scan_save +
ALIGN_SIZE(sizeof(*info->scan_save)));
}
- /* Point to the last read row */
- *lastpos= info->cur_row.nextpos - 1;
- info->scan.dir+= DIR_ENTRY_SIZE;
+ /* For checking if pages have changed since we last read it */
+ info->scan.row_changes= info->row_changes;
/* Remember used bitmap and used head page */
bitmap_buff= info->scan_save->bitmap_buff;
memcpy(info->scan_save, &info->scan, sizeof(*info->scan_save));
info->scan_save->bitmap_buff= bitmap_buff;
memcpy(bitmap_buff, info->scan.bitmap_buff, info->s->block_size * 2);
+
+ /* Point to the last read row */
+ *lastpos= info->cur_row.nextpos - 1;
+ info->scan_save->dir+= DIR_ENTRY_SIZE;
DBUG_RETURN(0);
}
@@ -5280,15 +5281,22 @@ int _ma_scan_remember_block_record(MARIA_HA *info,
/**
@brief restore scan block it's original values
+ @return
+ 0 ok
+ # error
+
@note
In theory we could swap bitmap buffers instead of copy them.
For the moment we don't do that because there are variables pointing
inside the buffers and it's a bit of hassle to either make them relative
or repoint them.
+
+ If the data file has changed, we will re-read the new block record
+ to ensure that when we continue scanning we can ignore any deleted rows.
*/
-void _ma_scan_restore_block_record(MARIA_HA *info,
- MARIA_RECORD_POS lastpos)
+int _ma_scan_restore_block_record(MARIA_HA *info,
+ MARIA_RECORD_POS lastpos)
{
uchar *bitmap_buff;
DBUG_ENTER("_ma_scan_restore_block_record");
@@ -5299,7 +5307,26 @@ void _ma_scan_restore_block_record(MARIA_HA *info,
info->scan.bitmap_buff= bitmap_buff;
memcpy(bitmap_buff, info->scan_save->bitmap_buff, info->s->block_size * 2);
- DBUG_VOID_RETURN;
+ if (info->scan.row_changes != info->row_changes)
+ {
+ /*
+ Table has been changed. We have to re-read the current page block as
+ data may have changed on it that we have to see.
+ */
+ if (!(pagecache_read(info->s->pagecache,
+ &info->dfile,
+ ma_recordpos_to_page(info->scan.row_base_page),
+ 0, info->scan.page_buff,
+ info->s->page_type,
+ PAGECACHE_LOCK_LEFT_UNLOCKED, 0)))
+ DBUG_RETURN(my_errno);
+ info->scan.number_of_rows=
+ (uint) (uchar) info->scan.page_buff[DIR_COUNT_OFFSET];
+ info->scan.dir_end= (info->scan.page_buff + info->s->block_size -
+ PAGE_SUFFIX_SIZE -
+ info->scan.number_of_rows * DIR_ENTRY_SIZE);
+ }
+ DBUG_RETURN(0);
}
@@ -5326,7 +5353,7 @@ void _ma_scan_restore_block_record(MARIA_HA *info,
RETURN
0 ok
- # Error code
+ # Error code (Normally HA_ERR_END_OF_FILE)
*/
int _ma_scan_block_record(MARIA_HA *info, uchar *record,
@@ -5345,6 +5372,12 @@ restart_record_read:
uchar *data, *end_of_data;
int error;
+ /* Ensure that scan.dir and record_pos are in sync */
+ DBUG_ASSERT(info->scan.dir == dir_entry_pos(info->scan.page_buff,
+ share->block_size,
+ record_pos));
+
+ /* Search for a valid directory entry (not 0) */
while (!(offset= uint2korr(info->scan.dir)))
{
info->scan.dir-= DIR_ENTRY_SIZE;
@@ -5357,13 +5390,19 @@ restart_record_read:
}
#endif
}
+ /*
+ This should always be true as the directory should always start with
+ a valid entry.
+ */
+ DBUG_ASSERT(info->scan.dir >= info->scan.dir_end);
+
/* found row */
info->cur_row.lastpos= info->scan.row_base_page + record_pos;
info->cur_row.nextpos= record_pos + 1;
data= info->scan.page_buff + offset;
length= uint2korr(info->scan.dir + 2);
end_of_data= data + length;
- info->scan.dir-= DIR_ENTRY_SIZE; /* Point to previous row */
+ info->scan.dir-= DIR_ENTRY_SIZE; /* Point to next row to process */
#ifdef SANITY_CHECKS
if (end_of_data > info->scan.dir_end ||
offset < PAGE_HEADER_SIZE || length < share->base.min_block_length)
@@ -6937,6 +6976,7 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn,
res= 0;
end:
+ /* The following is true only if _ma_bitmap_flushable() was called earlier */
if (info->non_flushable_state)
_ma_bitmap_flushable(info, -1);
_ma_unpin_all_pages_and_finalize_row(info, lsn);
@@ -6946,6 +6986,11 @@ err:
DBUG_ASSERT(!maria_assert_if_crashed_table);
res= 1;
_ma_mark_file_crashed(share);
+ /*
+ Don't write a new LSN on the used pages. Not important as the file is
+ marked as crashed and need to be repaired before it can be used.
+ */
+ lsn= LSN_IMPOSSIBLE;
goto end;
}