Skip to content

Commit 801deed

Browse files
author
Satya B
committed
Fix for Bug#37408 - Compressed MyISAM files should not require/use mmap()
When compressed myisam files are opened, they are always memory mapped sometimes causing memory swapping problems. When we mmap the myisam compressed tables of size greater than the memory available, the kswapd0 process utilization is very high consuming 30-40% of the cpu. This happens only with linux kernels older than 2.6.9 With newer linux kernels, we don't have this problem of high cpu consumption and this option may not be required. The option 'myisam_mmap_size' is added to limit the amount of memory used for memory mapping of myisam files. This option is not dynamic. The default value on 32 bit system is 4294967295 bytes and on 64 bit system it is 18446744073709547520 bytes. Note: Testcase only tests the option variable. The actual bug has be to tested manually.
1 parent 092f25c commit 801deed

File tree

10 files changed

+78
-5
lines changed

10 files changed

+78
-5
lines changed

include/my_global.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,9 @@ typedef SOCKET_SIZE_TYPE size_socket;
793793
#define DBL_MAX 1.79769313486231470e+308
794794
#define FLT_MAX ((float)3.40282346638528860e+38)
795795
#endif
796+
#ifndef SIZE_T_MAX
797+
#define SIZE_T_MAX (~((size_t) 0))
798+
#endif
796799

797800
#ifndef HAVE_FINITE
798801
#define finite(x) (1.0 / fabs(x) > 0.0)

include/myisam.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,8 @@ extern ulong myisam_bulk_insert_tree_size, myisam_data_pointer_size;
270270
/* usually used to check if a symlink points into the mysql data home */
271271
/* which is normally forbidden */
272272
extern int (*myisam_test_invalid_symlink)(const char *filename);
273+
extern ulonglong myisam_mmap_size, myisam_mmap_used;
274+
extern pthread_mutex_t THR_LOCK_myisam_mmap;
273275

274276
/* Prototypes for myisam-functions */
275277

@@ -315,6 +317,8 @@ extern int mi_delete_all_rows(struct st_myisam_info *info);
315317
extern ulong _mi_calc_blob_length(uint length , const byte *pos);
316318
extern uint mi_get_pointer_length(ulonglong file_length, uint def);
317319

320+
#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for mmap file */
321+
318322
/* this is used to pass to mysql_myisamchk_table -- by Sasha Pachev */
319323

320324
#define MYISAMCHK_REPAIR 1 /* equivalent to myisamchk -r */

