2012-01-11 32 views
23

Tôi đang làm một bản cập nhật rất đơn giản trên một bảng, mà còn gây ra một kích hoạt thực sự đơn giản, và nó mang lại cho tôi những lỗiMySQL lỗi 1436: Chủ đề chồng tràn ngập, với đơn giản truy vấn

#1436 - Thread stack overrun: 6136 bytes used of a 131072 byte stack, and 128000 bytes needed. 

Truy vấn tôi thực hiện :

UPDATE field_values SET value = 'asaf' WHERE field_values.id =1 

Trường giá trị là trường text. Vì vậy, về lý thuyết nó có thể trở nên yên tĩnh lớn. Đó không phải là trường hợp trong tình huống này.

Trigger đó là nhận được thực hiện là:

DELIMITER $$ 
    CREATE TRIGGER field_value_update_trigger BEFORE UPDATE ON community_fields_values 
    FOR EACH ROW BEGIN 
     INSERT INTO user_field_log (user_id, field_id, value) VALUES (NEW.user_id, NEW.field_id, NEW.value); 
    END; 
$$ 
DELIMITER ; 

Tại sao lỗi này hiển thị? Nó không giống như có bất kỳ truy vấn nặng có liên quan. Cũng lưu ý rằng cơ sở dữ liệu là gần như trống rỗng, chỉ cần 2 dòng trong community_fields_values và không có hàng trong phiên bản user_field_log

MySQL: 5.1.44

+0

bạn có thể đăng toàn bộ mã kích hoạt, vui lòng –

+0

@ f00 Tôi đã thêm toàn bộ trình kích hoạt –

+0

Phiên bản MySQL nào? – jan

Trả lời

46

1436 - Ngăn xếp chủ đề vượt quá: 6136 byte được sử dụng trong ngăn xếp 131072 byte và 128000 byte cần thiết.

Lỗi 1436 tương ứng với ER_STACK_OVERRUN_NEED_MORE trong mysql 5.1 mã:

[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 

Mã in lỗi nhìn thấy là trong sql/sql_parse.cc, chức năng 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)); 

Từ các giá trị được thấy, lề là 128000 và my_thread_stack_size là 131072.

Lệnh gọi duy nhất để check_stack_overrun() cố gắng dự trữ 128.000 byte là từ:

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

Giá trị của STACK_MIN_SIZE là 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. 

Cho đến nay, mọi thứ hoạt động như mong đợi cho máy chủ:

  • mã thực thi một kích hoạt , được triển khai với sp_head :: execute.
  • thời gian chạy MySQL kiểm tra rằng có ít nhất 128000 byte trên ngăn xếp
  • kiểm tra này không thành công (đúng như vậy) và việc thực thi kích hoạt kết thúc bằng lỗi.

Lượng ngăn xếp cần thiết bởi việc thực thi kích hoạt MySQL không phụ thuộc vào độ phức tạp của trình kích hoạt, hoặc nội dung/cấu trúc của các bảng liên quan.

Điều gì là thực tế câu hỏi là, tôi đoán, tại sao thread_stack chỉ ở 128K (131072).

Biến máy chủ có tên là 'thread_stack' được thực hiện trong C như 'my_thread_stack_size' trong 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 là giá trị tối thiểu cho tham số này. Giá trị mặc định là DEFAULT_THREAD_STACK, được định nghĩa trong 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 

Vì vậy, theo mặc định, kích thước stack nên được 192K (32bits) hoặc 256K (64bits kiến ​​trúc).

Thứ nhất, kiểm tra như thế nào nhị phân mysqld đã được biên soạn, để xem các giá trị mặc định là gì:

