Python+Twisted+sqlanydb=abort()

Python+Twisted+sqlanydb=abort(),python,twisted,sqlanywhere,Python,Twisted,Sqlanywhere,我通过官方的sqlanydb驱动程序将Twisted 11与SQLAnywhere 12一起使用 一般来说,它工作得很好 但偶尔应用程序会在第一次查询时中止而崩溃 如果一个查询起作用,那么下面的所有查询也起作用。然而,我的测试很少通过 这是可怕的发展和斯特拉斯没有告诉我任何信息太多。有时它在select内部崩溃,有时在mmap中崩溃 我正在运行64位Linux,并以dbeng12的形式在本地运行Sybase进行测试 是否有人成功使用这些组件?有什么建议可以解决这个问题吗?我以前在Django中使

我通过官方的sqlanydb驱动程序将Twisted 11与SQLAnywhere 12一起使用

一般来说,它工作得很好

但偶尔应用程序会在第一次查询时中止而崩溃

如果一个查询起作用,那么下面的所有查询也起作用。然而,我的测试很少通过

这是可怕的发展和斯特拉斯没有告诉我任何信息太多。有时它在select内部崩溃,有时在mmap中崩溃

我正在运行64位Linux,并以dbeng12的形式在本地运行Sybase进行测试

是否有人成功使用这些组件?有什么建议可以解决这个问题吗?我以前在Django中使用过sqlanydb,但它从未崩溃

通过打印,我发现它在延迟列表中崩溃,重要的代码基本上如下所示:

class WhoisDb(object):
    # ... shortened ...
    def _get_contacts(self, dom):
        if not dom:
            self.d.errback(UnknownDomain(self._get_limit()))
            return
        self.dom = Domain._make(dom[0])

        dl = defer.DeferredList( [
            self.dbpool.runQuery(CON_SQL, (self.dom.dom_owner,)),
            self.dbpool.runQuery(CON_SQL, (self.dom.dom_admin,)),
            self.dbpool.runQuery(CON_SQL, (self.dom.dom_tech,)),
            self.dbpool.runQuery(
                LAST_UPDATE_SQL,
                ( self.dom.domName, )), ] ).addCallback(self._fmt_string)

    def get_whois(self, domain):
        self.d = defer.Deferred()
        if not self._check_limit():
            self.d.errback(LimitExceeded(MAX_PER_HOUR))
        elif not RE_ALLOWED_TLDS.match(domain):
            self.d.errback(UnknownDomain(self._get_limit()))
        else: 
            self.dbpool.runQuery(
                    'select ' + DOM_FIELDS + ' from domains where '
                    'domain = ? or domain_idn = ?',
                    ( domain, domain, )) \
                            .addCallback(self._get_contacts)

        return self.d
_如果fmt_字符串崩溃,则不会调用它

在gdb内部,它是一个简单的SIGSEV:

(gdb) run ~/.virtualenvs/whois/bin/trial test.test_protocol.ProtocolTestCase.test_correct_domain
Starting program: /home/hynek/.virtualenvs/whois/bin/python ~/.virtualenvs/whois/bin/trial test.test_protocol.ProtocolTestCase.test_correct_domain
[Thread debugging using libthread_db enabled]
test.test_protocol
  ProtocolTestCase
    test_correct_domain ... [New Thread 0x7ffff311a700 (LWP 6685)]
[New Thread 0x7ffff3099700 (LWP 6686)]
[New Thread 0x7ffff27dc700 (LWP 6723)]
[New Thread 0x7ffff1fdb700 (LWP 6724)]
[New Thread 0x7ffff17da700 (LWP 6725)]
[New Thread 0x7ffff0fd9700 (LWP 6729)]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff1fdb700 (LWP 6724)]
0x00007ffff4d4167c in ?? () from /opt/sqlanywhere12/lib64/libdbcapi_r.so