myisam/mi_packrec.c

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1499,12 +1499,26 @@ my_bool _mi_memmap_file(MI_INFO *info)
14991499
{
15001500
byte *file_map;
15011501
MYISAM_SHARE *share=info->s;
1502+
my_bool eom;
1503+
15021504
DBUG_ENTER("mi_memmap_file");
15031505

15041506
if (!share->file_map)
15051507
{
15061508
my_off_t data_file_length= share->state.state.data_file_length;
1507-
if (data_file_length > (my_off_t) (~((size_t) 0)) - MEMMAP_EXTRA_MARGIN)
1509+
1510+
if (myisam_mmap_size != SIZE_T_MAX)
1511+
{
1512+
pthread_mutex_lock(&THR_LOCK_myisam_mmap);
1513+
eom= data_file_length > myisam_mmap_size - myisam_mmap_used - MEMMAP_EXTRA_MARGIN;
1514+
if (!eom)
1515+
myisam_mmap_used+= data_file_length + MEMMAP_EXTRA_MARGIN;
1516+
pthread_mutex_unlock(&THR_LOCK_myisam_mmap);
1517+
}
1518+
else
1519+
eom= data_file_length > myisam_mmap_size - MEMMAP_EXTRA_MARGIN;
1520+
1521+
if (eom)
15081522
{
15091523
DBUG_PRINT("warning", ("File is too large for mmap"));
15101524
DBUG_RETURN(0);
@@ -1513,6 +1527,12 @@ my_bool _mi_memmap_file(MI_INFO *info)
15131527
data_file_length + MEMMAP_EXTRA_MARGIN)
15141528
{
15151529
DBUG_PRINT("warning",("File isn't extended for memmap"));
1530+
if (myisam_mmap_size != SIZE_T_MAX)
1531+
{
1532+
pthread_mutex_lock(&THR_LOCK_myisam_mmap);
1533+
myisam_mmap_used-= data_file_length + MEMMAP_EXTRA_MARGIN;
1534+
pthread_mutex_unlock(&THR_LOCK_myisam_mmap);
1535+
}
15161536
DBUG_RETURN(0);
15171537
}
15181538
file_map=(byte*)
@@ -1522,6 +1542,12 @@ my_bool _mi_memmap_file(MI_INFO *info)
15221542
{
15231543
DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
15241544
my_errno=errno;
1545+
if (myisam_mmap_size != SIZE_T_MAX)
1546+
{
1547+
pthread_mutex_lock(&THR_LOCK_myisam_mmap);
1548+
myisam_mmap_used-= data_file_length + MEMMAP_EXTRA_MARGIN;
1549+
pthread_mutex_unlock(&THR_LOCK_myisam_mmap);
1550+
}
15251551
DBUG_RETURN(0);
15261552
}
15271553
share->file_map= file_map;
@@ -1538,6 +1564,13 @@ void _mi_unmap_file(MI_INFO *info)
15381564
VOID(my_munmap(info->s->file_map,
15391565
(size_t) info->s->state.state.data_file_length+
15401566
MEMMAP_EXTRA_MARGIN));
1567+
1568+
if (myisam_mmap_size != SIZE_T_MAX)
1569+
{
1570+
pthread_mutex_lock(&THR_LOCK_myisam_mmap);
1571+
myisam_mmap_used-= info->s->state.state.data_file_length + MEMMAP_EXTRA_MARGIN;
1572+
pthread_mutex_unlock(&THR_LOCK_myisam_mmap);
1573+
}
15411574
}
15421575

15431576

myisam/mi_static.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ ulong myisam_concurrent_insert= 0;
4040
my_off_t myisam_max_temp_length= MAX_FILE_SIZE;
4141
ulong myisam_bulk_insert_tree_size=8192*1024;
4242
ulong myisam_data_pointer_size=4;
43-
43+
ulonglong myisam_mmap_size= SIZE_T_MAX, myisam_mmap_used= 0;
44+
pthread_mutex_t THR_LOCK_myisam_mmap;
4445

4546
static int always_valid(const char *filename __attribute__((unused)))
4647
{

myisam/myisamdef.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,6 @@ typedef struct st_mi_sort_param
428428
#define MI_MAX_BLOCK_LENGTH ((((ulong) 1 << 24)-1) & (~ (ulong) (MI_DYN_ALIGN_SIZE-1)))
429429
#define MI_REC_BUFF_OFFSET ALIGN_SIZE(MI_DYN_DELETE_BLOCK_HEADER+sizeof(uint32))
430430

431-
#define MEMMAP_EXTRA_MARGIN 7 /* Write this as a suffix for file */
432431

433432
#define PACK_TYPE_SELECTED 1 /* Bits in field->pack_type */
434433
#define PACK_TYPE_SPACE_FIELDS 2

mysql-test/r/variables.result

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,3 +904,9 @@ set global server_id =@my_server_id;
904904
set global slow_launch_time =@my_slow_launch_time;
905905
set global storage_engine =@my_storage_engine;
906906
set global thread_cache_size =@my_thread_cache_size;
907+
#
908+
# BUG#37408 - Compressed MyISAM files should not require/use mmap()
909+
#
910+
# Test 'myisam_mmap_size' option is not dynamic
911+
SET @@myisam_mmap_size= 500M;
912+
ERROR HY000: Variable 'myisam_mmap_size' is a read only variable

mysql-test/t/variables.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,3 +765,9 @@ set global slow_launch_time =@my_slow_launch_time;
765765
set global storage_engine =@my_storage_engine;
766766
set global thread_cache_size =@my_thread_cache_size;
767767

768+
--echo #
769+
--echo # BUG#37408 - Compressed MyISAM files should not require/use mmap()
770+
--echo #
771+
--echo # Test 'myisam_mmap_size' option is not dynamic
772+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
773+
SET @@myisam_mmap_size= 500M;

mysys/my_thr_init.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ pthread_key(struct st_my_thread_var, THR_KEY_mysys);
3030
#endif /* USE_TLS */
3131
pthread_mutex_t THR_LOCK_malloc,THR_LOCK_open,
3232
THR_LOCK_lock,THR_LOCK_isam,THR_LOCK_myisam,THR_LOCK_heap,
33-
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads;
33+
THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads,
34+
THR_LOCK_myisam_mmap;
35+
3436
pthread_cond_t THR_COND_threads;
3537
uint THR_thread_count= 0;
3638
uint my_thread_end_wait_time= 5;
@@ -143,6 +145,7 @@ my_bool my_thread_global_init(void)
143145
pthread_mutex_init(&THR_LOCK_lock,MY_MUTEX_INIT_FAST);
144146
pthread_mutex_init(&THR_LOCK_isam,MY_MUTEX_INIT_SLOW);
145147
pthread_mutex_init(&THR_LOCK_myisam,MY_MUTEX_INIT_SLOW);
148+
pthread_mutex_init(&THR_LOCK_myisam_mmap,MY_MUTEX_INIT_FAST);
146149
pthread_mutex_init(&THR_LOCK_heap,MY_MUTEX_INIT_FAST);
147150
pthread_mutex_init(&THR_LOCK_net,MY_MUTEX_INIT_FAST);
148151
pthread_mutex_init(&THR_LOCK_charset,MY_MUTEX_INIT_FAST);
@@ -208,6 +211,7 @@ void my_thread_global_end(void)
208211
pthread_mutex_destroy(&THR_LOCK_lock);
209212
pthread_mutex_destroy(&THR_LOCK_isam);
210213
pthread_mutex_destroy(&THR_LOCK_myisam);
214+
pthread_mutex_destroy(&THR_LOCK_myisam_mmap);
211215
pthread_mutex_destroy(&THR_LOCK_heap);
212216
pthread_mutex_destroy(&THR_LOCK_net);
213217
pthread_mutex_destroy(&THR_LOCK_charset);

sql/mysqld.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4975,7 +4975,8 @@ enum options_mysqld
49754975
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
49764976
OPT_MAX_ERROR_COUNT, OPT_MULTI_RANGE_COUNT, OPT_MYISAM_DATA_POINTER_SIZE,
49774977
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
4978-
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE,
4978+
OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_MMAP_SIZE,
4979+
OPT_MYISAM_SORT_BUFFER_SIZE,
49794980
OPT_MYISAM_STATS_METHOD,
49804981
OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT,
49814982
OPT_NET_READ_TIMEOUT, OPT_NET_WRITE_TIMEOUT,
@@ -6255,6 +6256,10 @@ The minimum value for this variable is 4096.",
62556256
(gptr*) &max_system_variables.myisam_max_sort_file_size, 0,
62566257
GET_ULL, REQUIRED_ARG, (longlong) LONG_MAX, 0, (ulonglong) MAX_FILE_SIZE,
62576258
0, 1024*1024, 0},
6259+
{"myisam_mmap_size", OPT_MYISAM_MMAP_SIZE,
6260+
"Can be used to restrict the total memory used for memory mmaping of myisam files",
6261+
(gptr*) &myisam_mmap_size, (gptr*) &myisam_mmap_size, 0,
6262+
GET_ULL, REQUIRED_ARG, SIZE_T_MAX, MEMMAP_EXTRA_MARGIN, SIZE_T_MAX, 0, 1, 0},
62586263
{"myisam_repair_threads", OPT_MYISAM_REPAIR_THREADS,
62596264
"Number of threads to use when repairing MyISAM tables. The value of 1 disables parallel repair.",
62606265
(gptr*) &global_system_variables.myisam_repair_threads,

sql/set_var.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static byte *get_error_count(THD *thd);
122122
static byte *get_warning_count(THD *thd);
123123
static byte *get_have_innodb(THD *thd);
124124
static byte *get_tmpdir(THD *thd);
125+
static byte *get_myisam_mmap_size(THD *thd);
125126

126127
/*
127128
Variable definition list
@@ -623,6 +624,10 @@ sys_var_thd_bool sys_keep_files_on_create("keep_files_on_create",
623624
&SV::keep_files_on_create);
624625

625626

627+
static sys_var_readonly sys_myisam_mmap_size("myisam_mmap_size",
628+
OPT_GLOBAL,
629+
SHOW_LONGLONG,
630+
get_myisam_mmap_size);
626631

627632

628633
/*
@@ -723,6 +728,7 @@ sys_var *sys_variables[]=
723728
&sys_multi_range_count,
724729
&sys_myisam_data_pointer_size,
725730
&sys_myisam_max_sort_file_size,
731+
&sys_myisam_mmap_size,
726732
&sys_myisam_repair_threads,
727733
&sys_myisam_sort_buffer_size,
728734
&sys_myisam_stats_method,
@@ -1026,6 +1032,7 @@ struct show_var_st init_vars[]= {
10261032
{sys_myisam_data_pointer_size.name, (char*) &sys_myisam_data_pointer_size, SHOW_SYS},
10271033
{sys_myisam_max_sort_file_size.name, (char*) &sys_myisam_max_sort_file_size,
10281034
SHOW_SYS},
1035+
{sys_myisam_mmap_size.name, (char*) &sys_myisam_mmap_size, SHOW_SYS},
10291036
{"myisam_recover_options", (char*) &myisam_recover_options_str, SHOW_CHAR_PTR},
10301037
{sys_myisam_repair_threads.name, (char*) &sys_myisam_repair_threads,
10311038
SHOW_SYS},
@@ -3181,6 +3188,11 @@ static byte *get_tmpdir(THD *thd)
31813188
return (byte*)mysql_tmpdir;
31823189
}
31833190

3191+
static byte *get_myisam_mmap_size(THD *thd)
3192+
{
3193+
return (byte *)&myisam_mmap_size;
3194+
}
3195+
31843196
/****************************************************************************
31853197
Main handling of variables:
31863198
- Initialisation

0 commit comments

Comments
 (0)