diff options
author | tnurnberg@sin.intern.azundris.com <> | 2007-06-27 08:18:24 +0200 |
---|---|---|
committer | tnurnberg@sin.intern.azundris.com <> | 2007-06-27 08:18:24 +0200 |
commit | 31e98955a5aa1da0fbbd8cfcfc9e9c9c74907e60 (patch) | |
tree | b2e12e93a26fa55ca31b2580ce5fadf193bfbf6e /sql | |
parent | d3ec46f6f5dc6de0bf196008de1a6223c90598d2 (diff) | |
download | mariadb-git-31e98955a5aa1da0fbbd8cfcfc9e9c9c74907e60.tar.gz |
Merge rkalimullin@bk-internal.mysql.com:/home/bk/mysql-5.0-maint
into mysql.com:/home/ram/work/b29079/b29079.5.0
---
Bug #22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB
fix binlog-writing so that end_log_pos is given correctly even
within transactions for both SHOW BINLOG and SHOW MASTER STATUS,
that is as absolute values (from log start) rather than relative
values (from transaction's start).
---
Merge tnurnberg@bk-internal.mysql.com:/home/bk/mysql-5.0-maint
into sin.intern.azundris.com:/home/tnurnberg/22540/50-22540
---
Bug#22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB
end_log_pos data within a transaction are relative to
the start of the transaction rather than absolute.
we fix those groups in situ before writing the log out.
additional comments and handling for groups with very
large single events, as suggested by Guilhem.
---
Merge bk-internal.mysql.com:/home/bk/mysql-5.0-maint
into amd64.(none):/src/bug24732/my50-bug24732
---
Merge maint1.mysql.com:/data/localhome/tsmith/bk/50
into maint1.mysql.com:/data/localhome/tsmith/bk/maint/50
---
Bug#22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB
end_log_pos data within a transaction are relative to
the start of the transaction rather than absolute.
we fix those groups in situ before writing the log out.
additional comments and handling for groups with very
large single events, as suggested by Guilhem.
---
Merge tnurnberg@bk-internal.mysql.com:/home/bk/mysql-5.0-maint
into sin.intern.azundris.com:/home/tnurnberg/22540/50-22540
---
Merge tnurnberg@bk-internal.mysql.com:/home/bk/mysql-5.1-maint
into sin.intern.azundris.com:/home/tnurnberg/22540/51-22540
---
Merge sin.intern.azundris.com:/home/tnurnberg/22540/50-22540
into sin.intern.azundris.com:/home/tnurnberg/22540/51-22540
Diffstat (limited to 'sql')
-rw-r--r-- | sql/log.cc | 92 |
1 files changed, 69 insertions, 23 deletions
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. + */ + + 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); + } + } 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(); |