sql >> Database >  >> RDS >> Mysql

MySQL-fout 1436:Thread-stack overschrijding, met eenvoudige query

1436 - Overschrijding threadstack:6136 bytes gebruikt van een stack van 131072 bytes en 128000 bytes nodig.

De fout 1436 komt overeen met ER_STACK_OVERRUN_NEED_MORE in de mysql 5.1-code:

[email protected]:include> pwd
/home/malff/BZR_TREE/mysql-5.1/include
[email protected]:include> grep 1436 mysqld_error.h
#define ER_STACK_OVERRUN_NEED_MORE 1436

De code die de waargenomen fout afdrukt, staat in sql/sql_parse.cc,function check_stack_overrun() :

bool check_stack_overrun(THD *thd, long margin,
                         uchar *buf __attribute__((unused)))
{
  long stack_used;
  DBUG_ASSERT(thd == current_thd);
  if ((stack_used=used_stack(thd->thread_stack,(char*) &stack_used)) >=
      (long) (my_thread_stack_size - margin))
  {
    char ebuff[MYSQL_ERRMSG_SIZE];
    my_snprintf(ebuff, sizeof(ebuff), ER(ER_STACK_OVERRUN_NEED_MORE),
                stack_used, my_thread_stack_size, margin);
    my_message(ER_STACK_OVERRUN_NEED_MORE, ebuff, MYF(ME_FATALERROR));

Van de geziene waarden is de marge 128000 en is my_thread_stack_size 131072.

De enige aanroep naar check_stack_overrun() die 128000 bytes probeert te reserveren is van:

bool
sp_head::execute(THD *thd)
{
  /* Use some extra margin for possible SP recursion and functions */
  if (check_stack_overrun(thd, 8 * STACK_MIN_SIZE, (uchar*)&old_packet))
    DBUG_RETURN(TRUE);

De waarde van STACK_MIN_SIZE is 16000:

[email protected]:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
[email protected]:sql> grep STACK_MIN_SIZE *.h
mysql_priv.h:#define STACK_MIN_SIZE          16000   // Abort if less stack during eval.

Tot nu toe werkt alles zoals verwacht voor de server:

  • de code voert een trigger uit, die wordt geïmplementeerd met sp_head::execute.
  • de MySQL-runtime controleert of er ten minste 128000 bytes op de stapel staan
  • deze controle mislukt (terecht), en de uitvoering van de trigger eindigt met een fout.

De hoeveelheid stack die nodig is voor de uitvoering van de MySQL-trigger is niet afhankelijk van de complexiteit van de trigger zelf, of de inhoud/structuur van de betrokken tabellen.

Wat is het echte de vraag is, denk ik, waarom de thread_stack slechts 128K (131072) is.

De servervariabele met de naam 'thread_stack' is geïmplementeerd in C als 'my_thread_stack_size' in sql/mysqld.cc :

  {"thread_stack", OPT_THREAD_STACK,
   "The stack size for each thread.", &my_thread_stack_size,
   &my_thread_stack_size, 0, GET_ULONG, REQUIRED_ARG,DEFAULT_THREAD_STACK,
   1024L*128L, ULONG_MAX, 0, 1024, 0},

1024L*128L is de minimumwaarde voor deze parameter. De standaardwaarde is DEFAULT_THREAD_STACK, die is gedefinieerd in include/my_pthread.h:

#ifndef DEFAULT_THREAD_STACK
#if SIZEOF_CHARP > 4
/*
  MySQL can survive with 32K, but some glibc libraries require > 128K stack
  To resolve hostnames. Also recursive stored procedures needs stack.
*/
#define DEFAULT_THREAD_STACK    (256*1024L)
#else
#define DEFAULT_THREAD_STACK    (192*1024)
#endif
#endif

De stackgrootte moet dus standaard 192K (32bits) of 256K (64bits architecturen) zijn.

Controleer eerst hoe de mysqld binary is gecompileerd, om te zien wat de standaardwaarde is:

[email protected]:sql> pwd
/home/malff/BZR_TREE/mysql-5.1/sql
[email protected]:sql> ./mysqld --no-defaults --verbose --help | grep thread_stack
...
  --thread_stack=#    The stack size for each thread.
thread_stack                      262144

Op mijn systeem kreeg ik 256K op een 64-bits platform.

Als er verschillende waarden zijn, kan iemand de server misschien bouwen met verschillende compileeropties, zoals -DDEFAULT_THREAD_STACK (of gewoon de bron aanpassen) ... In dat geval zou ik me afvragen waar het binaire bestand vandaan komt.

Ten tweede, controleer my.cnf voor standaardwaarden in het configuratiebestand zelf. Een regel die expliciet een waarde instelt op thread_stack (en met een lage waarde) zou de waargenomen fout definitief veroorzaken.

Controleer als laatste het serverlogbestand op een fout zoals deze (zie sql/mysqld.cc):

sql_print_warning("Asked for %lu thread stack, but got %ld",
                  my_thread_stack_size, (long) stack_size);

De servercode roept:

  • pthread_attr_setstacksize() om de stapelgrootte in te stellen
  • pthread_attr_getstacksize() om te controleren hoeveel stack een thread werkelijk heeft en klaagt in het logboek als de pthread-bibliotheek minder gebruikt.

Om een ​​lang verhaal kort te maken, de fout wordt gezien omdat de thread_stack te klein is in vergelijking met de standaardwaarden die bij de server zijn geleverd. Dit kan gebeuren:

  • bij het maken van aangepaste builds van de server, met verschillende compileeropties
  • bij het wijzigen van de standaardwaarde in het my.cnf-bestand
  • als er iets mis is gegaan in de pthread-bibliotheek zelf (in theorie door het lezen van de code, heb ik het zelf nooit gezien).

Ik hoop dat dit de vraag beantwoordt.

Met vriendelijke groet,-- Marc Alff

Update (2014-03-11), om het "hoe op te lossen" duidelijker te maken.

Wat er naar alle waarschijnlijkheid aan de hand is, is dat de standaardwaarde voor het thread_stack-bestand is gewijzigd in het my.cnf-bestand.

Hoe dit op te lossen is dan triviaal, zoek uit waar thread_stack is ingesteld in het my.cnf-bestand en verwijder de instelling (vertrouw op de servercode om een ​​fatsoenlijke standaardwaarde te bieden, zodat dit de volgende keer niet opnieuw gebeurt) of verhoog de stapel maat.

Update (2021-04-28), controleer waar de thread_stack vandaan komt:

Gebruik tabel performance_schema.variables_info om erachter te komen waar een bepaalde variabele vandaan komt.

mysql> select * from variables_info where VARIABLE_NAME = 'thread_stack';
+---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
| VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH | MIN_VALUE | MAX_VALUE            | SET_TIME | SET_USER | SET_HOST |
+---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
| thread_stack  | COMPILED        |               | 131072    | 18446744073709550592 | NULL     | NULL     | NULL     |
+---------------+-----------------+---------------+-----------+----------------------+----------+----------+----------+
1 row in set (0.01 sec)

Hier is de standaardwaarde de fabriekswaarde (gecompileerd in het binaire mysqld-bestand).

Nog een voorbeeld:

mysql> select * from variables_info where VARIABLE_NAME = 'thread_stack';
+---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
| VARIABLE_NAME | VARIABLE_SOURCE | VARIABLE_PATH                                                  | MIN_VALUE | MAX_VALUE            | SET_TIME | SET_USER | SET_HOST |
+---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
| thread_stack  | EXPLICIT        | /home/malff/CODE/GIT/GIT_TRUNK/build-dbg/mysql-test/var/my.cnf | 131072    | 18446744073709550592 | NULL     | NULL     | NULL     |
+---------------+-----------------+----------------------------------------------------------------+-----------+----------------------+----------+----------+----------+
1 row in set (0.00 sec)

Hier wordt de thread_stack ingesteld in het gerapporteerde my.cnf-bestand.

Refman:

https://dev.mysql .com/doc/refman/8.0/en/performance-schema-variables-info-table.html



  1. SQL juiste join

  2. MySQL omzeilen Kan tabelfout niet heropenen

  3. T-SQL:alle dubbele rijen verwijderen, maar er één behouden

  4. SQLite introduceert de UNIXEPOCH()-functie