Skip to content

Commit d8b8258

Browse files
committed
MDEV-26789 log_write_up_to needs mechanism to prevent stalls of async. waiters
Retry write and/or flush, if group_commit_lock::release() indicates that there are async waiters left, and there is no new group commit lead
1 parent 41c66ef commit d8b8258

File tree

3 files changed

+45
-16
lines changed

3 files changed

+45
-16
lines changed

storage/innobase/log/log0log.cc

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -803,6 +803,9 @@ void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key,
803803
return;
804804
}
805805

806+
repeat:
807+
lsn_t ret_lsn1= 0, ret_lsn2= 0;
808+
806809
if (flush_to_disk &&
807810
flush_lock.acquire(lsn, callback) != group_commit_lock::ACQUIRED)
808811
return;
@@ -817,20 +820,32 @@ void log_write_up_to(lsn_t lsn, bool flush_to_disk, bool rotate_key,
817820
log_write(rotate_key);
818821

819822
ut_a(log_sys.write_lsn == write_lsn);
820-
write_lock.release(write_lsn);
823+
ret_lsn1= write_lock.release(write_lsn);
821824
}
822825

823-
if (!flush_to_disk)
824-
return;
825-
826-
/* Flush the highest written lsn.*/
827-
auto flush_lsn = write_lock.value();
828-
flush_lock.set_pending(flush_lsn);
829-
log_write_flush_to_disk_low(flush_lsn);
830-
flush_lock.release(flush_lsn);
826+
if (flush_to_disk)
827+
{
828+
/* Flush the highest written lsn.*/
829+
auto flush_lsn = write_lock.value();
830+
flush_lock.set_pending(flush_lsn);
831+
log_write_flush_to_disk_low(flush_lsn);
832+
ret_lsn2= flush_lock.release(flush_lsn);
833+
834+
log_flush_notify(flush_lsn);
835+
DBUG_EXECUTE_IF("crash_after_log_write_upto", DBUG_SUICIDE(););
836+
}
831837

832-
log_flush_notify(flush_lsn);
833-
DBUG_EXECUTE_IF("crash_after_log_write_upto", DBUG_SUICIDE(););
838+
if (ret_lsn1 || ret_lsn2)
839+
{
840+
/*
841+
There is no new group commit lead, some async waiters could stall.
842+
Rerun log_write_up_to(), to prevent that.
843+
*/
844+
lsn= std::max(ret_lsn1, ret_lsn2);
845+
static const completion_callback dummy{[](void *) {},nullptr};
846+
callback= &dummy;
847+
goto repeat;
848+
}
834849
}
835850

836851
/** Write to the log file up to the last log entry.

storage/innobase/log/log0sync.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,11 @@ group_commit_lock::lock_return_code group_commit_lock::acquire(value_type num, c
274274
return lock_return_code::EXPIRED;
275275
}
276276

277-
void group_commit_lock::release(value_type num)
277+
group_commit_lock::value_type group_commit_lock::release(value_type num)
278278
{
279279
completion_callback callbacks[1000];
280280
size_t callback_count = 0;
281-
281+
value_type ret = 0;
282282
std::unique_lock<std::mutex> lk(m_mtx);
283283
m_lock = false;
284284

@@ -359,6 +359,12 @@ void group_commit_lock::release(value_type num)
359359
{
360360
wakeup_list->m_group_commit_leader=true;
361361
}
362+
else
363+
{
364+
/* Tell the caller that some pending callbacks left, and he should
365+
do something to prevent stalls. This should be a rare situation.*/
366+
ret= m_pending_callbacks[0].first;
367+
}
362368
}
363369

364370
lk.unlock();
@@ -371,6 +377,7 @@ void group_commit_lock::release(value_type num)
371377
next= cur->m_next;
372378
cur->m_sema.wake();
373379
}
380+
return ret;
374381
}
375382

376383
#ifndef DBUG_OFF

storage/innobase/log/log0sync.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,23 @@ It has a state consisting of
3939
4040
Operations supported on this semaphore
4141
42-
1.acquire(num):
42+
1.acquire(num, callback):
4343
- waits until current value exceeds num, or until lock is granted.
44+
if running synchronously (callback is nullptr)
4445
4546
- returns EXPIRED if current_value >= num,
46-
or ACQUIRED, if current_value < num and lock is granted.
47+
or ACQUIRED, if current_value < num and lock is granted,
48+
or CALLBACK_QUEUED, if callback was not nullptr, and function
49+
would otherwise have to wait
4750
4851
2.release(num)
4952
- releases lock
5053
- sets new current value to max(num,current_value)
5154
- releases some threads waiting in acquire()
55+
- executes some callbacks
56+
- might return some lsn, meaning there are some pending
57+
callbacks left, and there is no new group commit lead
58+
(i.e caller must do something to flush those pending callbacks)
5259
5360
3. value()
5461
- read current value
@@ -82,7 +89,7 @@ class group_commit_lock
8289
CALLBACK_QUEUED
8390
};
8491
lock_return_code acquire(value_type num, const completion_callback *cb);
85-
void release(value_type num);
92+
value_type release(value_type num);
8693
value_type value() const;
8794
value_type pending() const;
8895
void set_pending(value_type num);

0 commit comments

Comments
 (0)