Bug #55981 | Assertion failure in file fsp0fsp.c line 3276 | ||
---|---|---|---|
Submitted: | 14 Aug 2010 7:07 | Modified: | 24 Aug 2010 1:27 |
Reporter: | Serge Kozlov | Email Updates: | |
Status: | Duplicate | Impact on me: | |
Category: | MySQL Server: InnoDB storage engine | Severity: | S2 (Serious) |
Version: | 5.6.99-m5 | OS: | Any |
Assigned to: | Assigned Account | CPU Architecture: | Any |
Tags: | assertion, fsp0fsp.c, innodb, nuts |
[14 Aug 2010 7:07]
Serge Kozlov
[14 Aug 2010 7:12]
Serge Kozlov
MTR test case and dump file
Attachment: bug_assert_fsp0fsp.tgz (application/x-gzip, text), 1.30 KiB.
[23 Aug 2010 8:08]
Jimmy Yang
In essential, a rollback of an update on a table contains BLOB field would deallocate external stored data (space, page) for the BLOB: Simply the repro to following steps: mysql> CREATE TABLE t4(c1 int, c2, int, c3 MEDIUMBLOB, PRIMARY KEY(c1)) engine = innodb; mysql> insert into t4 values(1, 2, REPEAT('b', 54903)); Query OK, 1 row affected (30.91 sec) mysql> start transaction; mysql> update t4 set c1 = 3; mysql> rollback; <=== This rollback removes all external stored BLOB mysql> start transaction; mysql> update t4 set c1 = 3; mysql> rollback; <=== Cannot find the page for external field (gdb) c Continuing. InnoDB: Dump of the tablespace extent descriptor: len 40; hex 0000000000000000ffffffff0000ffffffff000000000002aaffffffffffffffffffffffffffffff; asc ; InnoDB: Serious error! InnoDB is trying to free page 4 InnoDB: though it is already marked as free in the tablespace! InnoDB: The tablespace free space info is corrupt. InnoDB: You may need to dump your InnoDB tables and recreate the whole InnoDB: database! InnoDB: Please refer to InnoDB: http://dev.mysql.com/doc/refman/5.1/en/forcing-recovery.html InnoDB: about forcing recovery. ..... 100823 1:03:10 InnoDB: Assertion failure in thread 3000892272 in file /home/jy/work/mysql5.6_1/mysql-next-mr-innodb/storage/innobase/fsp/fsp0fsp.c line 3276 The key for such failure is the deallocation of external stored fields for the original data during the update rollback. More info will be updated.
[23 Aug 2010 10:56]
Jimmy Yang
Here is the detail info of the problem. In short, the external stored blob data is freed in the rollback, while it shouldn't, since the data is inherited from the original row. Such deletion basically delete the original blob data. The reason it is freed is because the BTR_EXTERN_INHERITED_FLAG is not set on the field: In btr_cur_mark_dtuple_inherited_extern(), the status BTR_EXTERN_INHERITED_FLAG is not marked on the field. Thus during rollback when btr_free_externally_stored_field() is called, following condition evaluated to false, and it proceeds to free: btr_free_externally_stored_field() { ... 4572 if (/* There is no external storage data */ 4573 page_no == FIL_NULL 4574 /* This field does not own the externally stored field */ 4575 || (mach_read_from_1(field_ref + BTR_EXTERN_LEN) 4576 & BTR_EXTERN_OWNER_FLAG) 4577 /* Rollback and inherited field */ 4578 || ((rb_ctx == RB_NORMAL || rb_ctx == RB_RECOVERY) 4579 && (mach_read_from_1(field_ref + BTR_EXTERN_LEN) 4580 & BTR_EXTERN_INHERITED_FLAG))) { 4581 4582 /* Do not free */ 4583 mtr_commit(&mtr); <==== Should come in here 4584 4585 return; 4586 } .... } The reason that BTR_EXTERN_INHERITED_FLAG is not marked because function to mark it (btr_cur_mark_dtuple_inherited_extern() is not called at all: row_upd_clust_rec_by_insert() { if (node->upd_ext) { <==== node->upd_ext is NULL /* If we return from a lock wait, for example, we may have extern fields marked as not-owned in entry (marked in the if-branch above). We must unmark them. */ btr_cur_unmark_dtuple_extern_fields(entry); /* We must mark non-updated extern fields in entry as inherited, so that a possible rollback will not free them. */ btr_cur_mark_dtuple_inherited_extern(entry, node->update); } } So in our case, node->upd_ext is NULL. And node->upd_ext can be updated in row_upd_replace(): row_upd_replace() { for (col_no = 0; col_no < n_cols; col_no++) { .... if (dfield_is_ext(dfield) && col->ord_part) { <== in our case, col->ord_part is 0 ext_cols[n_ext_cols++] = col_no; } } if (n_ext_cols) { *ext = row_ext_create(n_ext_cols, ext_cols, row, dict_table_zip_size(table), heap); } else { *ext = NULL; } } 8: dfield_is_ext(dfield) = 1 (gdb) p col->ord_part $106 = 0 As a result node->upd_ext is NULL, btr_cur_mark_dtuple_inherited_extern() is not called to mark BTR_EXTERN_INHERITED_FLAG bit, and during rollback, btr_free_externally_stored_field() frees the external data while it shouldn't. And if the update/rollback is called again, it would find the external data are already freed.
[23 Aug 2010 22:00]
Sunny Bains
Thank you for your bug report. This issue has been committed to our source repository of that product and will be incorporated into the next release. If necessary, you can access the source repository and build the latest available version, including the bug fix. More information about accessing the source trees is available at http://dev.mysql.com/doc/en/installing-source.html
[24 Aug 2010 1:27]
Jimmy Yang
Duplicate of bug #55543
[13 Dec 2010 8:22]
Marko Mäkelä
I would say that this is a duplicate of Bug #55284, which is Bug #55543 fixed more thoroughly.