From 4a0c83f59896ef31bae8133fa4d1ae8366d4d1e0 Mon Sep 17 00:00:00 2001 From: Zsolt Parragi Date: Thu, 8 Feb 2018 10:13:07 +0100 Subject: [PATCH] PS-314: issue with 65536+ threads and mdl locks MDL uses the LF_PINS structure for maintaining a global map, which had a 16 bit limitations. After reaching 65535 threads, new threads couldn't access the MDL structures until older threads disconnected. This limitation also caused assertions in the debug builds, stopping the server. This patch changes the 16 bit limitation of the LF_PINS structure to 32 bit. While this solves the problem, it does so with a high memory cost: as the LF_PINS structure uses the LF_DYNARRAY for storing its data, a 1GB array will be allocated when reaching 65536+256+1 threads. 99% of that memory will never be used, as MySQL has a connection limit of 100000, and this array would be enough for 4 billion. As servers with 65k+ connections will use more than 40GB of address space anyway, this shouldn't be an issue, especially as most of it will never be accessed.. --- include/lf.h | 12 ++++++------ mysys/lf_alloc-pin.cc | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/lf.h b/include/lf.h index 4403284a6639..2c090056d5de 100644 --- a/include/lf.h +++ b/include/lf.h @@ -78,19 +78,19 @@ typedef struct { lf_pinbox_free_func *free_func; void *free_func_arg; uint free_ptr_offset; - std::atomic pinstack_top_ver; /* this is a versioned pointer */ - std::atomic pins_in_array; /* number of elements in array */ + std::atomic pinstack_top_ver; /* this is a versioned pointer */ + std::atomicuint64> pins_in_array; /* number of elements in array */ } LF_PINBOX; typedef struct st_lf_pins { std::atomic pin[LF_PINBOX_PINS]; LF_PINBOX *pinbox; void *purgatory; - uint32 purgatory_count; - std::atomic link; + uint64 purgatory_count; + std::atomic link; /* we want sizeof(LF_PINS) to be 64 to avoid false sharing */ -#if SIZEOF_INT*2+SIZEOF_CHARP*(LF_PINBOX_PINS+2) != 64 - char pad[64-sizeof(uint32)*2-sizeof(void*)*(LF_PINBOX_PINS+2)]; +#if 2*8+SIZEOF_CHARP*(LF_PINBOX_PINS+2) != 64 + char pad[64-sizeof(uint64)*2-sizeof(void*)*(LF_PINBOX_PINS+2)]; #endif } LF_PINS; diff --git a/mysys/lf_alloc-pin.cc b/mysys/lf_alloc-pin.cc index 5868d1a42c85..720561744411 100644 --- a/mysys/lf_alloc-pin.cc +++ b/mysys/lf_alloc-pin.cc @@ -114,8 +114,8 @@ static_assert( Pins are given away from a "pinbox". Pinbox is stack-based allocator. It used dynarray for storing pins, new elements are allocated by dynarray as necessary, old are pushed in the stack for reuse. ABA is solved by - versioning a pointer - because we use an array, a pointer to pins is 16 bit, - upper 16 bits are used for a version. + versioning a pointer - because we use an array, a pointer to pins is 32 bit, + upper 32 bits are used for a version. */ #include "lf.h" #include "my_atomic.h" @@ -127,7 +127,7 @@ static_assert( #include "mysql/service_mysql_alloc.h" #include "mysys/mysys_priv.h" /* key_memory_lf_node */ -#define LF_PINBOX_MAX_PINS 65536 +#define LF_PINBOX_MAX_PINS (65536ULL*65536ULL) static void lf_pinbox_real_free(LF_PINS *pins); @@ -165,15 +165,15 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox) */ LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox) { - uint32 pins, next, top_ver; + uint64 pins, next, top_ver; LF_PINS *el; /* We have an array of max. 64k elements. The highest index currently allocated is pinbox->pins_in_array. Freed elements are in a lifo stack, pinstack_top_ver. - pinstack_top_ver is 32 bits; 16 low bits are the index in the - array, to the first element of the list. 16 high bits are a version - (every time the 16 low bits are updated, the 16 high bits are + pinstack_top_ver is 64 bits; 16 low bits are the index in the + array, to the first element of the list. 32 high bits are a version + (every time the 32 low bits are updated, the 32 high bits are incremented). Versioning prevents the ABA problem. */ top_ver= pinbox->pinstack_top_ver; @@ -221,7 +221,7 @@ LF_PINS *lf_pinbox_get_pins(LF_PINBOX *pinbox) void lf_pinbox_put_pins(LF_PINS *pins) { LF_PINBOX *pinbox= pins->pinbox; - uint32 top_ver, nr; + uint64 top_ver, nr; nr= pins->link; #ifndef DBUG_OFF