[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 メーリングリストの案内