[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 

Trên hệ thống của tôi, tôi có 256K trên một nền tảng 64 bit.

Nếu có giá trị khác nhau, có thể ai đó đang tạo máy chủ với các tùy chọn biên dịch khác nhau, chẳng hạn như -DDEFAULT_THREAD_STACK (hoặc vừa sửa đổi nguồn) ... Tôi sẽ đặt câu hỏi về nhị phân đến từ đâu trong trường hợp đó.

Thứ hai, hãy kiểm tra my.cnf để biết các giá trị mặc định được cung cấp trong chính tệp cấu hình. Một dòng thiết lập một giá trị cho thread_stack một cách rõ ràng (và với một giá trị thấp) chắc chắn sẽ gây ra lỗi nhìn thấy.

ngoái, kiểm tra các tập tin đăng nhập máy chủ cho một lỗi như thế này (xem sql/mysqld.cc):

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

Mã máy chủ gọi:

  • pthread_attr_setstacksize() để thiết lập kích thước ngăn xếp
  • pthread_attr_getstacksize() để xác minh số lượng ngăn xếp mà một chuỗi thực sự có và than phiền trong nhật ký nếu thư viện pthread được sử dụng ít hơn.

Ngắn câu chuyện, lỗi được nhìn thấy bởi vì thread_stack quá nhỏ so với giá trị mặc định được vận chuyển với máy chủ. Điều này có thể xảy ra:

  • khi thực hiện tùy chỉnh xây dựng của máy chủ, với khác nhau biên soạn tùy chọn
  • khi thay đổi giá trị mặc định trong file my.cnf
  • nếu một cái gì đó đã đi sai trong thư viện pthread bản thân (theo lý thuyết từ đọc mã, tôi chưa bao giờ tự mình thấy nó).

Tôi hy vọng điều này sẽ trả lời câu hỏi.

Kính trọng, - Marc Alff

Cập nhật (2014/03/11), để làm cho "làm thế nào để sửa chữa" rõ ràng hơn.

Điều gì đang xảy ra, trong mọi khả năng, là giá trị mặc định cho tệp tin thread_stack đã được thay đổi trong tệp my.cnf.

Cách khắc phục nó là tầm thường, tìm nơi thread_stack được đặt trong tệp my.cnf và xóa cài đặt (tin tưởng mã máy chủ để cung cấp giá trị mặc định, vì vậy điều này không xảy ra lần sau) hoặc tăng kích thước ngăn xếp.

+3

+1, câu trả lời nổi bật! –

+7

Điều này giải thích rất nhiều về "những gì đang xảy ra ở đây". Tuy nhiên, nó làm obfuscates phần "làm thế nào để sửa chữa". –

+0

Tôi cũng nhận được ngăn xếp byte 131072 trên hệ thống EL6 (CentOS6) (64 bit). Câu trả lời tuyệt vời, mặc dù bỏ phiếu của tôi đi cho bài viết khác cung cấp cho một giải pháp ngắn và súc tích cho vấn đề :-) POST-EDIT: thấy rằng một người nào đó thực sự đã có hard_stack thread_stack = 128k trong cấu hình. Có lẽ nó đã được đứng đó trong hơn một thập kỷ :-) – tobixen

29

Mặc dù không phải là một giải pháp, nhưng một sửa chữa nhanh chóng có thể là để tăng kích thước thread_stack bằng cách tăng nó trong my.cnf của bạn:

thread_stack = 256K

là người sử dụng "foo" chỉ ra, đăng mã toàn bộ kích hoạt có thể hữu ích hơn để phát hiện các vấn đề thực sự.

+0

Hoàn hảo cho các quy trình sử dụng một lần, bạn chỉ cần thực hiện một sửa đổi phức tạp và quên đi. – kaay

+4

Trên thực tế, điều này * là * độ phức tạp của trình kích hoạt - giải pháp và kích thước ngăn xếp luồng không liên quan đặc biệt đến nhau và khi ngăn xếp luồng của bạn quá nhỏ, bạn làm cho nó lớn hơn. Bất cứ điều gì dưới 256K trên một hệ thống 64-bit là quá nhỏ. –

Các vấn đề liên quan