2

公式の sqlanydb ドライバーを介して Twisted 11 を SQLAnywhere 12 と一緒に使用しています。

一般的に、それはうまくいきます。

ただし、最初のクエリでアプリケーションが異常終了してクラッシュすることがあります。

1 つのクエリが機能した場合、次のすべてのクエリも機能します。ただし、私のテストはめったに実行されません。

それは開発するのがひどいですし、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
4

2 に答える 2

2

データベース ライブラリがスレッドセーフではないようです。接続を安定させるには、次のようにします。

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

これにより、最大同時実行数が 1 に設定され、ThreadPool は 1 スレッドに制限されます。つまり、クエリは同時に実行されません。これにより、スレッドでクエリを実行し、メインループをブロックせずに、スレッドセーフでないライブラリがドラマを引き起こすのを防ぐことができます。

于 2011-05-04T07:54:21.313 に答える
1

ええ、あなたの据え置きリストは、あなたが望むことをしないようです。各 runQuery は adbapi スレッドプールで実行されるため、これらのクエリの順序は保証されません。「LAST_UPDATE_SQL」が DeferredList の最後にあるからといって、それが最後になるとは限りません。遅延リスト内のクエリは、単一のトランザクションの一部であると想定されていますか?

ここにある SQL クエリが正確にはわからないので、LAST_UPDATE_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
于 2011-04-27T16:08:00.093 に答える