我通过官方的SQLAnywhere驱动程序将Twisted 11和sqlanydb 12一起使用。
一般来说,它工作得很好。
但有时应用程序在第一次查询时会崩溃并中止。
如果一个查询起作用了,下面的所有查询也会起作用。然而,我的测试很少通过。
这对开发来说很糟糕,strace也没有告诉我任何有用的东西。有时它在select()中崩溃,有时在mmap()中崩溃...
我运行的是64位Linux,并以dbeng12的身份在本地Sybase上运行以进行测试。
是否有人成功地使用了这些组件?有什么建议如何解决这个问题吗?我以前在Django中使用过sqlanydb,它从未崩溃过。
使用打印,我发现它在DeferredList内部崩溃,重要的代码基本上如下:
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_string()崩溃,则不会调用它。
在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发布于 2011-05-04 15:54:21
看起来你的数据库库不是threadsafe。为了使其成为稳定的连接,请执行以下操作:
self.dbpool = ConnectionPool(..., cp_min=1, cp_max=1)这会将最大并发数设置为1,并且ThreadPool将限制为1个线程,这意味着不会同时运行任何查询。这应该会阻止你的非threadsafe库引起任何麻烦,同时仍然在线程中运行查询,并且不会阻塞主循环。
发布于 2011-04-28 00:08:00
是的,你的延迟列表看起来不会像你想要的那样。每个runQuery都将在adbapi线程池中运行,因此不能保证这些查询的顺序。"LAST_UPDATE_SQL“是DeferredList中的最后一件事,并不一定会让它最后发生。延迟列表中的查询是否应该是单个事务的一部分?
由于不知道这里的SQL查询是什么,我假设有时已经为您的LAST_UPDATE_SQL设置了一个事务,有时还没有设置,这取决于这些runQuery最终实际运行的顺序。
下面是如何用一个使用adbapi.runInteraction的adbapi线程替换延迟列表。我不是百分之百地相信这会解决你的问题,但我认为这是编写你想要做的那种数据库交互的正确方式。
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 obviouslyhttps://stackoverflow.com/questions/5790435
复制相似问题