2009-06-03 43 views
10

TL; DR: Tôi đã cung cấp bản vá cho một lỗi mà tôi đã tìm thấy và tôi có 0 phản hồi về nó. Tôi tự hỏi nếu nó là một lỗi ở tất cả. Đây không phải là một rant. Xin vui lòng đọc điều này và nếu bạn có thể bị ảnh hưởng bởi nó kiểm tra sửa chữa.Tại sao không ai quan tâm đến lỗi MySQLdb này? nó là một lỗi?

Tôi đã tìm và báo cáo lỗi MySQLdb này cách đây vài tuần (chỉnh sửa: 6 tuần trước), đã gửi một bản vá, đăng trên một vài diễn đàn của ORM, gửi thư cho tác giả MySQLdb, gửi một số người nói về xử lý deadlocks Tác giả ORM và tôi vẫn đang chờ đợi bất kỳ phản hồi nào.

Lỗi này khiến tôi rất đau buồn và giải thích duy nhất tôi có thể tìm thấy trong phản hồi là không ai sử dụng "CHỌN ... CẬP NHẬT" trong python với mysql hoặc đây không phải là lỗi.

Về cơ bản, vấn đề là deadlocks và "khóa chờ thời gian chờ" ngoại lệ KHÔNG được nâng lên khi phát hành "SELECT ... FOR UPDATE" bằng cách sử dụng con trỏ MySQLdb. Thay vào đó, câu lệnh không thành công và trả về một kết quả rỗng, mà bất kỳ ứng dụng nào sẽ hiểu như thể không có hàng nào khớp với nhau.

Tôi đã thử nghiệm phiên bản SVN và nó vẫn bị ảnh hưởng. Thử nghiệm trên các bản cài đặt mặc định của Ubuntu Intrepid, Jaunty và Debian Lenny và những cài đặt này cũng bị ảnh hưởng. Phiên bản hiện tại được cài đặt bởi easy_install (1.2.3c1) bị ảnh hưởng.

Điều này cũng ảnh hưởng đến SQLAlchemy và SQLObject và có lẽ bất kỳ ORM nào đã sử dụng con trỏ MySQLdb cũng bị ảnh hưởng.

Kịch bản này có thể tái tạo một bế tắc sẽ kích hoạt các lỗi (chỉ cần thay đổi user/pass trong get_conn, nó sẽ tạo ra các bảng cần thiết):

import time 
import threading 
import traceback 
import logging 
import MySQLdb 

def get_conn(): 
    return MySQLdb.connect(host='localhost', db='TESTS', 
          user='tito', passwd='testing123') 

class DeadlockTestThread(threading.Thread): 
    def __init__(self, order): 
     super(DeadlockTestThread, self).__init__() 
     self.first_select_done = threading.Event() 
     self.do_the_second_one = threading.Event() 
     self.order = order 

    def log(self, msg): 
     logging.info('%s: %s' % (self.getName(), msg)) 

    def run(self): 
     db = get_conn() 
     c = db.cursor() 
     c.execute('BEGIN;') 
     query = 'SELECT * FROM locktest%i FOR UPDATE;' 
     try: 
      try: 
       c.execute(query % self.order[0]) 
       self.first_select_done.set() 

       self.do_the_second_one.wait() 
       c.execute(query % self.order[1]) 
       self.log('2nd SELECT OK, we got %i rows' % len(c.fetchall())) 

       c.execute('SHOW WARNINGS;') 
       self.log('SHOW WARNINGS: %s' % str(c.fetchall())) 
      except: 
       self.log('Failed! Rolling back') 
       c.execute('ROLLBACK;') 
       raise 
      else: 
       c.execute('COMMIT;') 
     finally: 
      c.close() 
      db.close() 


def init(): 
    db = get_conn() 

    # Create the tables. 
    c = db.cursor() 
    c.execute('DROP TABLE IF EXISTS locktest1;') 
    c.execute('DROP TABLE IF EXISTS locktest2;') 
    c.execute('''CREATE TABLE locktest1 (
        a int(11), PRIMARY KEY(a) 
       ) ENGINE=innodb;''') 
    c.execute('''CREATE TABLE locktest2 (
        a int(11), PRIMARY KEY(a) 
       ) ENGINE=innodb;''') 
    c.close() 

    # Insert some data. 
    c = db.cursor() 
    c.execute('BEGIN;') 
    c.execute('INSERT INTO locktest1 VALUES (123456);') 
    c.execute('INSERT INTO locktest2 VALUES (123456);') 
    c.execute('COMMIT;') 
    c.close() 

    db.close() 

if __name__ == '__main__': 
    logging.basicConfig(level=logging.INFO) 

    init() 

    t1 = DeadlockTestThread(order=[1, 2]) 
    t2 = DeadlockTestThread(order=[2, 1]) 

    t1.start() 
    t2.start() 

    # Wait till both threads did the 1st select. 
    t1.first_select_done.wait() 
    t2.first_select_done.wait() 

    # Let thread 1 continue, it will get wait for the lock 
    # at this point. 
    t1.do_the_second_one.set() 

    # Just make sure thread 1 is waiting for the lock. 
    time.sleep(0.1) 

    # This will trigger the deadlock and thread-2 will 
    # fail silently, getting 0 rows. 
    t2.do_the_second_one.set() 

    t1.join() 
    t2.join() 

