added more cache reuse for better short-route performance

This commit is contained in:
Arndt Brenschede 2014-02-02 20:37:22 +01:00
parent 702c614dd3
commit 87ed332a56
3 changed files with 138 additions and 8 deletions

View file

@ -24,6 +24,11 @@ final class MicroCache
private int aboffset; private int aboffset;
private int ablength; private int ablength;
// cache control: a virgin cache can be
// put to ghost state for later recovery
boolean virgin = true;
boolean ghost = false;
public MicroCache( OsmFile segfile, int lonIdx80, int latIdx80, byte[] iobuffer ) throws Exception public MicroCache( OsmFile segfile, int lonIdx80, int latIdx80, byte[] iobuffer ) throws Exception
{ {
int lonDegree = lonIdx80/80; int lonDegree = lonIdx80/80;
@ -40,6 +45,7 @@ final class MicroCache
if ( asize == 0 ) if ( asize == 0 )
{ {
ab = null;
return; return;
} }
if ( asize > iobuffer.length ) if ( asize > iobuffer.length )
@ -105,9 +111,19 @@ final class MicroCache
return size; return size;
} }
public int getDataSize()
{
return ab == null ? 0 : ab.length;
}
/** /**
* @return the value for "id", * Set the internal reader (aboffset, ablength)
* Throw an exception if not contained in the map. * to the body data for the given id
*
* @return true if id was found
*
* Throws an exception if that id was already requested
* as an early detector for identity problems
*/ */
private boolean getAndClear( long id ) private boolean getAndClear( long id )
{ {
@ -148,7 +164,10 @@ final class MicroCache
return false; return false;
} }
public void fillNode( OsmNode node, OsmNodesMap nodesMap, DistanceChecker dc ) /**
* Fill a hollow node with it's body data
*/
public void fillNode( OsmNode node, OsmNodesMap nodesMap, DistanceChecker dc, boolean doCollect )
{ {
long id = node.getIdFromPos(); long id = node.getIdFromPos();
if ( getAndClear( id ) ) if ( getAndClear( id ) )
@ -156,8 +175,18 @@ final class MicroCache
node.parseNodeBody( this, ablength, nodesMap, dc ); node.parseNodeBody( this, ablength, nodesMap, dc );
} }
if ( delcount > size / 2 ) // garbage collection if ( doCollect && delcount > size / 2 ) // garbage collection
{ {
collect();
}
}
void collect()
{
if ( delcount > 0 )
{
virgin = false;
int nsize = size - delcount; int nsize = size - delcount;
if ( nsize == 0 ) if ( nsize == 0 )
{ {
@ -197,6 +226,17 @@ final class MicroCache
} }
} }
void unGhost()
{
ghost = false;
delcount = 0;
delbytes = 0;
for( int i=0; i<size; i++ )
{
fapos[i] &= 0x7fffffff; // clear deleted flags
}
}
public List<OsmNode> getPositions( OsmNodesMap nodesMap ) public List<OsmNode> getPositions( OsmNodesMap nodesMap )
{ {
ArrayList<OsmNode> positions = new ArrayList<OsmNode>(); ArrayList<OsmNode> positions = new ArrayList<OsmNode>();

View file

@ -19,13 +19,16 @@ public final class NodesCache
private HashMap<String,PhysicalFile> fileCache; private HashMap<String,PhysicalFile> fileCache;
private byte[] iobuffer; private byte[] iobuffer;
private OsmFile[][] fileRows = new OsmFile[180][]; private OsmFile[][] fileRows;
private ArrayList<MicroCache> segmentList = new ArrayList<MicroCache>(); private ArrayList<MicroCache> segmentList = new ArrayList<MicroCache>();
public DistanceChecker distanceChecker; public DistanceChecker distanceChecker;
public boolean oom_carsubset_hint = false; public boolean oom_carsubset_hint = false;
private long cacheSum = 0;
private boolean garbageCollectionEnabled = false;
public NodesCache( String segmentDir, OsmNodesMap nodesMap, int lookupVersion, boolean carMode, NodesCache oldCache ) public NodesCache( String segmentDir, OsmNodesMap nodesMap, int lookupVersion, boolean carMode, NodesCache oldCache )
{ {
this.segmentDir = segmentDir; this.segmentDir = segmentDir;
@ -38,14 +41,55 @@ public final class NodesCache
fileCache = oldCache.fileCache; fileCache = oldCache.fileCache;
iobuffer = oldCache.iobuffer; iobuffer = oldCache.iobuffer;
oom_carsubset_hint = oldCache.oom_carsubset_hint; oom_carsubset_hint = oldCache.oom_carsubset_hint;
// re-use old, virgin caches
fileRows = oldCache.fileRows;
for( OsmFile[] fileRow : fileRows )
{
if ( fileRow == null ) continue;
for( OsmFile osmf : fileRow )
{
cacheSum += osmf.setGhostState();
}
}
} }
else else
{ {
fileCache = new HashMap<String,PhysicalFile>(4); fileCache = new HashMap<String,PhysicalFile>(4);
fileRows = new OsmFile[180][];
iobuffer = new byte[65636]; iobuffer = new byte[65636];
} }
} }
// if the cache sum exceeded a threshold,
// clean all ghosts and enable garbage collection
private void checkEnableCacheCleaning()
{
if ( cacheSum < 200000 || garbageCollectionEnabled ) return;
for( int i=0; i<fileRows.length; i++ )
{
OsmFile[] fileRow = fileRows[i];
if ( fileRow == null ) continue;
int nghosts = 0;
for( OsmFile osmf : fileRow )
{
if ( osmf.ghost ) nghosts++;
else osmf.cleanAll();
}
if ( nghosts == 0 ) continue;
int j=0;
OsmFile[] frow = fileRows[fileRows.length-nghosts];
for( OsmFile osmf : fileRow )
{
if ( osmf.ghost ) continue;
frow[j++] = osmf;
}
fileRows[i] = frow;
}
garbageCollectionEnabled = true;
}
public int loadSegmentFor( int ilon, int ilat ) public int loadSegmentFor( int ilon, int ilat )
{ {
MicroCache mc = getSegmentFor( ilon, ilat ); MicroCache mc = getSegmentFor( ilon, ilat );
@ -82,6 +126,7 @@ public final class NodesCache
newFileRow[ndegrees] = osmf; newFileRow[ndegrees] = osmf;
fileRows[latDegree] = newFileRow; fileRows[latDegree] = newFileRow;
} }
osmf.ghost = false;
currentFileName = osmf.filename; currentFileName = osmf.filename;
if ( osmf.microCaches == null ) if ( osmf.microCaches == null )
{ {
@ -93,10 +138,18 @@ public final class NodesCache
{ {
// nodesMap.removeCompleteNodes(); // nodesMap.removeCompleteNodes();
checkEnableCacheCleaning();
segment = new MicroCache( osmf, lonIdx80, latIdx80, iobuffer ); segment = new MicroCache( osmf, lonIdx80, latIdx80, iobuffer );
cacheSum += segment.getDataSize();
osmf.microCaches[subIdx] = segment; osmf.microCaches[subIdx] = segment;
segmentList.add( segment ); segmentList.add( segment );
} }
else if ( segment.ghost )
{
segment.unGhost();
segmentList.add( segment );
}
return segment; return segment;
} }
catch( RuntimeException re ) catch( RuntimeException re )
@ -119,7 +172,7 @@ public final class NodesCache
{ {
return false; return false;
} }
segment.fillNode( node, nodesMap, distanceChecker ); segment.fillNode( node, nodesMap, distanceChecker, garbageCollectionEnabled );
return !node.isHollow(); return !node.isHollow();
} }

View file

@ -22,6 +22,8 @@ final class OsmFile
public String filename; public String filename;
public boolean ghost = false;
public OsmFile( PhysicalFile rafile, int tileIndex, byte[] iobuffer ) throws Exception public OsmFile( PhysicalFile rafile, int tileIndex, byte[] iobuffer ) throws Exception
{ {
if ( rafile != null ) if ( rafile != null )
@ -76,8 +78,43 @@ final class OsmFile
return size; return size;
} }
public void close() // set this OsmFile to ghost-state:
long setGhostState()
{ {
try { is.close(); } catch( IOException e ) { throw new RuntimeException( e ); } long sum = 0;
ghost = true;
for( int i=0; i< microCaches.length; i++ )
{
MicroCache mc = microCaches[i];
if ( mc == null ) continue;
if ( mc.virgin )
{
mc.ghost = true;
sum += mc.getDataSize();
} }
else
{
microCaches[i] = null;
}
}
return sum;
}
void cleanAll()
{
for( int i=0; i< microCaches.length; i++ )
{
MicroCache mc = microCaches[i];
if ( mc == null ) continue;
if ( mc.ghost )
{
microCaches[i] = null;
}
else
{
mc.collect();
}
}
}
} }