Bug - Fixed Grey GUI when updating prices.

Veracity

Developer
Staff member
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:

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)
Sure enough, it was hanging waiting to finish that. So, why was the GUI not enabled? We do this in LoginManager:

Code:
		if ( Preferences.getBoolean( "sharePriceData" ) )
		{
			MallPriceDatabase.updatePricesInParallel( "http://kolmafia.us/scripts/updateprices.php?action=getmap" );
		}
Well, gosh - we "update prices in parallel" specifically so we don't hang waiting for it.

Code:
	public static void updatePricesInParallel( String filename )
	{
		RequestThread.runInParallel( new UpdatePricesRunnable( filename ) );
	}
UpdatePricesRunnable simply does "MallPriceDatabase.updatePrices( this.filename );" with that URL. So, why is the GUI still grey?

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 );
			}
		}
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:

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 ) );
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".
 
Top