Kết quả của hoạt động này trên một MySQLdb chưa được vá là này:

$ python bug_mysqldb_deadlock.py 
INFO:root:Thread-2: 2nd SELECT OK, we got 0 rows 
INFO:root:Thread-2: SHOW WARNINGS: (('Error', 1213L, 'Deadlock found when trying to get lock; try restarting transaction'),) 
INFO:root:Thread-1: 2nd SELECT OK, we got 1 rows 
INFO:root:Thread-1: SHOW WARNINGS:() 

Bạn có thể thấy Thread-2 có 0 hàng từ bảng mà chúng tôi biết có 1 và chỉ phát hành câu lệnh "HIỂN THỊ HIỂN THỊ" bạn có thể thấy điều gì đã xảy ra. Nếu bạn kiểm tra "SHOW ENGINE INNODB STATUS", bạn sẽ thấy dòng này trong nhật ký "*** WE ROLL BACK TRANSACTION (2)", mọi thứ xảy ra sau khi lựa chọn không thành công trên Thread-2 là một giao dịch được phục hồi một nửa.

Sau khi áp dụng các bản vá (kiểm tra vé cho nó, url bên dưới), đây là sản phẩm của chạy kịch bản:

$ python bug_mysqldb_deadlock.py 
INFO:root:Thread-2: Failed! Rolling back 
Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "/usr/lib/python2.4/threading.py", line 442, in __bootstrap 
    self.run() 
    File "bug_mysqldb_deadlock.py", line 33, in run 
    c.execute(query % self.order[1]) 
    File "/home/koba/Desarollo/InetPub/IBSRL/VirtualEnv-1.0-p2.4/lib/python2.4/site-packages/MySQL_python-1.2.2-py2.4-linux-x86_64.egg/MySQLdb/cursors.py", line 178, in execute 
    self.errorhandler(self, exc, value) 
    File "/home/koba/Desarollo/InetPub/IBSRL/VirtualEnv-1.0-p2.4/lib/python2.4/site-packages/MySQL_python-1.2.2-py2.4-linux-x86_64.egg/MySQLdb/connections.py", line 35, in defaulterrorhandler 
    raise errorclass, errorvalue 
OperationalError: (1213, 'Deadlock found when trying to get lock; try restarting transaction') 

INFO:root:Thread-1: 2nd SELECT OK, we got 1 rows 
INFO:root:Thread-1: SHOW WARNINGS:() 

Trong trường hợp này là một ngoại lệ được nâng lên trên Thread-2 và nó cuộn lại đúng.

Vì vậy, ý kiến ​​của bạn là gì ?, đây có phải là lỗi không? không ai quan tâm hay tôi điên à?

Đây là vé tôi mở trên SF: http://sourceforge.net/tracker/index.php?func=detail&aid=2776267&group_id=22307&atid=374932

+2

+1 cho mô tả báo cáo lỗi tốt của bạn –

+8

Tôi hầu như không thấy câu hỏi SO có thể trợ giúp như thế nào ở đây. Nếu bạn có một bản vá làm việc, tốt cho bạn, hãy sử dụng nó. Nhưng đừng quên rằng các nhà phát triển PMNM có một công việc thực sự, một cuộc sống riêng tư, và đôi khi nó chỉ mất thời gian để xử lý các lỗi tồn đọng. Chủ sở hữu đã được thông báo khi bạn gửi báo cáo lỗi, anh ấy đã nhìn thấy thông báo. Imho càng có nhiều bạn phàn nàn, thì ít quan điểm của việc sửa lỗi đã nói sẽ trông hấp dẫn anh ta. Chỉ cần kiên nhẫn. Và ngay cả khi anh ấy sửa lỗi này trong một tháng, hãy cảm ơn. – NicDumZ

+3

Tôi không gửi cùng một người nhiều hơn 1 tin nhắn về chủ đề này. Thay vì làm điều đó tôi hỏi những người khác nhau và lý do tôi hỏi ở đây là để tránh hỏi những người tôi đã làm. Tôi cung cấp một sửa chữa và tôi sẽ yêu một số thông tin phản hồi từ một người có thẩm quyền về vấn đề này để biết nếu nó ok hay không. – Koba

Trả lời

7

Tại sao không ai quan tâm đến MySQLdb lỗi này?

lỗi có thể mất một lúc để ưu tiên, nghiên cứu, xác minh sự cố, tìm sửa chữa, kiểm tra sửa chữa, đảm bảo sửa chữa không làm hỏng bất kỳ điều gì khác. Tôi sẽ đề nghị bạn triển khai một công việc xung quanh, vì nó có thể mất một thời gian để sửa chữa này để đến cho bạn.

+3

Tôi vẫn không hiểu được thiếu phản hồi (0, đây là thực tế là phản ứng đầu tiên mà tôi từng có về chủ đề này). Nó thực sự cảm thấy như không ai đọc nó. Tôi hiện đang sử dụng bản vá tôi đã tải lên vé "worksforme". – Koba

+3

Thật thú vị, mặc dù lỗi của ông đã được báo cáo từ 2009-04-20. Ai đó nên trả lời ít nhất! –

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