スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

sun.misc.Unsafe#parkって何?

Datastoreやmemcacheが固まる時によく出てくる「sun.misc.Unsafe#park」って何だろ?と思ってググってみたら(←なぜか変換できた。ATOKすばらしす)、以下のページによると「Object#wait」みたいなもんらしい。。

http://d.hatena.ne.jp/freebeans/20080509/p1
http://d.hatena.ne.jp/freebeans/20080511/p1

sun.misc.Unsafeのpark(), unpark()メソッドによると、VM作成者は以下の機能を提供する必要があるらしい。

    ・park(boolean isAbsolute, long timeout)が呼び出された場合、呼び出したスレッドを以下のいずれかの条件が成立するまでブロックさせる

       1. 「パーミット」が与えられた(パーミットはunpark()メソッドにより与えられる)
       2. タイムアウト時間が設定されていた場合は、そのタイムアウト時間が経過した(タイムアウトは相対/絶対時間の両方で設定可能)
       3. ほかのスレッドから割り込みが発生した

    ・unpark(Thread t)が呼び出された場合、引数で指定されたスレッドに「パーミット」を与える

     パーミットは蓄積される。つまり、unpark(), park()の順番で呼び出した場合、park()はすぐにリターンする。ただし蓄積数は最大1個までである。(2回以上unpark()を呼び出しても蓄積されない)

動作としてはObjectクラスのwait()とnotify()に近い。

なるほど、つまりスレッドをブロックするためのものなのですね。これをふまえてDatastore等が固まったスタックトレースを見直してみると、

com.google.apphosting.runtime.HardDeadlineExceededError: This request (1e5289f5333d0c9a) started at 2009/09/21 20:35:21.551 UTC and was still executing at 2009/09/21 20:35:51.561 UTC.
	at sun.misc.Unsafe.park(Native Method)
	at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedNanos(Unknown Source)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer.tryAcquireSharedNanos(Unknown Source)
	at java.util.concurrent.CountDownLatch.await(Unknown Source)
	at com.google.net.rpc.util.RpcWaiter.waitForRpcsToFinish(RpcWaiter.java:96)
	at com.google.apphosting.runtime.ApiProxyImpl.doSyncCall(ApiProxyImpl.java:99)
	at com.google.apphosting.runtime.ApiProxyImpl.access$000(ApiProxyImpl.java:36)
	at com.google.apphosting.runtime.ApiProxyImpl$1.run(ApiProxyImpl.java:68)
	at com.google.apphosting.runtime.ApiProxyImpl$1.run(ApiProxyImpl.java:64)
	at java.security.AccessController.doPrivileged(Native Method)
	at com.google.apphosting.runtime.ApiProxyImpl.makeSyncCall(ApiProxyImpl.java:64)

つまり、ApiProxyがmakeSyncCallしてリモート呼び出ししたら、相手から返事を待つためにjava.util.concurrent.CountDownLatchを使って同期してて、このクラスが内部でUnsafe#parkを呼び出してスレッド止めているという仕組みのようです。

結論:要するにDatastore/memcacheサービスからの返事がないのです。