diff options
author | unknown <monty@mysql.com/nosik.monty.fi> | 2007-09-09 19:15:10 +0300 |
---|---|---|
committer | unknown <monty@mysql.com/nosik.monty.fi> | 2007-09-09 19:15:10 +0300 |
commit | 155193a6e27b22e5557e536dd9189e26bbb8fb3a (patch) | |
tree | 2fc6f1290733619db80ad29eb78ed30f4cec06b6 | |
parent | 58ac5254fabb2e571af18f15aba874121a92a05f (diff) | |
download | mariadb-git-155193a6e27b22e5557e536dd9189e26bbb8fb3a.tar.gz |
Added applying of undo for updates
Fixed bug in duplicate key handling for block records during repair
All read-row methods now return error number in case of error
Don't calculate checksum for null fields
Fixed bug when running maria_read_log with -o
BUILD/SETUP.sh:
Added STACK_DIRECTION
BUILD/compile-pentium-debug-max:
Moved STACK_DIRECTION to SETUP
include/myisam.h:
Added extra parameter to write_key
storage/maria/ma_blockrec.c:
Added applying of undo for updates
Fixed indentation
Removed some not needed casts
Fixed wrong logging of CLR record
Split ma_update_block_record to two functions to be able to reuse it from undo-applying
Simplify filling of packed fields
ma_record_block_record) now returns error number on failure
Sligtly changed log record information for undo-update
storage/maria/ma_check.c:
Fixed bug in duplicate key handling for block records during repair
storage/maria/ma_checksum.c:
Don't calculate checksum for null fields
storage/maria/ma_dynrec.c:
_ma_read_dynamic_reocrd() now returns error number on error
Rest of the changes are code simplification and indentation fixes
storage/maria/ma_locking.c:
Added comment
storage/maria/ma_loghandler.c:
More debugging
Removed printing of total_record_length as this was always same as record_length
storage/maria/ma_open.c:
Allocate bitmap for changed fields
storage/maria/ma_packrec.c:
read_record now returns error number on error
storage/maria/ma_recovery.c:
Fixed wrong arguments to undo_row_update
storage/maria/ma_statrec.c:
read_record now returns error number on error (not 1)
Code simplification
storage/maria/ma_test1.c:
Added exit possibility after update phase (to test undo of updates)
storage/maria/maria_def.h:
Include bitmap header file
storage/maria/maria_read_log.c:
Fixed bug when running with -o
-rwxr-xr-x | BUILD/SETUP.sh | 6 | ||||
-rwxr-xr-x | BUILD/compile-pentium-debug-max | 2 | ||||
-rw-r--r-- | include/myisam.h | 2 | ||||
-rw-r--r-- | storage/maria/ma_blockrec.c | 309 | ||||
-rw-r--r-- | storage/maria/ma_check.c | 14 | ||||
-rw-r--r-- | storage/maria/ma_checksum.c | 7 | ||||
-rw-r--r-- | storage/maria/ma_dynrec.c | 191 | ||||
-rw-r--r-- | storage/maria/ma_locking.c | 3 | ||||
-rw-r--r-- | storage/maria/ma_loghandler.c | 8 | ||||
-rw-r--r-- | storage/maria/ma_open.c | 5 | ||||
-rw-r--r-- | storage/maria/ma_packrec.c | 12 | ||||
-rw-r--r-- | storage/maria/ma_recovery.c | 10 | ||||
-rw-r--r-- | storage/maria/ma_statrec.c | 21 | ||||
-rw-r--r-- | storage/maria/ma_test1.c | 19 | ||||
-rw-r--r-- | storage/maria/maria_def.h | 4 | ||||
-rw-r--r-- | storage/maria/maria_read_log.c | 3 |
16 files changed, 418 insertions, 198 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh index 6b3708f475f..429c0cd85b4 100755 --- a/BUILD/SETUP.sh +++ b/BUILD/SETUP.sh @@ -170,10 +170,10 @@ max_configs="$SSL_LIBRARY --with-plugins=max --with-embedded-server" # CPU and platform specific compilation flags. # alpha_cflags="$check_cpu_cflags -Wa,-m$cpu_flag" -amd64_cflags="$check_cpu_cflags" +amd64_cflags="$check_cpu_cflags -DSTACK_DIRECTION=-1" amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES" -pentium_cflags="$check_cpu_cflags" -pentium64_cflags="$check_cpu_cflags -m64" +pentium_cflags="$check_cpu_cflags -DSTACK_DIRECTION=-1" +pentium64_cflags="$check_cpu_cflags -m64 -DSTACK_DIRECTION=-1" ppc_cflags="$check_cpu_cflags" sparc_cflags="" diff --git a/BUILD/compile-pentium-debug-max b/BUILD/compile-pentium-debug-max index 39d12a8320a..941a63a209f 100755 --- a/BUILD/compile-pentium-debug-max +++ b/BUILD/compile-pentium-debug-max @@ -4,7 +4,7 @@ path=`dirname $0` set -- "$@" --with-debug=full . "$path/SETUP.sh" -extra_flags="$pentium_cflags $debug_cflags -DSTACK_DIRECTION=-1" +extra_flags="$pentium_cflags $debug_cflags" extra_configs="$pentium_configs $debug_configs $max_configs $error_inject --with-experimental-collations" . "$path/FINISH.sh" diff --git a/include/myisam.h b/include/myisam.h index 154a3d95b41..75c56e100c9 100644 --- a/include/myisam.h +++ b/include/myisam.h @@ -364,7 +364,7 @@ typedef struct st_mi_sort_param NEAR int (*write_keys)(struct st_mi_sort_param *, register uchar **, uint , struct st_buffpek *, IO_CACHE *); NEAR uint (*read_to_buffer)(IO_CACHE *,struct st_buffpek *, uint); - NEAR int (*write_key)(struct st_mi_sort_param *, IO_CACHE *,char *, + NEAR int (*write_key)(struct st_mi_sort_param *, IO_CACHE *,uchar *, uint, uint); } MI_SORT_PARAM; diff --git a/storage/maria/ma_blockrec.c b/storage/maria/ma_blockrec.c index 55dc72b1d02..9dfdab4688d 100644 --- a/storage/maria/ma_blockrec.c +++ b/storage/maria/ma_blockrec.c @@ -678,6 +678,46 @@ static my_bool check_if_zero(uchar *pos, uint length) /* + @brief Copy not changed fields from 'from' to 'to' + + @notes + Assumption is that most fields are not changed! + (Which is why we don't test if all bits are set for some bytes in bitmap) +*/ + +void copy_not_changed_fields(MARIA_HA *info, MY_BITMAP *changed_fields, + uchar *to, uchar *from) +{ + MARIA_COLUMNDEF *column, *end_column; + uchar *bitmap= (uchar*) changed_fields->bitmap; + MARIA_SHARE *share= info->s; + uint bit= 1; + + for (column= share->columndef, end_column= column+ share->base.fields; + column < end_column; column++) + { + if (!(*bitmap & bit)) + { + uint field_length= column->length; + if (column->type == FIELD_VARCHAR) + { + if (column->fill_length == 1) + field_length= (uint) from[column->offset] + 1; + else + field_length= uint2korr(from + column->offset) + 2; + } + memcpy(to + column->offset, from + column->offset, field_length); + } + if ((bit= (bit << 1)) == 256) + { + bitmap++; + bit= 1; + } + } +} + + +/* Unpin all pinned pages SYNOPSIS @@ -878,7 +918,7 @@ static void calc_record_size(MARIA_HA *info, const uchar *record, *blob_lengths++= 0; continue; } - switch ((enum en_fieldtype) column->type) { + switch (column->type) { case FIELD_CHECK: case FIELD_NORMAL: /* Fixed length field */ case FIELD_ZERO: @@ -1321,8 +1361,8 @@ static my_bool write_tail(MARIA_HA *info, LSN lsn; /* Log REDO changes of tail page */ - page_store(log_data+ FILEID_STORE_SIZE, block->page); - dirpos_store(log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE, + page_store(log_data + FILEID_STORE_SIZE, block->page); + dirpos_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, row_pos.rownr); log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data; log_array[TRANSLOG_INTERNAL_PARTS + 0].length= sizeof(log_data); @@ -1804,7 +1844,7 @@ static my_bool write_block_record(MARIA_HA *info, continue; field_pos= record + column->offset; - switch ((enum en_fieldtype) column->type) { + switch (column->type) { case FIELD_NORMAL: /* Fixed length field */ case FIELD_SKIP_PRESPACE: case FIELD_SKIP_ZERO: /* Fixed length field */ @@ -2295,7 +2335,7 @@ static my_bool write_block_record(MARIA_HA *info, if (translog_write_record(&lsn, LOGREC_CLR_END, info->trn, info, sizeof(log_data), TRANSLOG_INTERNAL_PARTS + 1, log_array, - log_data+ FILEID_STORE_SIZE)) + log_data + LSN_STORE_SIZE)) goto disk_err; } else @@ -2305,9 +2345,9 @@ static my_bool write_block_record(MARIA_HA *info, /* LOGREC_UNDO_ROW_INSERT & LOGREC_UNDO_ROW_INSERT share same header */ lsn_store(log_data, info->trn->undo_lsn); - page_store(log_data+ LSN_STORE_SIZE + FILEID_STORE_SIZE, + page_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, head_block->page); - dirpos_store(log_data+ LSN_STORE_SIZE + FILEID_STORE_SIZE + + dirpos_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE, row_pos->rownr); @@ -2329,12 +2369,13 @@ static my_bool write_block_record(MARIA_HA *info, size_t row_length; uint row_parts_count; row_length= fill_update_undo_parts(info, old_record, record, - info->log_row_parts + + log_array + TRANSLOG_INTERNAL_PARTS + 1, &row_parts_count); if (translog_write_record(&lsn, LOGREC_UNDO_ROW_UPDATE, info->trn, info, sizeof(log_data) + row_length, - TRANSLOG_INTERNAL_PARTS + 1 + row_parts_count, + TRANSLOG_INTERNAL_PARTS + 1 + + row_parts_count, log_array, log_data + LSN_STORE_SIZE)) goto disk_err; } @@ -2601,8 +2642,11 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info) for rows split into many extents. */ -my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, - const uchar *oldrec, const uchar *record) +static my_bool _ma_update_block_record2(MARIA_HA *info, + MARIA_RECORD_POS record_pos, + const uchar *oldrec, + const uchar *record, + LSN undo_lsn) { MARIA_BITMAP_BLOCKS *blocks= &info->cur_row.insert_blocks; uchar *buff; @@ -2614,9 +2658,14 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, ulonglong page; struct st_row_pos_info row_pos; MARIA_SHARE *share= info->s; - DBUG_ENTER("_ma_update_block_record"); + DBUG_ENTER("_ma_update_block_record2"); DBUG_PRINT("enter", ("rowid: %lu", (long) record_pos)); +#ifdef ENABLE_IF_PROBLEM_WITH_UPDATE + DBUG_DUMP("oldrec", oldrec, share->base.reclength); + DBUG_DUMP("newrec", record, share->base.reclength); +#endif + calc_record_size(info, record, new_row); page= ma_recordpos_to_page(record_pos); @@ -2669,11 +2718,12 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, if (cur_row->extents_count && free_full_pages(info, cur_row)) goto err; DBUG_RETURN(write_block_record(info, oldrec, record, new_row, blocks, - 1, &row_pos, 0)); + 1, &row_pos, undo_lsn)); } /* Allocate all size in block for record - QQ: Need to improve this to do compact if we can fit one more blob into + TODO: + Need to improve this to do compact if we can fit one more blob into the head page */ head_length= uint2korr(dir + 2); @@ -2702,7 +2752,7 @@ my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, row_pos.data= buff + uint2korr(dir); row_pos.length= head_length; DBUG_RETURN(write_block_record(info, oldrec, record, new_row, blocks, 1, - &row_pos, 0)); + &row_pos, undo_lsn)); err: _ma_unpin_all_pages(info, 0); @@ -2710,6 +2760,16 @@ err: } +/* Wrapper for _ma_update_block_record2() used by ma_update() */ + + +my_bool _ma_update_block_record(MARIA_HA *info, MARIA_RECORD_POS record_pos, + const uchar *orig_rec, const uchar *new_rec) +{ + return _ma_update_block_record2(info, record_pos, orig_rec, new_rec, 0); +} + + /* Delete a directory entry @@ -2848,8 +2908,8 @@ static my_bool delete_head_or_tail(MARIA_HA *info, if (info->s->now_transactional) { /* Log REDO data */ - page_store(log_data+ FILEID_STORE_SIZE, page); - dirpos_store(log_data+ FILEID_STORE_SIZE + PAGE_STORE_SIZE, + page_store(log_data + FILEID_STORE_SIZE, page); + dirpos_store(log_data + FILEID_STORE_SIZE + PAGE_STORE_SIZE, record_number); log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data; @@ -2877,7 +2937,7 @@ static my_bool delete_head_or_tail(MARIA_HA *info, PAGE_STORE_SIZE + PAGERANGE_STORE_SIZE]; LEX_STRING log_array[TRANSLOG_INTERNAL_PARTS + 1]; pagerange_store(log_data + FILEID_STORE_SIZE, 1); - page_store(log_data+ FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE, page); + page_store(log_data + FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE, page); pagerange_store(log_data + FILEID_STORE_SIZE + PAGERANGE_STORE_SIZE + PAGE_STORE_SIZE, 1); log_array[TRANSLOG_INTERNAL_PARTS + 0].str= (char*) log_data; @@ -2975,8 +3035,8 @@ my_bool _ma_delete_block_record(MARIA_HA *info, const uchar *record) /* Write UNDO record */ lsn_store(log_data, info->trn->undo_lsn); - page_store(log_data+ LSN_STORE_SIZE + FILEID_STORE_SIZE, page); - dirpos_store(log_data+ LSN_STORE_SIZE + FILEID_STORE_SIZE + + page_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE, page); + dirpos_store(log_data + LSN_STORE_SIZE + FILEID_STORE_SIZE + PAGE_STORE_SIZE, record_number); info->log_row_parts[TRANSLOG_INTERNAL_PARTS].str= (char*) log_data; @@ -3421,16 +3481,14 @@ int _ma_read_block_record2(MARIA_HA *info, uchar *record, for (end_column= share->columndef + share->base.fields; column < end_column; column++) { - enum en_fieldtype type= (enum en_fieldtype) column->type; + enum en_fieldtype type= column->type; uchar *field_pos= record + column->offset; /* First check if field is present in record */ if ((record[column->null_pos] & column->null_bit) || (cur_row->empty_bits[column->empty_pos] & column->empty_bit)) { - if (type == FIELD_SKIP_ENDSPACE) - bfill(record + column->offset, column->length, ' '); - else - bzero(record + column->offset, column->fill_length); + bfill(record + column->offset, column->fill_length, + type == FIELD_SKIP_ENDSPACE ? ' ' : 0); continue; } switch (type) { @@ -3586,7 +3644,7 @@ err: This function is a simpler version of _ma_read_block_record2() The data about the used pages is stored in info->cur_row. - @return + @return Status @retval 0 ok @retval 1 Error. my_errno contains error number */ @@ -3679,11 +3737,14 @@ static my_bool read_row_extent_info(MARIA_HA *info, uchar *buff, /* Read a record based on record position - SYNOPSIS - _ma_read_block_record() - info Maria handler - record Store record here - record_pos Record position + @fn _ma_read_block_record() + @param info Maria handler + @param record Store record here + @param record_pos Record position + + @return Status + @retval 0 ok + @retval # Error number */ int _ma_read_block_record(MARIA_HA *info, uchar *record, @@ -3702,13 +3763,13 @@ int _ma_read_block_record(MARIA_HA *info, uchar *record, &info->dfile, ma_recordpos_to_page(record_pos), 0, info->buff, info->s->page_type, PAGECACHE_LOCK_LEFT_UNLOCKED, 0))) - DBUG_RETURN(1); + DBUG_RETURN(my_errno); DBUG_ASSERT((buff[PAGE_TYPE_OFFSET] & PAGE_TYPE_MASK) == HEAD_PAGE); if (!(data= get_record_position(buff, block_size, offset, &end_of_data))) { - my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */ DBUG_PRINT("error", ("Wrong directory entry in data block")); - DBUG_RETURN(1); + my_errno= HA_ERR_WRONG_IN_RECORD; /* File crashed */ + DBUG_RETURN(HA_ERR_WRONG_IN_RECORD); } DBUG_RETURN(_ma_read_block_record2(info, record, data, end_of_data)); } @@ -4204,7 +4265,7 @@ static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record, column_pos= record+ column->offset; column_length= column->length; - switch ((enum en_fieldtype) column->type) { + switch (column->type) { case FIELD_CHECK: case FIELD_NORMAL: /* Fixed length field */ case FIELD_ZERO: @@ -4288,7 +4349,7 @@ static size_t fill_insert_undo_parts(MARIA_HA *info, const uchar *record, Fields are stored in same order as the field array. - Number of changed fields (packed) + Offset to changed field data (packed) For each changed field Fieldnumber (packed) @@ -4323,7 +4384,7 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, uchar *old_field_lengths= old_row->field_lengths; uchar *new_field_lengths= new_row->field_lengths; size_t row_length= 0; - uint field_count= 0; + uint field_lengths; LEX_STRING *start_log_parts; my_bool new_column_is_empty; DBUG_ENTER("fill_update_undo_parts"); @@ -4341,7 +4402,6 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, { /* Store changed null bits */ *field_data++= (uchar) 255; /* Special case */ - field_count++; log_parts->str= (char*) oldrec; log_parts->length= share->base.null_bytes; row_length= log_parts->length; @@ -4359,10 +4419,9 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, { field_data= ma_store_length(field_data, (uint) (column - share->columndef)); - field_count++; log_parts->str= (char*) oldrec + column->offset; log_parts->length= column->length; - row_length+= log_parts->length; + row_length+= column->length; log_parts++; } } @@ -4394,7 +4453,6 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, field_data= ma_store_length(field_data, (uint) (column - share->columndef)); field_data= ma_store_length(field_data, 0); - field_count++; continue; } /* @@ -4409,7 +4467,7 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, new_column_pos= newrec + column->offset; old_column_length= new_column_length= column->length; - switch ((enum en_fieldtype) column->type) { + switch (column->type) { case FIELD_CHECK: case FIELD_NORMAL: /* Fixed length field */ case FIELD_ZERO: @@ -4418,6 +4476,8 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, break; case FIELD_VARCHAR: new_column_length--; /* Skip length prefix */ + old_column_pos+= column->fill_length; + new_column_pos+= column->fill_length; /* Fall through */ case FIELD_SKIP_ENDSPACE: /* CHAR */ { @@ -4465,22 +4525,22 @@ static size_t fill_update_undo_parts(MARIA_HA *info, const uchar *oldrec, field_data= ma_store_length(field_data, (uint) (column - share->columndef)); field_data= ma_store_length(field_data, old_column_length); - field_count++; log_parts->str= (char*) old_column_pos; log_parts->length= old_column_length; - row_length+= log_parts->length; + row_length+= old_column_length; log_parts++; } } *log_parts_count= (log_parts - start_log_parts); - /* Store number of fields before the field/field_lengths */ + /* Store length of field length data before the field/field_lengths */ + field_lengths= (field_data - start_field_data); start_log_parts->str= ((char*) (start_field_data - - ma_calc_length_for_store_length(field_count))); - ma_store_length(start_log_parts->str, field_count); + ma_calc_length_for_store_length(field_lengths))); + ma_store_length(start_log_parts->str, field_lengths); start_log_parts->length= (size_t) ((char*) field_data - start_log_parts->str); row_length+= start_log_parts->length; @@ -4864,7 +4924,7 @@ my_bool _ma_apply_undo_row_insert(MARIA_HA *info, LSN undo_lsn, if (translog_write_record(&lsn, LOGREC_CLR_END, info->trn, info, sizeof(log_data), TRANSLOG_INTERNAL_PARTS + 1, log_array, - log_data+ FILEID_STORE_SIZE)) + log_data + FILEID_STORE_SIZE)) goto err; info->s->state.state.records--; @@ -4952,10 +5012,11 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn, else *blob_lengths++= 0; if (share->calc_checksum) - bzero(record + column->offset, column->length); + bfill(record + column->offset, column->fill_length, + column->type == FIELD_SKIP_ENDSPACE ? ' ' : 0); continue; } - switch ((enum en_fieldtype) column->type) { + switch (column->type) { case FIELD_CHECK: case FIELD_NORMAL: /* Fixed length field */ case FIELD_ZERO: @@ -5041,15 +5102,147 @@ my_bool _ma_apply_undo_row_delete(MARIA_HA *info, LSN undo_lsn, } -/* Execute undo of a row update */ +/* + Execute undo of a row update + + @fn _ma_apply_undo_row_update() + + @return Operation status + @retval 0 OK + @retval 1 Error +*/ -my_bool _ma_apply_undo_row_update(MARIA_HA *info __attribute__ ((unused)), - LSN undo_lsn __attribute__ ((unused)), - const uchar *header __attribute__ ((unused)), - size_t length __attribute__ ((unused))) +my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn, + const uchar *header, + size_t header_length __attribute__((unused))) { + ulonglong page; + uint rownr, field_length_header; + MARIA_SHARE *share= info->s; + const uchar *field_length_data, *field_length_data_end; + uchar *current_record, *orig_record; + int error= 1; + MARIA_RECORD_POS record_pos; DBUG_ENTER("_ma_apply_undo_row_update"); - fprintf(stderr, "Undo of row update is not yet done\n"); - exit(1); - DBUG_RETURN(0); + + page= page_korr(header); + rownr= dirpos_korr(header + PAGE_STORE_SIZE); + record_pos= ma_recordpos(page, rownr); + DBUG_PRINT("enter", ("Page: %lu rownr: %u", (ulong) page, rownr)); + + /* + Set header to point to old field values, generated by + fill_update_undo_parts() + */ + header+= PAGE_STORE_SIZE + DIRPOS_STORE_SIZE; + field_length_header= ma_get_length((uchar**) &header); + field_length_data= header; + header+= field_length_header; + field_length_data_end= header; + + /* Allocate buffer for current row & original row */ + if (!(current_record= my_malloc(share->base.reclength * 2, MYF(MY_WME)))) + DBUG_RETURN(1); + orig_record= current_record+ share->base.reclength; + + /* Read current record */ + if (_ma_read_block_record(info, current_record, record_pos)) + goto err; + + if (*field_length_data == 255) + { + /* Bitmap changed */ + field_length_data++; + memcpy(orig_record, header, share->base.null_bytes); + header+= share->base.null_bytes; + } + else + memcpy(orig_record, current_record, share->base.null_bytes); + bitmap_clear_all(&info->changed_fields); + + while (field_length_data < field_length_data_end) + { + uint field_nr= ma_get_length((uchar**) &field_length_data), field_length; + MARIA_COLUMNDEF *column= share->columndef + field_nr; + uchar *orig_field_pos= orig_record + column->offset; + + bitmap_set_bit(&info->changed_fields, field_nr); + if (field_nr >= share->base.fixed_not_null_fields) + { + if (!(field_length= ma_get_length((uchar**) &field_length_data))) + { + /* Null field or empty field */ + bfill(orig_field_pos, column->fill_length, + column->type == FIELD_SKIP_ENDSPACE ? ' ' : 0); + continue; + } + } + else + field_length= column->length; + + switch (column->type) { + case FIELD_CHECK: + case FIELD_NORMAL: /* Fixed length field */ + case FIELD_ZERO: + case FIELD_SKIP_PRESPACE: /* Not packed */ + memcpy(orig_field_pos, header, column->length); + header+= column->length; + break; + case FIELD_SKIP_ZERO: /* Number */ + case FIELD_SKIP_ENDSPACE: /* CHAR */ + { + uint diff; + memcpy(orig_field_pos, header, field_length); + if ((diff= (column->length - field_length))) + bfill(orig_field_pos + column->length - diff, diff, + column->type == FIELD_SKIP_ENDSPACE ? ' ' : 0); + header+= field_length; + } + break; + case FIELD_VARCHAR: + if (column->length <= 256) + { + *orig_field_pos++= (uchar) field_length; + } + else + { + int2store(orig_field_pos, field_length); + orig_field_pos+= 2; + } + memcpy(orig_field_pos, header, field_length); + header+= field_length; + break; + case FIELD_BLOB: + { + uint size_length= column->length - portable_sizeof_char_ptr; + _ma_store_blob_length(orig_field_pos, size_length, field_length); + memcpy_fixed(orig_field_pos + size_length, &header, sizeof(header)); + header+= field_length; + break; + } + default: + DBUG_ASSERT(0); + } + } + copy_not_changed_fields(info, &info->changed_fields, + orig_record, current_record); + + if (share->calc_checksum) + { + info->cur_row.checksum= (*share->calc_checksum)(info, orig_record); + info->state->checksum+= (info->cur_row.checksum - + (*share->calc_checksum)(info, current_record)); + } + + /* + Now records are up to date, execute the update to original values + */ + if (_ma_update_block_record2(info, record_pos, current_record, orig_record, + undo_lsn)) + goto err; + + error= 0; +err: + my_free(current_record, MYF(0)); + DBUG_RETURN(error); } diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index a5e64cb555c..f051dc4518e 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -2165,9 +2165,19 @@ int maria_repair(HA_CHECK *param, register MARIA_HA *info, param->error_printed=1; goto err; } - continue; + /* purecov: begin tested */ + if (block_record) + { + sort_info.new_info->state->records--; + if ((*sort_info.new_info->s->write_record_abort)(sort_info.new_info)) + { + _ma_check_print_error(param,"Couldn't delete duplicate row"); + goto err; + } + continue; + } + /* purecov: end */ } - if (!block_record && _ma_sort_write_record(&sort_param)) goto err; } diff --git a/storage/maria/ma_checksum.c b/storage/maria/ma_checksum.c index 30921ad8213..9076b3ebb86 100644 --- a/storage/maria/ma_checksum.c +++ b/storage/maria/ma_checksum.c @@ -31,6 +31,9 @@ ha_checksum _ma_checksum(MARIA_HA *info, const uchar *record) const uchar *pos= record + column->offset; ulong length; + if (record[column->null_pos] & column->null_bit) + continue; /* Null field */ + switch (column->type) { case FIELD_BLOB: { @@ -45,12 +48,12 @@ ha_checksum _ma_checksum(MARIA_HA *info, const uchar *record) } case FIELD_VARCHAR: { - uint pack_length= HA_VARCHAR_PACKLENGTH(column->length-1); + uint pack_length= column->fill_length; if (pack_length == 1) length= (ulong) *(uchar*) pos; else length= uint2korr(pos); - pos+= pack_length; + pos+= pack_length; /* Skip length information */ break; } default: diff --git a/storage/maria/ma_dynrec.c b/storage/maria/ma_dynrec.c index 52ade04db98..6e13fbcecb6 100644 --- a/storage/maria/ma_dynrec.c +++ b/storage/maria/ma_dynrec.c @@ -1138,10 +1138,14 @@ err: } +/* + @brief Unpacks a record - /* Unpacks a record */ - /* Returns -1 and my_errno =HA_ERR_RECORD_DELETED if reclength isn't */ - /* right. Returns reclength (>0) if ok */ + @return Recordlength + @retval >0 ok + @retval MY_FILE_ERROR (== -1) Error. + my_errno is set to HA_ERR_WRONG_IN_RECORD +*/ ulong _ma_rec_unpack(register MARIA_HA *info, register uchar *to, uchar *from, ulong found_length) @@ -1369,9 +1373,10 @@ void _ma_store_blob_length(uchar *pos,uint pack_length,uint length) part of the record. RETURN - 0 OK - 1 Error + 0 OK + # Error number */ + int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) { @@ -1379,103 +1384,102 @@ int _ma_read_dynamic_record(MARIA_HA *info, uchar *buf, uint b_type; MARIA_BLOCK_INFO block_info; File file; + uchar *to; + uint left_length; DBUG_ENTER("_ma_read_dynamic_record"); - if (filepos != HA_OFFSET_ERROR) + if (filepos == HA_OFFSET_ERROR) + goto err; + + LINT_INIT(to); + LINT_INIT(left_length); + file= info->dfile.file; + block_of_record= 0; /* First block of record is numbered as zero. */ + block_info.second_read= 0; + do { - uchar *to; - uint left_length; - - LINT_INIT(to); - LINT_INIT(left_length); - file= info->dfile.file; - block_of_record= 0; /* First block of record is numbered as zero. */ - block_info.second_read= 0; - do - { - /* A corrupted table can have wrong pointers. (Bug# 19835) */ - if (filepos == HA_OFFSET_ERROR) + /* A corrupted table can have wrong pointers. (Bug# 19835) */ + if (filepos == HA_OFFSET_ERROR) + goto panic; + if (info->opt_flag & WRITE_CACHE_USED && + (info->rec_cache.pos_in_file < filepos + + MARIA_BLOCK_INFO_HEADER_LENGTH) && + flush_io_cache(&info->rec_cache)) + goto err; + info->rec_cache.seek_not_done=1; + if ((b_type= _ma_get_block_info(&block_info, file, filepos)) & + (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | + BLOCK_FATAL_ERROR)) + { + if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED)) + my_errno=HA_ERR_RECORD_DELETED; + goto err; + } + if (block_of_record++ == 0) /* First block */ + { + if (block_info.rec_len > (uint) info->s->base.max_pack_length) goto panic; - if (info->opt_flag & WRITE_CACHE_USED && - (info->rec_cache.pos_in_file < filepos + - MARIA_BLOCK_INFO_HEADER_LENGTH) && - flush_io_cache(&info->rec_cache)) - goto err; - info->rec_cache.seek_not_done=1; - if ((b_type= _ma_get_block_info(&block_info, file, filepos)) & - (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | - BLOCK_FATAL_ERROR)) - { - if (b_type & (BLOCK_SYNC_ERROR | BLOCK_DELETED)) - my_errno=HA_ERR_RECORD_DELETED; - goto err; - } - if (block_of_record++ == 0) /* First block */ - { - if (block_info.rec_len > (uint) info->s->base.max_pack_length) - goto panic; - if (info->s->base.blobs) - { - if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, - block_info.rec_len + - info->s->base.extra_rec_buff_size)) - goto err; - } - to= info->rec_buff; - left_length=block_info.rec_len; - } - if (left_length < block_info.data_len || ! block_info.data_len) - goto panic; /* Wrong linked record */ - /* copy information that is already read */ + if (info->s->base.blobs) { - uint offset= (uint) (block_info.filepos - filepos); - uint prefetch_len= (sizeof(block_info.header) - offset); - filepos+= sizeof(block_info.header); - - if (prefetch_len > block_info.data_len) - prefetch_len= block_info.data_len; - if (prefetch_len) - { - memcpy((uchar*) to, block_info.header + offset, prefetch_len); - block_info.data_len-= prefetch_len; - left_length-= prefetch_len; - to+= prefetch_len; - } + if (_ma_alloc_buffer(&info->rec_buff, &info->rec_buff_size, + block_info.rec_len + + info->s->base.extra_rec_buff_size)) + goto err; } - /* read rest of record from file */ - if (block_info.data_len) + to= info->rec_buff; + left_length=block_info.rec_len; + } + if (left_length < block_info.data_len || ! block_info.data_len) + goto panic; /* Wrong linked record */ + /* copy information that is already read */ + { + uint offset= (uint) (block_info.filepos - filepos); + uint prefetch_len= (sizeof(block_info.header) - offset); + filepos+= sizeof(block_info.header); + + if (prefetch_len > block_info.data_len) + prefetch_len= block_info.data_len; + if (prefetch_len) { - if (info->opt_flag & WRITE_CACHE_USED && - info->rec_cache.pos_in_file < filepos + block_info.data_len && - flush_io_cache(&info->rec_cache)) - goto err; - /* - What a pity that this method is not called 'file_pread' and that - there is no equivalent without seeking. We are at the right - position already. :( - */ - if (info->s->file_read(info, (uchar*) to, block_info.data_len, - filepos, MYF(MY_NABP))) - goto panic; - left_length-=block_info.data_len; - to+=block_info.data_len; + memcpy((uchar*) to, block_info.header + offset, prefetch_len); + block_info.data_len-= prefetch_len; + left_length-= prefetch_len; + to+= prefetch_len; } - filepos= block_info.next_filepos; - } while (left_length); + } + /* read rest of record from file */ + if (block_info.data_len) + { + if (info->opt_flag & WRITE_CACHE_USED && + info->rec_cache.pos_in_file < filepos + block_info.data_len && + flush_io_cache(&info->rec_cache)) + goto err; + /* + What a pity that this method is not called 'file_pread' and that + there is no equivalent without seeking. We are at the right + position already. :( + */ + if (info->s->file_read(info, (uchar*) to, block_info.data_len, + filepos, MYF(MY_NABP))) + goto panic; + left_length-=block_info.data_len; + to+=block_info.data_len; + } + filepos= block_info.next_filepos; + } while (left_length); - info->update|= HA_STATE_AKTIV; /* We have a aktive record */ - fast_ma_writeinfo(info); - DBUG_RETURN(_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) != - MY_FILE_ERROR ? 0 : 1); - } + info->update|= HA_STATE_AKTIV; /* We have a aktive record */ + fast_ma_writeinfo(info); + DBUG_RETURN(_ma_rec_unpack(info,buf,info->rec_buff,block_info.rec_len) != + MY_FILE_ERROR ? 0 : my_errno); + +err: fast_ma_writeinfo(info); - DBUG_RETURN(1); /* Wrong data to read */ + DBUG_RETURN(my_errno); panic: my_errno=HA_ERR_WRONG_IN_RECORD; -err: - VOID(_ma_writeinfo(info,0)); - DBUG_RETURN(1); + goto err; } /* compare unique constraint between stored rows */ @@ -1655,7 +1659,7 @@ err: RETURN 0 OK - != 0 Error + != 0 Error number */ int _ma_read_rnd_dynamic_record(MARIA_HA *info, @@ -1663,7 +1667,7 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, MARIA_RECORD_POS filepos, my_bool skip_deleted_blocks) { - int block_of_record, info_read, save_errno; + int block_of_record, info_read; uint left_len,b_type; uchar *to; MARIA_BLOCK_INFO block_info; @@ -1827,9 +1831,8 @@ int _ma_read_rnd_dynamic_record(MARIA_HA *info, panic: my_errno=HA_ERR_WRONG_IN_RECORD; /* Something is fatal wrong */ err: - save_errno=my_errno; - VOID(_ma_writeinfo(info,0)); - DBUG_RETURN(my_errno=save_errno); + fast_ma_writeinfo(info); + DBUG_RETURN(my_errno); } diff --git a/storage/maria/ma_locking.c b/storage/maria/ma_locking.c index dad4071edf8..190356af76b 100644 --- a/storage/maria/ma_locking.c +++ b/storage/maria/ma_locking.c @@ -387,6 +387,9 @@ int _ma_readinfo(register MARIA_HA *info, int lock_type, int check_keybuffer) /* Every isam-function that uppdates the isam-database MUST end with this request + + NOTES + my_errno is not changed if this succeeds! */ int _ma_writeinfo(register MARIA_HA *info, uint operation) diff --git a/storage/maria/ma_loghandler.c b/storage/maria/ma_loghandler.c index 56c0e1aaef7..24ec2b52e8d 100644 --- a/storage/maria/ma_loghandler.c +++ b/storage/maria/ma_loghandler.c @@ -4901,8 +4901,8 @@ my_bool translog_write_record(LSN *lsn, int rc; uint short_trid= trn->short_id; DBUG_ENTER("translog_write_record"); - DBUG_PRINT("enter", ("type: %u ShortTrID: %u", - (uint) type, (uint)short_trid)); + DBUG_PRINT("enter", ("type: %u ShortTrID: %u rec_len: %lu", + (uint) type, (uint) short_trid, (ulong) rec_len)); if (tbl_info) { @@ -4995,9 +4995,7 @@ my_bool translog_write_record(LSN *lsn, be add */ parts.total_record_length= parts.record_length; - DBUG_PRINT("info", ("record length: %lu %lu", - (ulong) parts.record_length, - (ulong) parts.total_record_length)); + DBUG_PRINT("info", ("record length: %lu", (ulong) parts.record_length)); /* process this parts */ if (!(rc= (log_record_type_descriptor[type].prewrite_hook && diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index 4c623ac56f3..a4085a27b08 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -94,6 +94,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode, int save_errno; uint errpos; MARIA_HA info,*m_info; + my_bitmap_map *changed_fields_bitmap; DBUG_ENTER("maria_clone_internal"); errpos= 0; @@ -120,6 +121,8 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode, &info.first_mbr_key, share->base.max_key_length, &info.maria_rtree_recursion_state, share->have_rtree ? 1024 : 0, + &changed_fields_bitmap, + bitmap_buffer_size(share->base.fields), NullS)) goto err; errpos= 6; @@ -144,6 +147,8 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, int mode, info.errkey= -1; info.page_changed=1; info.keyread_buff= info.buff + share->base.max_key_block_length; + bitmap_init(&info.changed_fields, changed_fields_bitmap, + share->base.fields, 0); if ((*share->init)(&info)) goto err; diff --git a/storage/maria/ma_packrec.c b/storage/maria/ma_packrec.c index ae3920dbb3c..173fafaf73f 100644 --- a/storage/maria/ma_packrec.c +++ b/storage/maria/ma_packrec.c @@ -728,8 +728,8 @@ static uint find_longest_bitstream(uint16 *table, uint16 *end) buf RETURN The buffer to receive the record. RETURN - 0 on success - HA_ERR_WRONG_IN_RECORD or -1 on error + 0 On success + # Error number */ int _ma_read_pack_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) @@ -739,7 +739,7 @@ int _ma_read_pack_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) DBUG_ENTER("maria_read_pack_record"); if (filepos == HA_OFFSET_ERROR) - DBUG_RETURN(-1); /* _search() didn't find record */ + DBUG_RETURN(my_errno); /* _search() didn't find record */ file= info->dfile.file; if (_ma_pack_get_block_info(info, &info->bit_buff, &block_info, @@ -755,7 +755,7 @@ int _ma_read_pack_record(MARIA_HA *info, uchar *buf, MARIA_RECORD_POS filepos) panic: my_errno=HA_ERR_WRONG_IN_RECORD; err: - DBUG_RETURN(-1); + DBUG_RETURN(my_errno); } @@ -1598,14 +1598,14 @@ static int _ma_read_mempack_record(MARIA_HA *info, uchar *buf, DBUG_ENTER("maria_read_mempack_record"); if (filepos == HA_OFFSET_ERROR) - DBUG_RETURN(-1); /* _search() didn't find record */ + DBUG_RETURN(my_errno); /* _search() didn't find record */ if (!(pos= (uchar*) _ma_mempack_get_block_info(info, &info->bit_buff, &block_info, &info->rec_buff, &info->rec_buff_size, (uchar*) share->file_map+ filepos))) - DBUG_RETURN(-1); + DBUG_RETURN(my_errno); DBUG_RETURN(_ma_pack_rec_unpack(info, &info->bit_buff, buf, pos, block_info.rec_len)); } diff --git a/storage/maria/ma_recovery.c b/storage/maria/ma_recovery.c index 5810f8e06fe..d7c67d4bd8a 100644 --- a/storage/maria/ma_recovery.c +++ b/storage/maria/ma_recovery.c @@ -1045,17 +1045,11 @@ prototype_undo_exec_hook(UNDO_ROW_UPDATE) info->trn= trn; info->trn->undo_lsn= lsn_korr(rec->header); - /* - For now we skip the page and directory entry. This is to be used - later when we mark rows as deleted. - */ error= _ma_apply_undo_row_update(info, rec->lsn, log_record_buffer.str + LSN_STORE_SIZE + - FILEID_STORE_SIZE + PAGE_STORE_SIZE + - DIRPOS_STORE_SIZE, + FILEID_STORE_SIZE, rec->record_length - - (LSN_STORE_SIZE + FILEID_STORE_SIZE + - PAGE_STORE_SIZE + DIRPOS_STORE_SIZE)); + (LSN_STORE_SIZE + FILEID_STORE_SIZE)); info->trn= 0; return error; } diff --git a/storage/maria/ma_statrec.c b/storage/maria/ma_statrec.c index b04b858c685..ebfab4fad76 100644 --- a/storage/maria/ma_statrec.c +++ b/storage/maria/ma_statrec.c @@ -183,26 +183,25 @@ int _ma_read_static_record(register MARIA_HA *info, register uchar *record, if (info->opt_flag & WRITE_CACHE_USED && info->rec_cache.pos_in_file <= pos && flush_io_cache(&info->rec_cache)) - return(-1); + return(my_errno); info->rec_cache.seek_not_done=1; /* We have done a seek */ error=info->s->file_read(info,(char*) record,info->s->base.reclength, - pos, MYF(MY_NABP)) != 0; - fast_ma_writeinfo(info); + pos, MYF(MY_NABP)); if (! error) { + fast_ma_writeinfo(info); if (!*record) { - my_errno=HA_ERR_RECORD_DELETED; - return(1); /* Record is deleted */ + /* Record is deleted */ + return ((my_errno=HA_ERR_RECORD_DELETED)); } info->update|= HA_STATE_AKTIV; /* Record is read */ return(0); } - return(-1); /* Error on read */ } fast_ma_writeinfo(info); /* No such record */ - return(-1); + return(my_errno); } @@ -264,13 +263,7 @@ int _ma_read_rnd_static_record(MARIA_HA *info, uchar *buf, if (! cache_read) /* No cacheing */ { - if ((error= _ma_read_static_record(info, buf, filepos))) - { - if (error > 0) - error=my_errno=HA_ERR_RECORD_DELETED; - else - error=my_errno; - } + error= _ma_read_static_record(info, buf, filepos); DBUG_RETURN(error); } diff --git a/storage/maria/ma_test1.c b/storage/maria/ma_test1.c index 4435de0bbdb..3209bbd6975 100644 --- a/storage/maria/ma_test1.c +++ b/storage/maria/ma_test1.c @@ -252,6 +252,9 @@ static int run_test(const char *filename) exit(1); } + if (maria_commit(file) || maria_begin(file)) + goto err; + if (!skip_update) { if (opt_unique) @@ -289,7 +292,7 @@ static int run_test(const char *filename) found=0; while ((error= maria_scan(file,read_record)) == 0) { - if (update_count-- == 0) { VOID(maria_close(file)) ; exit(0) ; } + if (--update_count == 0) { VOID(maria_close(file)) ; exit(0) ; } memcpy(record,read_record,rec_length); update_record(record); if (maria_update(file,read_record,record)) @@ -304,6 +307,18 @@ static int run_test(const char *filename) maria_scan_end(file); } + if (die_in_middle_of_transaction == 2) + { + /* + Ensure we get changed pages and log to disk + As commit record is not done, the undo entries needs to be rolled back. + */ + _ma_flush_table_files(file, MARIA_FLUSH_DATA, FLUSH_RELEASE, + FLUSH_RELEASE); + printf("Dying on request after update without maria_close()\n"); + exit(1); + } + if (!silent) printf("- Reopening file\n"); if (maria_commit(file)) @@ -356,7 +371,7 @@ static int run_test(const char *filename) } } - if (die_in_middle_of_transaction == 2) + if (die_in_middle_of_transaction == 3) { /* Ensure we get changed pages and log to disk diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index e8b53757a53..77a3f55e58f 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -16,8 +16,9 @@ /* This file is included by all internal maria files */ #include "maria.h" /* Structs & some defines */ -#include "myisampack.h" /* packing of keys */ +#include <myisampack.h> /* packing of keys */ #include <my_tree.h> +#include <my_bitmap.h> #ifdef THREAD #include <my_pthread.h> #include <thr_lock.h> @@ -437,6 +438,7 @@ struct st_maria_info PAGECACHE_FILE dfile; /* The datafile */ IO_CACHE rec_cache; /* When cacheing records */ LIST open_list; + MY_BITMAP changed_fields; uint opt_flag; /* Optim. for space/speed */ uint update; /* If file changed since open */ int lastinx; /* Last used index */ diff --git a/storage/maria/maria_read_log.c b/storage/maria/maria_read_log.c index 4057fd51e85..d22df34f14c 100644 --- a/storage/maria/maria_read_log.c +++ b/storage/maria/maria_read_log.c @@ -93,7 +93,8 @@ int main(int argc, char **argv) */ fprintf(stdout, "TRACE of the last maria_read_log\n"); - if (maria_apply_log(lsn, opt_display_and_apply, stdout, TRUE)) + if (maria_apply_log(lsn, opt_display_and_apply, stdout, + opt_display_and_apply)) goto err; fprintf(stdout, "%s: SUCCESS\n", my_progname); |