sql >> Base de Datos >  >> RDS >> Mysql

MySQL error 1436:Desbordamiento de la pila de subprocesos, con consulta simple

1436 - Desbordamiento de la pila de subprocesos:6136 bytes usados ​​de una pila de 131072 bytes y 128000 bytes necesarios.

El error 1436 corresponde a ER_STACK_OVERRUN_NEED_MORE en el código mysql 5.1:

[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

El código que imprime el error visto está en 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));

De los valores vistos, el margen es 128000 y my_thread_stack_size es 131072.

La única llamada a check_stack_overrun() que intenta reservar 128000 bytes es de:

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);

El valor de STACK_MIN_SIZE es 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.

Hasta ahora, todo funciona como se esperaba para el servidor:

  • el código ejecuta un activador, que se implementa con sp_head::execute.
  • el tiempo de ejecución de MySQL comprueba que hay al menos 128 000 bytes en la pila
  • esta comprobación falla (con razón) y la ejecución del activador finaliza con un error.

La cantidad de pila que necesita la ejecución del disparador de MySQL no depende de la complejidad del disparador en sí, ni del contenido/estructura de las tablas involucradas.

Lo que real la pregunta es, supongo, ¿por qué thread_stack está solo en 128K (131072).

La variable de servidor denominada 'thread_stack' se implementa en C como 'my_thread_stack_size' en 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 es el valor mínimo para este parámetro. El valor predeterminado es DEFAULT_THREAD_STACK, que se define en 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

Entonces, de forma predeterminada, el tamaño de la pila debe ser de 192 K (32 bits) o 256 K (arquitecturas de 64 bits).

Primero, verifique cómo se compiló el binario mysqld, para ver cuál es el valor predeterminado:

[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

En mi sistema, obtuve 256K en una plataforma de 64 bits.

Si hay diferentes valores, tal vez alguien construya el servidor con diferentes opciones de compilación, como -DDEFAULT_THREAD_STACK (o simplemente modificó la fuente)... Me preguntaría de dónde viene el binario en ese caso.

En segundo lugar, verifique my.cnf para los valores predeterminados provistos en el archivo de configuración en sí. Una línea que establece un valor para thread_stack explícitamente (y con un valor bajo) definitivamente causaría el error visto.

Por último, verifique el archivo de registro del servidor en busca de un error como este (consulte sql/mysqld.cc):

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

El código del servidor llama:

  • pthread_attr_setstacksize() para establecer el tamaño de la pila
  • pthread_attr_getstacksize() para verificar cuánta pila tiene realmente un hilo y se queja en el registro si la biblioteca pthread usó menos.

Para resumir, el error se ve porque thread_stack es demasiado pequeño en comparación con los valores predeterminados enviados con el servidor. Esto puede suceder:

  • al hacer compilaciones personalizadas del servidor, con diferentes opciones de compilación
  • al cambiar el valor predeterminado en el archivo my.cnf
  • si algo salió mal en la propia biblioteca pthread (en teoría, al leer el código, nunca lo he visto).

Espero que esto responda la pregunta.

Saludos,-- Marc Alff

Actualización (2014-03-11), para que el "cómo solucionarlo" sea más obvio.

Lo que está sucediendo, con toda probabilidad, es que el valor predeterminado para el archivo thread_stack se cambió en el archivo my.cnf.

Entonces, cómo solucionarlo es trivial, encuentre dónde está configurado thread_stack en el archivo my.cnf y elimine la configuración (confiando en el código del servidor para proporcionar un valor predeterminado decente, para que esto no vuelva a suceder la próxima vez) o aumente la pila tamaño.

Actualización (2021-04-28), verifique de dónde proviene thread_stack:

Utilice la tabla performance_schema.variables_info para saber de dónde viene una determinada variable.

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)

Aquí el valor predeterminado es el valor de fábrica (compilado en el binario mysqld).

Otro ejemplo:

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)

Aquí, thread_stack se establece en el archivo my.cnf informado.

Referencia:

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