Skip to content

Commit ad7ee45

Browse files
committed
Bug #33814188 - Assertion consumption > threshold
- For scenarios where we don't have to source a new block because previous blocks (shared or local) can accomodate a new allocation, we didn't check the per table allocation limit before increasing the number of consumed bytes (returned by consumption()) which caused the number of consumed bytes to overshoot the limit defined by tmp_table_size - This caused a crash the next time source_block was called due to failing the assertion of consumption() <= threshold. - Add a per table size check during each allocation and throw exception if size is exceeded. Change-Id: I90d7374971bdfc1fc178801d0c793382c6ab8a49
1 parent 8a952e2 commit ad7ee45

File tree

2 files changed

+25
-47
lines changed

2 files changed

+25
-47
lines changed

storage/temptable/include/temptable/allocator.h

Lines changed: 24 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,8 @@ class TableResourceMonitor {
189189
*/
190190
template <typename Block_size_policy, typename Block_source_policy>
191191
struct Allocation_scheme {
192-
static Source block_source(size_t block_size,
193-
TableResourceMonitor *table_resource_monitor) {
194-
return Block_source_policy::block_source(block_size,
195-
table_resource_monitor);
192+
static Source block_source(size_t block_size) {
193+
return Block_source_policy::block_source(block_size);
196194
}
197195
static size_t block_size(size_t number_of_blocks, size_t n_bytes_requested) {
198196
return Block_size_policy::block_size(number_of_blocks, n_bytes_requested);
@@ -212,8 +210,7 @@ struct Allocation_scheme {
212210
* tmp_table_size SYSVAR.
213211
* */
214212
struct Prefer_RAM_over_MMAP_policy {
215-
static Source block_source(uint32_t block_size,
216-
TableResourceMonitor * = nullptr) {
213+
static Source block_source(uint32_t block_size) {
217214
if (MemoryMonitor::RAM::consumption() < MemoryMonitor::RAM::threshold()) {
218215
if (MemoryMonitor::RAM::increase(block_size) <=
219216
MemoryMonitor::RAM::threshold()) {
@@ -234,38 +231,6 @@ struct Prefer_RAM_over_MMAP_policy {
234231
}
235232
};
236233

237-
/* Another concrete implementation of Block_source_policy, a type which controls
238-
* where TempTable allocator is going to be allocating next Block of memory
239-
* from. It acts the same as Prefer_RAM_over_MMAP_policy with the main
240-
* difference being that this policy obeys the per-table limit.
241-
*
242-
* What this means is that each temptable::Table is allowed to fit no more data
243-
* than the given threshold controlled through TableResourceMonitor abstraction.
244-
* TableResourceMonitor is a simple abstraction which is in its part an alias
245-
* for tmp_table_size, a system variable that end MySQL users will be using to
246-
* control this threshold.
247-
*
248-
* Updating the tmp_table_size threshold can only be done through the separate
249-
* SET statement which implies that the tmp_table_size threshold cannot be
250-
* updated during the duration of some query which is running within the same
251-
* session. Separate sessions can still of course change this value to their
252-
* liking.
253-
* */
254-
struct Prefer_RAM_over_MMAP_policy_obeying_per_table_limit {
255-
static Source block_source(uint32_t block_size,
256-
TableResourceMonitor *table_resource_monitor) {
257-
assert(table_resource_monitor);
258-
assert(table_resource_monitor->consumption() <=
259-
table_resource_monitor->threshold());
260-
261-
if (table_resource_monitor->consumption() + block_size >
262-
table_resource_monitor->threshold())
263-
throw Result::RECORD_FILE_FULL;
264-
265-
return Prefer_RAM_over_MMAP_policy::block_source(block_size);
266-
}
267-
};
268-
269234
/* Concrete implementation of Block_size_policy, a type which controls how big
270235
* next Block of memory is going to be allocated by TempTable allocator.
271236
*
@@ -314,8 +279,7 @@ struct Exponential_policy {
314279
* over MMAP allocations.
315280
*/
316281
using Exponential_growth_preferring_RAM_over_MMAP =
317-
Allocation_scheme<Exponential_policy,
318-
Prefer_RAM_over_MMAP_policy_obeying_per_table_limit>;
282+
Allocation_scheme<Exponential_policy, Prefer_RAM_over_MMAP_policy>;
319283

320284
/**
321285
Shared state between all instances of a given allocator.
@@ -556,9 +520,8 @@ inline T *Allocator<T, AllocationScheme>::allocate(size_t n_elements) {
556520
if (m_shared_block && m_shared_block->is_empty()) {
557521
const size_t block_size =
558522
AllocationScheme::block_size(0, n_bytes_requested);
559-
*m_shared_block = Block(
560-
block_size,
561-
AllocationScheme::block_source(block_size, &m_table_resource_monitor));
523+
*m_shared_block =
524+
Block(block_size, AllocationScheme::block_source(block_size));
562525
block = m_shared_block;
563526
} else if (m_shared_block &&
564527
m_shared_block->can_accommodate(n_bytes_requested)) {
@@ -567,15 +530,30 @@ inline T *Allocator<T, AllocationScheme>::allocate(size_t n_elements) {
567530
!m_state->current_block.can_accommodate(n_bytes_requested)) {
568531
const size_t block_size = AllocationScheme::block_size(
569532
m_state->number_of_blocks, n_bytes_requested);
570-
m_state->current_block = Block(
571-
block_size,
572-
AllocationScheme::block_source(block_size, &m_table_resource_monitor));
533+
m_state->current_block =
534+
Block(block_size, AllocationScheme::block_source(block_size));
573535
block = &m_state->current_block;
574536
++m_state->number_of_blocks;
575537
} else {
576538
block = &m_state->current_block;
577539
}
578540

541+
/* temptable::Table is allowed to fit no more data than the given threshold
542+
* controlled through TableResourceMonitor abstraction. TableResourceMonitor
543+
* is a simple abstraction which is in its part an alias for tmp_table_size, a
544+
* system variable that end MySQL users will be using to control this
545+
* threshold.
546+
*
547+
* Updating the tmp_table_size threshold can only be done through the separate
548+
* SET statement which implies that the tmp_table_size threshold cannot be
549+
* updated during the duration of some query which is running within the same
550+
* session. Separate sessions can still of course change this value to their
551+
* liking.
552+
*/
553+
if (m_table_resource_monitor.consumption() + n_bytes_requested >
554+
m_table_resource_monitor.threshold()) {
555+
throw Result::RECORD_FILE_FULL;
556+
}
579557
m_table_resource_monitor.increase(n_bytes_requested);
580558

581559
T *chunk_data =

unittest/gunit/temptable_allocator-t.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,7 @@ TEST_F(
625625

626626
try {
627627
// Allocate another chunk
628-
auto chunk3 = allocator.allocate(520_KiB);
628+
auto chunk3 = allocator.allocate(1024_KiB);
629629
(void)chunk3;
630630
} catch (std::exception &) {
631631
EXPECT_TRUE(false);

0 commit comments

Comments
 (0)