The other day, when I was logging in, the GUI never turned green. It looked like I was all the way logged in, but the last line in the gCLI mentioned "updating prices", but the final line, saying how many prices were updated, was not there. "greygui" got me a thread dump which showed this:
Sure enough, it was hanging waiting to finish that. So, why was the GUI not enabled? We do this in LoginManager:
Well, gosh - we "update prices in parallel" specifically so we don't hang waiting for it.
UpdatePricesRunnable simply does "MallPriceDatabase.updatePrices( this.filename );" with that URL. So, why is the GUI still grey?
Turns out that RequestThread.runInParallel() does this:
In other words, it puts the request into a "request sequence". And that is the problem: RequestThread.closeRequestSequence only enables the display if there are no other request sequences.
There are not that many places in KoLmafia where we do RequestThreadrunInParallel:
Well, maybe that is a fair number of places. I believe that almost all of them are for the purpose of doing (somewhat) lengthy operations at the behest of the GUI, but outside of the Swing event thread. The update prices case is probably the only one which actually makes a request over the net and can therefore hang.
We need to simply run that in a Thread which is NOT a "request sequence".
Code:
"Thread-116" prio=5 tid=0x00007fb340899000 nid=0xec07 runnable [0x000000011ba6c000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(SocketInputStream.java:152)
at java.net.SocketInputStream.read(SocketInputStream.java:122)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:273)
at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
- locked <0x0000000783cac6c8> (a java.io.BufferedInputStream)
at sun.net.www.http.ChunkedInputStream.fastRead(ChunkedInputStream.java:244)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:689)
- locked <0x0000000783cac6f0> (a sun.net.www.http.ChunkedInputStream)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:3053)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
- locked <0x0000000783cac7c0> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
- locked <0x0000000783cac7c0> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at net.sourceforge.kolmafia.utilities.FileUtilities.readLine(FileUtilities.java:164)
at net.sourceforge.kolmafia.utilities.FileUtilities.readData(FileUtilities.java:189)
at net.sourceforge.kolmafia.persistence.MallPriceDatabase.updatePrices(MallPriceDatabase.java:100)
at net.sourceforge.kolmafia.persistence.MallPriceDatabase.updatePrices(MallPriceDatabase.java:161)
at net.sourceforge.kolmafia.persistence.MallPriceDatabase$UpdatePricesRunnable.run(MallPriceDatabase.java:188)
at net.sourceforge.kolmafia.RequestThread$ThreadWrappedRunnable.run(RequestThread.java:400)
Code:
if ( Preferences.getBoolean( "sharePriceData" ) )
{
MallPriceDatabase.updatePricesInParallel( "http://kolmafia.us/scripts/updateprices.php?action=getmap" );
}
Code:
public static void updatePricesInParallel( String filename )
{
RequestThread.runInParallel( new UpdatePricesRunnable( filename ) );
}
Turns out that RequestThread.runInParallel() does this:
Code:
public void run()
{
Integer requestId = RequestThread.openRequestSequence();
try
{
this.wrapped.run();
}
catch ( Exception e )
{
StaticEntity.printStackTrace( e );
}
finally
{
RequestThread.closeRequestSequence( requestId );
}
}
There are not that many places in KoLmafia where we do RequestThreadrunInParallel:
Code:
./KoLmafia.java:1919: RequestThread.runInParallel( new PreferencesRunnable() );
./persistence/MallPriceDatabase.java:173: RequestThread.runInParallel( new UpdatePricesRunnable( filename ) );
./request/FightRequest.java:5838: RequestThread.runInParallel( initializeRunner );
./RequestThread.java:65: public static final void runInParallel( final Runnable action )
./RequestThread.java:76: RequestThread.runInParallel( new PostDelayedRequestRunnable( request ) );
./RequestThread.java:104: RequestThread.runInParallel( new ExecuteDelayedMethodRunnable( object, method ) );
./RequestThread.java:170: RequestThread.runInParallel( new ExecuteMethodRunnable( object, method ) );
./svn/SVNManager.java:1417: RequestThread.runInParallel( new Runnable()
./swingui/button/ThreadedButton.java:83: RequestThread.runInParallel( action );
./swingui/button/ThreadedButton.java:117: RequestThread.runInParallel( action );
./swingui/GenericFrame.java:518: RequestThread.runInParallel( new LogoutRunnable() );
./swingui/ItemManageFrame.java:722: RequestThread.runInParallel( new RefreshConcoctionsRunnable( desired ) );
./swingui/listener/HyperlinkAdapter.java:83: RequestThread.runInParallel( new HyperlinkUpdateRunnable( requestPane, location ) );
./swingui/listener/ThreadedListener.java:68: RequestThread.runInParallel( this );
./swingui/listener/ThreadedListener.java:122: RequestThread.runInParallel( this );
./swingui/listener/ThreadedListener.java:148: RequestThread.runInParallel( this );
./swingui/listener/ThreadedListener.java:159: RequestThread.runInParallel( this );
./swingui/listener/ThreadedListener.java:164: RequestThread.runInParallel( this );
./swingui/listener/ThreadedListener.java:183: RequestThread.runInParallel( this );
./swingui/panel/ChoiceOptionsPanel.java:759: RequestThread.runInParallel( new SaveOceanDestinationSettingsRunnable( this ) );
./swingui/panel/DailyDeedsPanel.java:1040: RequestThread.runInParallel( new InitialUpdateRunnable( daily ) );
./swingui/RequestFrame.java:467: RequestThread.runInParallel( new DisplayRequestRunnable( request ) );
./swingui/TabbedChatFrame.java:112: RequestThread.runInParallel( new CloseWindowRunnable( closedTab ) );
We need to simply run that in a Thread which is NOT a "request sequence".