more re-use after timeout

This commit is contained in:
Arndt 2015-10-25 13:39:23 +01:00
parent 723cf90dd2
commit 14a18fd770
6 changed files with 301 additions and 163 deletions

View file

@ -31,6 +31,7 @@ public final class OsmTrack
public MatchedWaypoint endPoint;
public long[] nogoChecksums;
public boolean isDirty;
private static class OsmPathElementHolder
{
@ -38,7 +39,6 @@ public final class OsmTrack
public OsmPathElementHolder nextHolder;
}
public ArrayList<OsmPathElement> nodes = new ArrayList<OsmPathElement>();
private CompactLongMap<OsmPathElementHolder> nodesMap;
@ -56,7 +56,7 @@ public final class OsmTrack
public void buildMap()
{
nodesMap = new CompactLongMap<OsmPathElementHolder>();
for( OsmPathElement node: nodes )
for ( OsmPathElement node : nodes )
{
long id = node.getIdFromPos();
OsmPathElementHolder nh = new OsmPathElementHolder();
@ -64,7 +64,7 @@ public final class OsmTrack
OsmPathElementHolder h = nodesMap.get( id );
if ( h != null )
{
while( h.nextHolder != null )
while (h.nextHolder != null)
{
h = h.nextHolder;
}
@ -82,7 +82,7 @@ public final class OsmTrack
{
ArrayList<String> res = new ArrayList<String>();
MessageData current = null;
for( OsmPathElement n : nodes )
for ( OsmPathElement n : nodes )
{
if ( n.message != null )
{
@ -110,7 +110,9 @@ public final class OsmTrack
/**
* writes the track in binary-format to a file
* @param filename the filename to write to
*
* @param filename
* the filename to write to
*/
public void writeBinary( String filename ) throws Exception
{
@ -118,13 +120,14 @@ public final class OsmTrack
endPoint.writeToStream( dos );
dos.writeInt( nodes.size() );
for( OsmPathElement node: nodes )
for ( OsmPathElement node : nodes )
{
node.writeToStream( dos );
}
dos.writeLong( nogoChecksums[0] );
dos.writeLong( nogoChecksums[1] );
dos.writeLong( nogoChecksums[2] );
dos.writeBoolean( isDirty );
dos.close();
}
@ -148,7 +151,7 @@ public final class OsmTrack
t.endPoint = ep;
int n = dis.readInt();
OsmPathElement last_pe = null;
for( int i=0; i<n; i++ )
for ( int i = 0; i < n; i++ )
{
OsmPathElement pe = OsmPathElement.readFromStream( dis );
pe.origin = last_pe;
@ -164,14 +167,21 @@ public final class OsmTrack
al[0] = dis.readLong();
al[1] = dis.readLong();
al[2] = dis.readLong();
} catch( EOFException eof ) { /* kind of expected */ }
}
catch (EOFException eof) { /* kind of expected */ }
try
{
boolean isDirty = dis.readBoolean();
if ( t != null ) t.isDirty = isDirty;
}
catch (EOFException eof) { /* kind of expected */ }
dis.close();
boolean nogoCheckOk = Math.abs( al[0] - nogoChecksums[0] ) <= 20
&& Math.abs( al[1] - nogoChecksums[1] ) <= 20
&& Math.abs( al[2] - nogoChecksums[2] ) <= 20;
if ( !nogoCheckOk ) return null;
}
catch( Exception e )
catch (Exception e)
{
throw new RuntimeException( "Exception reading rawTrack: " + e );
}
@ -182,7 +192,8 @@ public final class OsmTrack
public void addNodes( OsmTrack t )
{
for( OsmPathElement n : t.nodes ) addNode( n );
for ( OsmPathElement n : t.nodes )
addNode( n );
buildMap();
}
@ -194,7 +205,7 @@ public final class OsmTrack
public OsmPathElement getLink( long n1, long n2 )
{
OsmPathElementHolder h = nodesMap.get( n2 );
while( h != null )
while (h != null)
{
OsmPathElement e1 = h.node.origin;
if ( e1 != null && e1.getIdFromPos() == n1 )
@ -208,11 +219,11 @@ public final class OsmTrack
public void appendTrack( OsmTrack t )
{
for( int i=0; i<t.nodes.size(); i++ )
for ( int i = 0; i < t.nodes.size(); i++ )
{
if ( i > 0 || nodes.size() == 0 )
{
nodes.add( t.nodes.get(i) );
nodes.add( t.nodes.get( i ) );
}
}
distance += t.distance;
@ -228,7 +239,9 @@ public final class OsmTrack
/**
* writes the track in gpx-format to a file
* @param filename the filename to write to
*
* @param filename
* the filename to write to
*/
public void writeGpx( String filename ) throws Exception
{
@ -240,14 +253,16 @@ public final class OsmTrack
public String formatAsGpx()
{
StringBuilder sb = new StringBuilder(8192);
StringBuilder sb = new StringBuilder( 8192 );
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
for( int i=messageList.size()-1; i >= 0; i-- )
for ( int i = messageList.size() - 1; i >= 0; i-- )
{
String message = messageList.get(i);
if ( i < messageList.size()-1 ) message = "(alt-index " + i + ": " + message + " )";
if ( message != null ) sb.append("<!-- ").append(message).append(" -->\n");
String message = messageList.get( i );
if ( i < messageList.size() - 1 )
message = "(alt-index " + i + ": " + message + " )";
if ( message != null )
sb.append( "<!-- " ).append( message ).append( " -->\n" );
}
sb.append( "<gpx \n" );
sb.append( " xmlns=\"http://www.topografix.com/GPX/1/1\" \n" );
@ -255,13 +270,14 @@ public final class OsmTrack
sb.append( " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\" \n" );
sb.append( " creator=\"BRouter-1.3.1\" version=\"1.1\">\n" );
sb.append( " <trk>\n" );
sb.append(" <name>").append(name).append("</name>\n");
sb.append( " <name>" ).append( name ).append( "</name>\n" );
sb.append( " <trkseg>\n" );
for( OsmPathElement n : nodes )
for ( OsmPathElement n : nodes )
{
String sele = n.getSElev() == Short.MIN_VALUE ? "" : "<ele>" + n.getElev() + "</ele>";
sb.append(" <trkpt lon=\"").append(formatPos(n.getILon() - 180000000)).append("\" lat=\"").append(formatPos(n.getILat() - 90000000)).append("\">").append(sele).append("</trkpt>\n");
sb.append( " <trkpt lon=\"" ).append( formatPos( n.getILon() - 180000000 ) ).append( "\" lat=\"" )
.append( formatPos( n.getILat() - 90000000 ) ).append( "\">" ).append( sele ).append( "</trkpt>\n" );
}
sb.append( " </trkseg>\n" );
@ -281,7 +297,7 @@ public final class OsmTrack
public String formatAsKml()
{
StringBuilder sb = new StringBuilder(8192);
StringBuilder sb = new StringBuilder( 8192 );
sb.append( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
@ -304,10 +320,9 @@ public final class OsmTrack
sb.append( " <tessellate>1</tessellate>\n" );
sb.append( " <coordinates> " );
for( OsmPathElement n : nodes )
for ( OsmPathElement n : nodes )
{
sb.append(formatPos(n.getILon() - 180000000)).append(",").append(formatPos(n.getILat() - 90000000)).append("\n");
sb.append( formatPos( n.getILon() - 180000000 ) ).append( "," ).append( formatPos( n.getILat() - 90000000 ) ).append( "\n" );
}
sb.append( " </coordinates>\n" );
@ -324,7 +339,7 @@ public final class OsmTrack
public String formatAsGeoJson()
{
StringBuilder sb = new StringBuilder(8192);
StringBuilder sb = new StringBuilder( 8192 );
sb.append( "{\n" );
sb.append( " \"type\": \"FeatureCollection\",\n" );
@ -339,10 +354,10 @@ public final class OsmTrack
sb.append( " \"plain-ascend\": \"" ).append( plainAscend ).append( "\",\n" );
sb.append( " \"cost\": \"" ).append( cost ).append( "\",\n" );
sb.append( " \"messages\": [\n" );
sb.append( " [\"").append( MESSAGES_HEADER.replaceAll("\t", "\", \"") ).append( "\"],\n" );
for( String m : aggregateMessages() )
sb.append( " [\"" ).append( MESSAGES_HEADER.replaceAll( "\t", "\", \"" ) ).append( "\"],\n" );
for ( String m : aggregateMessages() )
{
sb.append( " [\"").append( m.replaceAll("\t", "\", \"") ).append( "\"],\n" );
sb.append( " [\"" ).append( m.replaceAll( "\t", "\", \"" ) ).append( "\"],\n" );
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
sb.append( " ]\n" );
@ -352,9 +367,9 @@ public final class OsmTrack
if ( iternity != null )
{
sb.append( " \"iternity\": [\n" );
for( String s : iternity )
for ( String s : iternity )
{
sb.append( " \"").append( s ).append( "\",\n" );
sb.append( " \"" ).append( s ).append( "\",\n" );
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
sb.append( " ],\n" );
@ -363,10 +378,11 @@ public final class OsmTrack
sb.append( " \"type\": \"LineString\",\n" );
sb.append( " \"coordinates\": [\n" );
for( OsmPathElement n : nodes )
for ( OsmPathElement n : nodes )
{
String sele = n.getSElev() == Short.MIN_VALUE ? "" : ", " + n.getElev();
sb.append( " [" ).append(formatPos(n.getILon() - 180000000)).append(", ").append(formatPos(n.getILat() - 90000000)).append(sele).append( "],\n" );
sb.append( " [" ).append( formatPos( n.getILon() - 180000000 ) ).append( ", " ).append( formatPos( n.getILat() - 90000000 ) )
.append( sele ).append( "],\n" );
}
sb.deleteCharAt( sb.lastIndexOf( "," ) );
@ -382,17 +398,20 @@ public final class OsmTrack
private static String formatPos( int p )
{
boolean negative = p < 0;
if ( negative ) p = -p;
if ( negative )
p = -p;
char[] ac = new char[12];
int i = 11;
while( p != 0 || i > 3 )
while (p != 0 || i > 3)
{
ac[i--] = (char)('0' + (p % 10));
ac[i--] = (char) ( '0' + ( p % 10 ) );
p /= 10;
if ( i == 5 ) ac[i--] = '.';
if ( i == 5 )
ac[i--] = '.';
}
if ( negative ) ac[i--] = '-';
return new String( ac, i+1, 11-i );
if ( negative )
ac[i--] = '-';
return new String( ac, i + 1, 11 - i );
}
public void dumpMessages( String filename, RoutingContext rc ) throws Exception
@ -404,14 +423,15 @@ public final class OsmTrack
public void writeMessages( BufferedWriter bw, RoutingContext rc ) throws Exception
{
dumpLine( bw, MESSAGES_HEADER );
for( String m : aggregateMessages() )
for ( String m : aggregateMessages() )
{
dumpLine( bw, m );
}
if ( bw != null ) bw.close();
if ( bw != null )
bw.close();
}
private void dumpLine( BufferedWriter bw, String s) throws Exception
private void dumpLine( BufferedWriter bw, String s ) throws Exception
{
if ( bw == null )
{
@ -427,28 +447,29 @@ public final class OsmTrack
public void readGpx( String filename ) throws Exception
{
File f = new File( filename );
if ( !f.exists() ) return;
BufferedReader br = new BufferedReader(
new InputStreamReader(
new FileInputStream( f ) ) );
if ( !f.exists() )
return;
BufferedReader br = new BufferedReader( new InputStreamReader( new FileInputStream( f ) ) );
for(;;)
for ( ;; )
{
String line = br.readLine();
if ( line == null ) break;
if ( line == null )
break;
int idx0 = line.indexOf( "<trkpt lon=\"" );
if ( idx0 >= 0 )
{
idx0 += 12;
int idx1 = line.indexOf( '"', idx0 );
int ilon = (int)((Double.parseDouble( line.substring( idx0, idx1 ) ) + 180. )*1000000. + 0.5);
int ilon = (int) ( ( Double.parseDouble( line.substring( idx0, idx1 ) ) + 180. ) * 1000000. + 0.5 );
int idx2 = line.indexOf( " lat=\"" );
if ( idx2 < 0 ) continue;
if ( idx2 < 0 )
continue;
idx2 += 6;
int idx3 = line.indexOf( '"', idx2 );
int ilat = (int)((Double.parseDouble( line.substring( idx2, idx3 ) ) + 90. )*1000000. + 0.5);
nodes.add( OsmPathElement.create( ilon, ilat, (short)0, null, false ) );
int ilat = (int) ( ( Double.parseDouble( line.substring( idx2, idx3 ) ) + 90. ) * 1000000. + 0.5 );
nodes.add( OsmPathElement.create( ilon, ilat, (short) 0, null, false ) );
}
}
br.close();
@ -456,12 +477,14 @@ public final class OsmTrack
public boolean equalsTrack( OsmTrack t )
{
if ( nodes.size() != t.nodes.size() ) return false;
for( int i=0; i<nodes.size(); i++ )
if ( nodes.size() != t.nodes.size() )
return false;
for ( int i = 0; i < nodes.size(); i++ )
{
OsmPathElement e1 = nodes.get(i);
OsmPathElement e2 = t.nodes.get(i);
if ( e1.getILon() != e2.getILon() || e1.getILat() != e2.getILat() ) return false;
OsmPathElement e1 = nodes.get( i );
OsmPathElement e2 = t.nodes.get( i );
if ( e1.getILon() != e2.getILon() || e1.getILat() != e2.getILat() )
return false;
}
return true;
}

View file

@ -0,0 +1,98 @@
/**
* Container for routig configs
*
* @author ab
*/
package btools.router;
import java.io.File;
import btools.expressions.BExpressionContextGlobal;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
public final class ProfileCache
{
private static BExpressionContextWay expctxWay;
private static BExpressionContextNode expctxNode;
private static File lastLookupFile;
private static File lastProfileFile;
private static long lastLookupTimestamp;
private static long lastProfileTimestamp;
private static boolean profilesBusy;
public static synchronized boolean parseProfile( RoutingContext rc )
{
String profileBaseDir = System.getProperty( "profileBaseDir" );
File profileDir;
File profileFile;
if ( profileBaseDir == null )
{
profileDir = new File( rc.localFunction ).getParentFile();
profileFile = new File( rc.localFunction ) ;
}
else
{
profileDir = new File( profileBaseDir );
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ;
}
File lookupFile = new File( profileDir, "lookups.dat" );
// check for re-use
if ( expctxWay != null && expctxNode != null && !profilesBusy )
{
if ( profileFile.equals( lastProfileFile ) && lookupFile.equals( lastLookupFile ) )
{
if ( profileFile.lastModified() == lastProfileTimestamp
&& lookupFile.lastModified() == lastLookupTimestamp )
{
rc.expctxWay = expctxWay;
rc.expctxNode = expctxNode;
profilesBusy = true;
rc.readGlobalConfig(expctxWay);
return true;
}
}
}
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta );
rc.expctxWay = new BExpressionContextWay( rc.serversizing ? 262144 : 8192, meta );
rc.expctxNode = new BExpressionContextNode( rc.serversizing ? 16384 : 2048, meta );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
expctxGlobal.parseFile( profileFile, null );
expctxGlobal.evaluate( new int[0] );
rc.readGlobalConfig(expctxGlobal);
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode.parseFile( profileFile, "global" );
lastProfileTimestamp = profileFile.lastModified();
lastLookupTimestamp = lookupFile.lastModified();
lastProfileFile = profileFile;
lastLookupFile = lookupFile;
expctxWay = rc.expctxWay;
expctxNode = rc.expctxNode;
profilesBusy = true;
return false;
}
public static synchronized void releaseProfile( RoutingContext rc )
{
// only the thread that holds the cached instance can release it
if ( rc.expctxWay == expctxWay && rc.expctxNode == expctxNode )
{
profilesBusy = false;
}
rc.expctxWay = null;
rc.expctxNode = null;
}
}

View file

@ -10,10 +10,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import btools.expressions.BExpressionContextGlobal;
import btools.expressions.BExpressionContextNode;
import btools.expressions.BExpressionContextWay;
import btools.expressions.BExpressionMetaData;
import btools.mapaccess.NodesCache;
import btools.mapaccess.OsmLink;
import btools.mapaccess.OsmLinkHolder;
@ -42,7 +38,6 @@ public class RoutingEngine extends Thread
private volatile boolean terminated;
protected File profileDir;
protected String segmentDir;
private String outfileBase;
private String logfileBase;
@ -71,36 +66,30 @@ public class RoutingEngine extends Thread
this.infoLogEnabled = outfileBase != null;
this.routingContext = rc;
if ( rc.localFunction != null )
try
{
String profileBaseDir = System.getProperty( "profileBaseDir" );
File profileFile;
if ( profileBaseDir == null )
File debugLog = new File( new File( routingContext.localFunction ).getParentFile(), "../debug.txt" );
if ( debugLog.exists() )
{
profileDir = new File( rc.localFunction ).getParentFile();
profileFile = new File( rc.localFunction ) ;
infoLogWriter = new FileWriter( debugLog, true );
logInfo( "********** start request at " );
logInfo( "********** " + new Date() );
}
else
}
catch( IOException ioe )
{
profileDir = new File( profileBaseDir );
profileFile = new File( profileDir, rc.localFunction + ".brf" ) ;
throw new RuntimeException( "cannot open debug-log:" + ioe );
}
boolean cachedProfile = ProfileCache.parseProfile( rc );
if ( hasInfo() )
{
logInfo( "parsed profile " + rc.localFunction + " cached=" + cachedProfile );
}
}
BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta );
rc.expctxWay = new BExpressionContextWay( rc.serversizing ? 262144 : 8192, meta );
rc.expctxNode = new BExpressionContextNode( rc.serversizing ? 16384 : 2048, meta );
meta.readMetaData( new File( profileDir, "lookups.dat" ) );
expctxGlobal.parseFile( profileFile, null );
expctxGlobal.evaluate( new int[0] );
rc.readGlobalConfig(expctxGlobal);
rc.expctxWay.parseFile( profileFile, "global" );
rc.expctxNode.parseFile( profileFile, "global" );
}
private boolean hasInfo()
{
return infoLogEnabled || infoLogWriter != null;
}
private void logInfo( String s )
@ -141,13 +130,6 @@ public class RoutingEngine extends Thread
{
try
{
File debugLog = new File( profileDir, "../debug.txt" );
if ( debugLog.exists() )
{
infoLogWriter = new FileWriter( debugLog, true );
logInfo( "start request at " + new Date() );
}
// delete nogos with waypoints in them
routingContext.cleanNogolist( waypoints );
@ -232,6 +214,8 @@ public class RoutingEngine extends Thread
}
finally
{
ProfileCache.releaseProfile( routingContext );
if ( nodesCache != null )
{
nodesCache.close();
@ -313,6 +297,10 @@ public class RoutingEngine extends Thread
nearbyTrack = OsmTrack.readBinary( routingContext.rawTrackPath, waypoints.get( waypoints.size()-1), routingContext.getNogoChecksums() );
if ( nearbyTrack != null )
{
if ( hasInfo() )
{
logInfo( "read referenceTrack, dirty=" + nearbyTrack.isDirty );
}
nUnmatched--;
}
}
@ -506,6 +494,7 @@ public class RoutingEngine extends Thread
OsmTrack track = null;
double[] airDistanceCostFactors = new double[]{ routingContext.pass1coefficient, routingContext.pass2coefficient };
boolean isDirty = false;
IllegalArgumentException dirtyMessage = null;
if ( nearbyTrack != null )
{
@ -524,6 +513,7 @@ public class RoutingEngine extends Thread
{
track = mergeTrack( matchPath, nearbyTrack );
isDirty = true;
dirtyMessage = iae;
logInfo( "using fast partial recalc" );
}
maxRunningTime += System.currentTimeMillis() - startTime; // reset timeout...
@ -541,7 +531,24 @@ public class RoutingEngine extends Thread
continue;
}
OsmTrack t = findTrack( cfi == 0 ? "pass0" : "pass1", startWp, endWp, track , refTrack, false );
OsmTrack t;
try
{
t = findTrack( cfi == 0 ? "pass0" : "pass1", startWp, endWp, track , refTrack, false );
}
catch( IllegalArgumentException iae )
{
if ( !terminated && matchPath != null ) // timeout, but eventually prepare a dirty ref track
{
logInfo( "supplying dirty reference track after timeout" );
foundRawTrack = mergeTrack( matchPath, track );
foundRawTrack.endPoint = endWp;
foundRawTrack.nogoChecksums = routingContext.getNogoChecksums();
foundRawTrack.isDirty = true;
}
throw iae;
}
if ( t == null && track != null && matchPath != null )
{
// ups, didn't find it, use a merge
@ -560,17 +567,25 @@ public class RoutingEngine extends Thread
}
if ( track == null ) throw new IllegalArgumentException( "no track found" );
if ( refTrack == null && !isDirty )
boolean wasClean = nearbyTrack != null && !nearbyTrack.isDirty;
if ( refTrack == null && !(wasClean && isDirty) ) // do not overwrite a clean with a dirty track
{
logInfo( "supplying new reference track" );
logInfo( "supplying new reference track, dirty=" + isDirty );
track.endPoint = endWp;
track.nogoChecksums = routingContext.getNogoChecksums();
track.isDirty = isDirty;
foundRawTrack = track;
}
if ( !wasClean && isDirty )
{
throw dirtyMessage;
}
// final run for verbose log info and detail nodes
airDistanceCostFactor = 0.;
guideTrack = track;
startTime = System.currentTimeMillis(); // reset timeout...
try
{
OsmTrack tt = findTrack( "re-tracking", startWp, endWp, null , refTrack, false );
@ -804,7 +819,8 @@ public class RoutingEngine extends Thread
continue;
}
if ( matchPath != null && fastPartialRecalc && firstMatchCost < 500 && path.cost > 30L*firstMatchCost )
if ( matchPath != null && fastPartialRecalc && firstMatchCost < 500 && path.cost > 30L*firstMatchCost
&& !costCuttingTrack.isDirty )
{
logInfo( "early exit: firstMatchCost=" + firstMatchCost + " path.cost=" + path.cost );
throw new IllegalArgumentException( "early exit for a close recalc" );

View file

@ -194,7 +194,7 @@ public final class NodesCache
}
catch (Exception e)
{
throw new RuntimeException( "error reading datafile " + currentFileName + ": ", e );
throw new RuntimeException( "error reading datafile " + currentFileName + ": " + e, e );
}
}

View file

@ -108,7 +108,7 @@ final public class PhysicalFile
if ( len < pos+extraLen ) // > is o.k. for future extensions!
{
throw new IOException( "file of size " + len + " + too short, should be " + (pos+extraLen) );
throw new IOException( "file of size " + len + " too short, should be " + (pos+extraLen) );
}
ra.seek( pos );

View file

@ -52,12 +52,9 @@ public class BRouterWorker
RoutingEngine cr = new RoutingEngine( null, null, segmentDir, readPositions(params), rc );
cr.quite = true;
cr.doRun( maxRunningTime );
if ( cr.getErrorMessage() != null )
{
return cr.getErrorMessage();
}
// store new reference track if any
// (can exist fot timeed-out search)
if ( cr.getFoundRawTrack() != null )
{
try
@ -67,6 +64,10 @@ public class BRouterWorker
catch( Exception e ) {}
}
if ( cr.getErrorMessage() != null )
{
return cr.getErrorMessage();
}
String format = params.getString("trackFormat");
boolean writeKml = format != null && "kml".equals( format );