#At bzr+ssh://bk-internal.mysql.com/bzrroot/server/mysql-maria/
2659 sanja@stripped 2008-07-23
Fix for BUG#37737.
Fixed prev_last_lsn assignment.
modified:
storage/maria/ma_loghandler.c
per-file messages:
storage/maria/ma_loghandler.c
Fix for BUG#37737:
- buffer flush finish now can be done only in order
- overlay processing fixed (no back direction bufferslocking now)
Fixed prev_last_lsn assignment (now only for new buffer and only under buffer lock protection).
=== modified file 'storage/maria/ma_loghandler.c'
--- a/storage/maria/ma_loghandler.c 2008-07-09 09:02:27 +0000
+++ b/storage/maria/ma_loghandler.c 2008-07-22 23:43:20 +0000
@@ -121,6 +121,8 @@ struct st_translog_buffer
in case of flush by LSN it can be offset + size - TRANSLOG_PAGE_SIZE)
*/
TRANSLOG_ADDRESS next_buffer_offset;
+ /* Previous buffer offset to detect it flush finish */
+ TRANSLOG_ADDRESS prev_buffer_offset;
/*
How much is written (or will be written when copy_to_buffer_in_progress
become 0) to this buffer
@@ -135,12 +137,12 @@ struct st_translog_buffer
/* list of waiting buffer ready threads */
struct st_my_thread_var *waiting_flush;
/*
- Pointer on the buffer which overlap with this one (due to flush of
+ If true then previous buffer overlap with this one (due to flush of
loghandler, the last page of that buffer is the same as the first page
of this buffer) and have to be written first (because contain old
content of page which present in both buffers)
*/
- struct st_translog_buffer *overlay;
+ my_bool overlay;
uint buffer_no;
/*
Lock for the buffer.
@@ -175,6 +177,14 @@ struct st_translog_buffer
With file and offset it allow detect buffer changes
*/
uint8 ver;
+
+ /*
+ When previous buffer sent to disk it set its address here to allow
+ to detect when it is done
+ (we have to keep it in this buffer to lock buffers only in one direction).
+ */
+ TRANSLOG_ADDRESS prev_sent_to_disk;
+ pthread_cond_t prev_sent_to_disk_cond;
};
@@ -1421,9 +1431,12 @@ static my_bool translog_buffer_init(stru
/* list of waiting buffer ready threads */
buffer->waiting_flush= 0;
/* lock for the buffer. Current buffer also lock the handler */
- if (pthread_mutex_init(&buffer->mutex, MY_MUTEX_INIT_FAST))
+ if (pthread_mutex_init(&buffer->mutex, MY_MUTEX_INIT_FAST) ||
+ pthread_cond_init(&buffer->prev_sent_to_disk_cond, 0))
DBUG_RETURN(1);
buffer->is_closing_buffer= 0;
+ buffer->prev_sent_to_disk= LSN_IMPOSSIBLE;
+ buffer->prev_buffer_offset= LSN_IMPOSSIBLE;
buffer->ver= 0;
DBUG_RETURN(0);
}
@@ -2100,10 +2113,12 @@ static my_bool translog_buffer_next(TRAN
{
translog_lock_assert_owner();
translog_start_buffer(new_buffer, cursor, new_buffer_no);
+ new_buffer->prev_buffer_offset=
+ log_descriptor.buffers[old_buffer_no].offset;
+ new_buffer->prev_last_lsn=
+ BUFFER_MAX_LSN(log_descriptor.buffers + old_buffer_no);
}
log_descriptor.buffers[old_buffer_no].next_buffer_offset= new_buffer->offset;
- new_buffer->prev_last_lsn=
- BUFFER_MAX_LSN(log_descriptor.buffers + old_buffer_no);
DBUG_PRINT("info", ("prev_last_lsn set to (%lu,0x%lx) buffer: 0x%lx",
LSN_IN_PARTS(new_buffer->prev_last_lsn),
(ulong) new_buffer));
@@ -2117,14 +2132,16 @@ static my_bool translog_buffer_next(TRAN
SYNOPSIS
translog_set_sent_to_disk()
- lsn LSN to assign
- in_buffers to assign to in_buffers_only
+ buffer buffer which we have sent to disk
TODO: use atomic operations if possible (64bit architectures?)
*/
-static void translog_set_sent_to_disk(LSN lsn, TRANSLOG_ADDRESS in_buffers)
+static void translog_set_sent_to_disk(struct st_translog_buffer *buffer)
{
+ LSN lsn= buffer->last_lsn;
+ TRANSLOG_ADDRESS in_buffers= buffer->next_buffer_offset;
+
DBUG_ENTER("translog_set_sent_to_disk");
pthread_mutex_lock(&log_descriptor.sent_to_disk_lock);
DBUG_PRINT("enter", ("lsn: (%lu,0x%lx) in_buffers: (%lu,0x%lx) "
@@ -2415,6 +2432,51 @@ static uint16 translog_get_total_chunk_l
}
}
+/*
+ @brief Waits previous buffer flush finish
+
+ @param buffer buffer for check
+
+ @retval 0 previous buffer flushed and this thread have to flush this one
+ @retval 1 previous buffer flushed and this buffer flushed by other thread too
+*/
+
+my_bool translog_prev_buffer_flush_wait(struct st_translog_buffer *buffer)
+{
+ TRANSLOG_ADDRESS offset= buffer->offset;
+ TRANSLOG_FILE *file= buffer->file;
+ uint8 ver= buffer->ver;
+ DBUG_ENTER("translog_prev_buffer_flush_wait");
+ DBUG_PRINT("enter", ("buffer: 0x%lx #%u offset: (%lu,0x%lx) "
+ "prev sent: (%lu,0x%lx) prev offset: (%lu,0x%lx)",
+ (ulong) buffer, (uint) buffer->buffer_no,
+ LSN_IN_PARTS(buffer->offset),
+ LSN_IN_PARTS(buffer->prev_sent_to_disk),
+ LSN_IN_PARTS(buffer->prev_buffer_offset)));
+ translog_buffer_lock_assert_owner(buffer);
+ /*
+ if prev_sent_to_disk == LSN_IMPOSSIBLE then
+ prev_buffer_offset should be LSN_IMPOSSIBLE
+ because it means that this buffer was never used
+ */
+ DBUG_ASSERT((buffer->prev_sent_to_disk == LSN_IMPOSSIBLE &&
+ buffer->prev_buffer_offset == LSN_IMPOSSIBLE) ||
+ buffer->prev_sent_to_disk != LSN_IMPOSSIBLE);
+ if (buffer->prev_buffer_offset != buffer->prev_sent_to_disk)
+ {
+ do {
+ pthread_cond_wait(&buffer->prev_sent_to_disk_cond, &buffer->mutex);
+ if (buffer->file != file || buffer->offset != offset ||
+ buffer->ver != ver)
+ {
+ translog_buffer_unlock(buffer);
+ DBUG_RETURN(1); /* some the thread flushed the buffer already */
+ }
+ } while(buffer->prev_buffer_offset != buffer->prev_sent_to_disk);
+ }
+ DBUG_RETURN(0);
+}
+
/*
Flush given buffer
@@ -2460,39 +2522,8 @@ static my_bool translog_buffer_flush(str
if (buffer->file != file || buffer->offset != offset || buffer->ver != ver)
DBUG_RETURN(0); /* some the thread flushed the buffer already */
- if (buffer->overlay && buffer->overlay->file == buffer->file &&
- cmp_translog_addr(buffer->overlay->offset + buffer->overlay->size,
- buffer->offset) > 0)
- {
- /*
- This can't happen for normal translog_flush,
- only during destroying the loghandler
- */
- struct st_translog_buffer *overlay= buffer->overlay;
- TRANSLOG_ADDRESS buffer_offset= buffer->offset;
- TRANSLOG_FILE *fl= buffer->file;
- uint8 ver= buffer->ver;
- translog_buffer_unlock(buffer);
- translog_buffer_lock(overlay);
- /* rechecks under mutex protection that overlay is still our overlay */
- if (buffer->overlay->file == fl &&
- cmp_translog_addr(buffer->overlay->offset + buffer->overlay->size,
- buffer_offset) > 0)
- {
- translog_wait_for_buffer_free(overlay);
- }
- translog_buffer_unlock(overlay);
- translog_buffer_lock(buffer);
- if (buffer->file != fl || buffer_offset != buffer->offset ||
- ver != buffer->ver)
- {
- /*
- This means that somebody else flushed the buffer while we was
- waiting for overlay then for locking buffer again.
- */
- DBUG_RETURN(0);
- }
- }
+ if (buffer->overlay && translog_prev_buffer_flush_wait(buffer))
+ DBUG_RETURN(0); /* some the thread flushed the buffer already */
/*
Send page by page in the pagecache what we are going to write on the
@@ -2553,10 +2584,34 @@ static my_bool translog_buffer_flush(str
file->is_sync= 0;
if (LSN_OFFSET(buffer->last_lsn) != 0) /* if buffer->last_lsn is set */
- translog_set_sent_to_disk(buffer->last_lsn,
- buffer->next_buffer_offset);
+ {
+ if (translog_prev_buffer_flush_wait(buffer))
+ DBUG_RETURN(0); /* some the thread flushed the buffer already */
+ translog_set_sent_to_disk(buffer);
+ }
else
translog_set_only_in_buffers(buffer->next_buffer_offset);
+
+ /* say to next buffer that we are finished */
+ {
+ struct st_translog_buffer *next_buffer=
+ log_descriptor.buffers + ((buffer->buffer_no + 1) % TRANSLOG_BUFFERS_NO);
+ if (likely(translog_status == TRANSLOG_OK)){
+ translog_buffer_lock(next_buffer);
+ next_buffer->prev_sent_to_disk= buffer->offset;
+ translog_buffer_unlock(next_buffer);
+ pthread_cond_broadcast(&next_buffer->prev_sent_to_disk_cond);
+ }
+ else
+ {
+ /*
+ It is shutdown =>
+ 1) there is only one thread
+ 2) mutexes of other buffers can be destroyed => we can't use them
+ */
+ next_buffer->prev_sent_to_disk= buffer->offset;
+ }
+ }
/* Free buffer */
buffer->file= NULL;
buffer->overlay= 0;
@@ -4640,6 +4695,7 @@ static my_bool translog_advance_pointer(
}
translog_start_buffer(new_buffer, &log_descriptor.bc, new_buffer_no);
old_buffer->next_buffer_offset= new_buffer->offset;
+ new_buffer->prev_buffer_offset= old_buffer->offset;
translog_buffer_unlock(old_buffer);
offset-= min_offset;
}
@@ -7355,7 +7411,7 @@ static void translog_force_current_buffe
log_descriptor.bc.ptr+= current_page_fill;
log_descriptor.bc.buffer->size= log_descriptor.bc.current_page_fill=
current_page_fill;
- new_buffer->overlay= old_buffer;
+ new_buffer->overlay= 1;
}
else
translog_new_page_header(&log_descriptor.horizon, &log_descriptor.bc);
@@ -7428,8 +7484,8 @@ static void translog_force_current_buffe
memcpy(new_buffer->buffer, data, current_page_fill);
}
old_buffer->next_buffer_offset= new_buffer->offset;
-
translog_buffer_lock(new_buffer);
+ new_buffer->prev_buffer_offset= old_buffer->offset;
translog_buffer_decrease_writers(new_buffer);
translog_buffer_unlock(new_buffer);
| Thread |
|---|
| • bzr commit into MySQL/Maria:mysql-maria branch (sanja:2659) Bug#37737 | sanja | 23 Jul |