[Seasar-user:2415] S2.2.7以降S2DBCPでデッドロックが発生することがある
Hikaru Taniguchi
taniguchi
2005年 7月 23日 (土) 13:51:33 JST
たにぐちです。
S2.2.7で S2DBCPのConnectionPoolImplの排他制御が変更されていますが、こ
のバージョン以降、スレッド間でデッドロックが発生することがあるという問
題に遭遇したため、報告とお願いとしてメールさせていただきます。
以下の処理が重なったときに、デッドロックになり、ConnectionPoolImplのイ
ンスタンスおよび TimeoutManagerの保持するリストがロックされ続けるため、
その後checkIn,checkOutが実施できなくなります。
・ConnectionPoolImplの checkIn()がコールされたとき
・TimeoutManagerのrun()で FreeItemのexpired()をコールするとき
上記を言い換えると、おそらく以下のようになるかと思います
・コネクションを論理クローズするとき
・コネクションを物理クローズするとき
前者は、checkIn()がsynchronizedメソッドであるため、ConnectionPoolImpl
インスタンスにロックがかかります。その後、checkIn処理の過程で、
freePoolリストに戻されたコネクションを格納するのですが、このとき
FreeItemクラスのインスタンスを作成し、TimeoutManagerに自身をタイムアウ
ト監視のターゲットとして追加しています。
(FreeItemのコンストラクタ内でTimeoutManager#addTimeoutTarget())
この処理の過程、TimeoutManagerの timeoutTaskList のロックを要求します。
後者は、タイムアウトの監視スレッドで、まず、timeoutTaskListをロックし、
リストのエントリそれぞれに対して、isExpired()で時間切れをチェックし、
期限が切れていれば(=物理コネクションを閉じるべきときがくれば) ターゲッ
トのexpired()をコールします。 ターゲット(=FreeItemインスタンス)は、自
身を ConnectionPoolImplのfreePoolから取り除こうとしますが、このときに
ConnectionPoolImplインスタンスのロックを要求します。
前者、後者のロック順序を示すと
・論理クローズ : ConnectionPoolImpl.this --> timeoutTaskList
・物理クローズ : timeoutTaskList --> ConnectionPoolImpl.this
となり、これが重なるとデッドロックになります。
どこを変えれば解決になるまだ個人的にはアイデアがないため、patchを送れ
なくて申し訳ないです…
次バージョン時にでも対策いただけると助かります。
現在は、"物理コネクションをクローズしない"(=addTimeout...しない)ように
変更して、暫定対策としています。
<以下、S2.2.9でのトレースを貼り付けます>
Found one Java-level deadlock:
=============================
"TP-Processor8":
waiting to lock monitor 0x0809cc84 (object 0x464ff440, a
org.seasar.framework.util.SLinkedList),
which is held by "Thread-8"
"Thread-8":
waiting to lock monitor 0x0809ccf4 (object 0x45602a60, a
org.seasar.extension.dbcp.impl.ConnectionPoolImpl),
which is held by "TP-Processor8"
Java stack information for the threads listed above:
===================================================
"TP-Processor8":
at org.seasar.extension.timer.TimeoutManager.addTimeoutTarget
(TimeoutManager.java:76)
- waiting to lock <0x464ff440> (a org.seasar.framework.util.SLinkedList)
at org.seasar.extension.dbcp.impl.ConnectionPoolImpl$FreeItem.<init>
(ConnectionPoolImpl.java:240)
at org.seasar.extension.dbcp.impl.ConnectionPoolImpl.checkInFreePool
(ConnectionPoolImpl.java:182)
at org.seasar.extension.dbcp.impl.ConnectionPoolImpl.checkIn
(ConnectionPoolImpl.java:177)
- locked <0x45602a60> (a org.seasar.extension.dbcp.impl.ConnectionPoolImpl)
at org.seasar.extension.dbcp.impl.ConnectionWrapperImpl.close
(ConnectionWrapperImpl.java:205)
at org.seasar.framework.util.ConnectionUtil.close
(ConnectionUtil.java:25)
(以下略)
"Thread-8":
at org.seasar.extension.dbcp.impl.ConnectionPoolImpl$FreeItem.expired
(ConnectionPoolImpl.java:253)
- waiting to lock <0x45602a60> (a org.seasar.extension.dbcp.impl.ConnectionPoolImpl)
at org.seasar.extension.timer.TimeoutTask.expired(TimeoutTask.java:59)
at org.seasar.extension.timer.TimeoutManager.run(TimeoutManager.java:54)
- locked <0x464ff440> (a org.seasar.framework.util.SLinkedList)
at java.lang.Thread.run(Thread.java:534)
---------------------------------
--
Hikaru Taniguchi <[E-MAIL ADDRESS DELETED]>
Seasar-user メーリングリストの案内