是的,你的延期名单看起来不符合你的要求。每个runQuery都将在adbapi线程池中运行,因此无法保证这些查询的顺序。上一次更新SQL作为延迟列表中的最后一件事并不一定会使它最后发生。延迟列表中的查询是否应该是单个事务的一部分

由于不知道这里的SQL查询是什么,我假设有时为您的上一次更新SQL设置了一个事务,有时根据这些runQuery实际运行的顺序没有设置

下面介绍如何使用adbapi.runInteraction将延迟列表替换为单个adbapi线程。我不是100%相信这会解决您的问题,但我认为这是编写您正在尝试的那种数据库交互的正确方法

class WhoisDb(object):
    # ... shortened ...
    def _get_contacts(self, dom):
        if not dom:
            self.d.errback(UnknownDomain(self._get_limit()))
            return
        self.dom = Domain._make(dom[0])

        d = self.dbpool.runInteraction(
                 self._get_stuff_from_db
            )
        d.addCallback(self._fmt_string)
        d.addErrback(self._fmt_string) # don't forget to add an errback!
        return d

    def _get_stuff_from_db(self, cursor):
        cursor.execute(CON_SQL, (self.dom.dom_owner,)),
        cursor.execute(CON_SQL, (self.dom.dom_admin,)),
        cursor.execute(CON_SQL, (self.dom.dom_tech,)),
        cursor.execute(
            LAST_UPDATE_SQL,
            ( self.dom.domName, )), ] )
        return cursor.fetchall() # or whatever you need to return obviously

看起来您的数据库库不是线程安全的。要使其成为稳定连接,请执行以下操作:

self.dbpool = ConnectionPool(..., cp_min=1, cp_max=1)

这将最大并发设置为1,线程池将限制为1个线程,这意味着不会同时运行任何查询。这应该可以防止非线程安全库在线程中运行查询而不阻塞主循环时给您带来任何麻烦。

这可能是由于与数据库的连接陈旧造成的?这是否只是在你的应用程序运行了一段时间(比如说5分钟以上没有任何活动)后才会崩溃?在运行任何查询之前,是否可以尝试检查连接的状态?我也很好奇你是怎么把这个整合到Twisted中的。我可以取消这个资格。在每次设置中,我都会重新启动DB服务器,以防止此类影响。在任何情况下都会立即发生。我在初始化后添加了一个睡眠,以避免可能的竞争考虑,但它没有帮助。有几次你说崩溃,但并不清楚这意味着什么。你也说了流产。这是否意味着这个过程将以SIGABRT结束?如果是这种情况,并且您所要做的就是C堆栈跟踪,请确保您正在查看进程中所有线程中的堆栈。其中一个可能正在调用abort。如果只查看不同线程的堆栈跟踪,这看起来会很神秘和随机。它总是一个中止。我设法得到了一个[unixshm]AttachToSharedMem p=5149 e=\uuuuSqlanycli\uuuu5149\u0C52015id=5 n=o=0 s=4096 d=1 errno=2一旦在试用中失败,我启动了一个共享mem的dbeng12。我在gdb中启动了它,并在上面添加了输出。看起来像是sqlany问题,这是我最初的问题:有人成功使用过它吗还是有什么办法可以让它工作呢?考虑到它在libdbcap_r中崩溃了,所以在我看来,这显然像sqlanywhere中的一个bug。可能是线程安全问题。我希望我能说得更清楚些,但我从来没有在任何地方使用过SQLS。不过,我应该注意,Twisted并不是唯一一个调用select的程序,所以即使是sqlanywhere库也可能在执行其他I/O。感谢您的努力,我按照您的建议进行了尝试,但不幸的是,没有成功。注意:它们不需要位于事务内部,查询是绝对独立的,它们只需要相同的参数。打印显示,中止发生在离开_get_contacts之后,但在从_db输入_get_stuff_之前。另一种允许一次进行多个查询的解决方案是使用ODBC。我写了一篇关于可能遇到的陷阱的文章。