diff --git a/mysql-test/r/rpl_truncate_7ndb.result b/mysql-test/r/rpl_truncate_7ndb.result index 62ace911e45..602c4d55ac5 100644 --- a/mysql-test/r/rpl_truncate_7ndb.result +++ b/mysql-test/r/rpl_truncate_7ndb.result @@ -32,11 +32,11 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4 master-bin.000001 106 Query 1 223 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB master-bin.000001 223 Query 1 287 BEGIN -master-bin.000001 287 Table_map 1 40 table_id: # (test.t1) -master-bin.000001 327 Table_map 1 98 table_id: # (mysql.ndb_apply_status) -master-bin.000001 385 Write_rows 1 157 table_id: # -master-bin.000001 444 Write_rows 1 195 table_id: # -master-bin.000001 482 Write_rows 1 233 table_id: # flags: STMT_END_F +master-bin.000001 287 Table_map 1 327 table_id: # (test.t1) +master-bin.000001 327 Table_map 1 385 table_id: # (mysql.ndb_apply_status) +master-bin.000001 385 Write_rows 1 444 table_id: # +master-bin.000001 444 Write_rows 1 482 table_id: # +master-bin.000001 482 Write_rows 1 520 table_id: # flags: STMT_END_F master-bin.000001 520 Query 1 585 COMMIT master-bin.000001 585 Query 1 665 use `test`; TRUNCATE TABLE t1 master-bin.000001 665 Query 1 741 use `test`; DROP TABLE t1 @@ -69,27 +69,27 @@ Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 4 Format_desc 1 106 Server ver: SERVER_VERSION, Binlog ver: 4 master-bin.000001 106 Query 1 223 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB master-bin.000001 223 Query 1 287 BEGIN -master-bin.000001 287 Table_map 1 40 table_id: # (test.t1) -master-bin.000001 327 Table_map 1 98 table_id: # (mysql.ndb_apply_status) -master-bin.000001 385 Write_rows 1 157 table_id: # -master-bin.000001 444 Write_rows 1 195 table_id: # -master-bin.000001 482 Write_rows 1 233 table_id: # flags: STMT_END_F +master-bin.000001 287 Table_map 1 327 table_id: # (test.t1) +master-bin.000001 327 Table_map 1 385 table_id: # (mysql.ndb_apply_status) +master-bin.000001 385 Write_rows 1 444 table_id: # +master-bin.000001 444 Write_rows 1 482 table_id: # +master-bin.000001 482 Write_rows 1 520 table_id: # flags: STMT_END_F master-bin.000001 520 Query 1 585 COMMIT master-bin.000001 585 Query 1 665 use `test`; TRUNCATE TABLE t1 master-bin.000001 665 Query 1 741 use `test`; DROP TABLE t1 master-bin.000001 741 Query 1 858 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB master-bin.000001 858 Query 1 922 BEGIN -master-bin.000001 922 Table_map 1 40 table_id: # (test.t1) -master-bin.000001 962 Table_map 1 98 table_id: # (mysql.ndb_apply_status) -master-bin.000001 1020 Write_rows 1 157 table_id: # -master-bin.000001 1079 Write_rows 1 195 table_id: # -master-bin.000001 1117 Write_rows 1 233 table_id: # flags: STMT_END_F +master-bin.000001 922 Table_map 1 962 table_id: # (test.t1) +master-bin.000001 962 Table_map 1 1020 table_id: # (mysql.ndb_apply_status) +master-bin.000001 1020 Write_rows 1 1079 table_id: # +master-bin.000001 1079 Write_rows 1 1117 table_id: # +master-bin.000001 1117 Write_rows 1 1155 table_id: # flags: STMT_END_F master-bin.000001 1155 Query 1 1220 COMMIT master-bin.000001 1220 Query 1 1284 BEGIN -master-bin.000001 1284 Table_map 1 40 table_id: # (test.t1) -master-bin.000001 1324 Table_map 1 98 table_id: # (mysql.ndb_apply_status) -master-bin.000001 1382 Write_rows 1 157 table_id: # -master-bin.000001 1441 Delete_rows 1 191 table_id: # -master-bin.000001 1475 Delete_rows 1 225 table_id: # flags: STMT_END_F +master-bin.000001 1284 Table_map 1 1324 table_id: # (test.t1) +master-bin.000001 1324 Table_map 1 1382 table_id: # (mysql.ndb_apply_status) +master-bin.000001 1382 Write_rows 1 1441 table_id: # +master-bin.000001 1441 Delete_rows 1 1475 table_id: # +master-bin.000001 1475 Delete_rows 1 1509 table_id: # flags: STMT_END_F master-bin.000001 1509 Query 1 1574 COMMIT master-bin.000001 1574 Query 1 1650 use `test`; DROP TABLE t1 diff --git a/sql/log.cc b/sql/log.cc index de5d94a2e93..831066ab401 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3949,65 +3949,111 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log) long val; uchar header[LOG_EVENT_HEADER_LEN]; + /* + The events in the buffer have incorrect end_log_pos data + (relative to beginning of group rather than absolute), + so we'll recalculate them in situ so the binlog is always + correct, even in the middle of a group. This is possible + because we now know the start position of the group (the + offset of this cache in the log, if you will); all we need + to do is to find all event-headers, and add the position of + the group to the end_log_pos of each event. This is pretty + straight forward, except that we read the cache in segments, + so an event-header might end up on the cache-border and get + split. + */ + group= my_b_tell(&log_file); hdr_offs= carry= 0; do { - if (likely(carry > 0)) + + /* + if we only got a partial header in the last iteration, + get the other half now and process a full header. + */ + if (unlikely(carry > 0)) { DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN); + /* assemble both halves */ memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry); + /* fix end_log_pos */ val= uint4korr(&header[LOG_POS_OFFSET]) + group; int4store(&header[LOG_POS_OFFSET], val); + /* write the first half of the split header */ if (my_b_write(&log_file, header, carry)) return ER_ERROR_ON_WRITE; + /* + copy fixed second half of header to cache so the correct + version will be written later. + */ memcpy((char *)cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry); + /* next event header at ... */ hdr_offs = LOG_EVENT_HEADER_LEN - carry + uint4korr(&header[EVENT_LEN_OFFSET]); carry= 0; } + /* if there is anything to write, process it. */ + if(likely(bytes > 0)) { - do { - DBUG_ASSERT((hdr_offs + max(EVENT_LEN_OFFSET, LOG_POS_OFFSET) + 4) <= bytes); + /* + next header beyond current read-buffer? we'll get it later + (though not necessarily in the very next iteration). + */ - val= uint4korr((char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET) + group; - int4store((char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET, val); - hdr_offs += uint4korr((char *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET); + if (hdr_offs >= bytes) + hdr_offs -= bytes; + else + { - /* header beyond current read-buffer? */ - if (hdr_offs >= bytes) - { - hdr_offs -= bytes; - break; - } + /* process all event-headers in this (partial) cache. */ - /* split header? */ - if (hdr_offs + LOG_EVENT_HEADER_LEN > bytes) - { - carry= bytes - hdr_offs; + do { - memcpy(header, (char *)cache->read_pos + hdr_offs, carry); - bytes -= carry; - } + /* + partial header only? save what we can get, process once + we get the rest. + */ - } while (hdr_offs < bytes); + if (hdr_offs + LOG_EVENT_HEADER_LEN > bytes) + { + carry= bytes - hdr_offs; + memcpy(header, (char *)cache->read_pos + hdr_offs, carry); + bytes= hdr_offs; + } + else + { + /* we've got a full event-header, and it came in one piece */ + + uchar *log_pos= cache->read_pos + hdr_offs + LOG_POS_OFFSET; + + /* fix end_log_pos */ + val= uint4korr(log_pos) + group; + int4store(log_pos, val); + + /* next event header at ... */ + log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET; + hdr_offs += uint4korr(log_pos); + + } + } while (hdr_offs < bytes); + } } /* Write data to the binary log file */ - if (my_b_write(&log_file, cache->read_pos, bytes)) return ER_ERROR_ON_WRITE; - cache->read_pos= cache->read_end; - } while ((bytes= my_b_fill(cache))); + cache->read_pos=cache->read_end; // Mark buffer used up + } while ((bytes=my_b_fill(cache))); if (sync_log) flush_and_sync();