more performance tuning

This commit is contained in:
Arndt 2016-08-28 19:43:40 +02:00
parent acb7c6b16f
commit ea572ad47f
10 changed files with 357 additions and 165 deletions

View file

@ -102,8 +102,7 @@ public final class MicroCache2 extends MicroCache
if ( debug ) System.out.println( "*** decoding node with links=" + links ); if ( debug ) System.out.println( "*** decoding node with links=" + links );
for( int li=0; li<links; li++ ) for( int li=0; li<links; li++ )
{ {
int startPointer = aboffset; int sizeoffset = 0;
int sizeoffset = writeSizePlaceHolder();
int nodeIdx = n + nodeIdxDiff.decodeSignedValue(); int nodeIdx = n + nodeIdxDiff.decodeSignedValue();
int dlon_remaining; int dlon_remaining;
@ -112,19 +111,25 @@ public final class MicroCache2 extends MicroCache
boolean isReverse = false; boolean isReverse = false;
if ( nodeIdx != n ) // internal (forward-) link if ( nodeIdx != n ) // internal (forward-) link
{ {
writeVarLengthSigned( dlon_remaining = alon[nodeIdx] - ilon ); dlon_remaining = alon[nodeIdx] - ilon;
writeVarLengthSigned( dlat_remaining = alat[nodeIdx] - ilat ); dlat_remaining = alat[nodeIdx] - ilat;
} }
else else
{ {
isReverse = bc.decodeBit(); isReverse = bc.decodeBit();
writeVarLengthSigned( dlon_remaining = extLonDiff.decodeSignedValue() ); dlon_remaining = extLonDiff.decodeSignedValue();
writeVarLengthSigned( dlat_remaining = extLatDiff.decodeSignedValue() ); dlat_remaining = extLatDiff.decodeSignedValue();
} }
TagValueWrapper wayTags = wayTagCoder.decodeTagValueSet(); TagValueWrapper wayTags = wayTagCoder.decodeTagValueSet();
if ( wayTags != null ) if ( wayTags != null )
{ {
int startPointer = aboffset;
sizeoffset = writeSizePlaceHolder();
writeVarLengthSigned( dlon_remaining );
writeVarLengthSigned( dlat_remaining );
validNodes.set( n, true ); // mark source-node valid validNodes.set( n, true ); // mark source-node valid
if ( nodeIdx != n ) // valid internal (forward-) link if ( nodeIdx != n ) // valid internal (forward-) link
{ {
@ -132,9 +137,9 @@ public final class MicroCache2 extends MicroCache
finaldatasize += 1 + aboffset-startPointer; // reserve place for reverse finaldatasize += 1 + aboffset-startPointer; // reserve place for reverse
validNodes.set( nodeIdx, true ); // mark target-node valid validNodes.set( nodeIdx, true ); // mark target-node valid
} }
writeModeAndDesc( isReverse, wayTags.data );
} }
writeModeAndDesc( isReverse, wayTags == null ? null : wayTags.data );
if ( !isReverse ) // write geometry for forward links only if ( !isReverse ) // write geometry for forward links only
{ {
WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher; WaypointMatcher matcher = wayTags == null || wayTags.accessType < 2 ? null : waypointMatcher;
@ -152,19 +157,19 @@ public final class MicroCache2 extends MicroCache
dlon_remaining -= dlon; dlon_remaining -= dlon;
dlat_remaining -= dlat; dlat_remaining -= dlat;
count--; count--;
int elediff = transEleDiff.decodeSignedValue();
if ( wayTags != null )
{
writeVarLengthSigned( dlon ); writeVarLengthSigned( dlon );
writeVarLengthSigned( dlat ); writeVarLengthSigned( dlat );
writeVarLengthSigned( transEleDiff.decodeSignedValue() ); writeVarLengthSigned( elediff );
}
if ( matcher != null ) matcher.transferNode( ilontarget - dlon_remaining, ilattarget - dlat_remaining ); if ( matcher != null ) matcher.transferNode( ilontarget - dlon_remaining, ilattarget - dlat_remaining );
} }
if ( matcher != null ) matcher.endNode( ilontarget, ilattarget ); if ( matcher != null ) matcher.endNode( ilontarget, ilattarget );
} }
if ( wayTags == null ) if ( wayTags != null )
{
aboffset = startPointer; // not a valid link, delete it
}
else
{ {
injectSize( sizeoffset ); injectSize( sizeoffset );
} }

View file

@ -63,8 +63,8 @@ public final class ProfileCache
BExpressionMetaData meta = new BExpressionMetaData(); BExpressionMetaData meta = new BExpressionMetaData();
BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta ); BExpressionContextGlobal expctxGlobal = new BExpressionContextGlobal( meta );
rc.expctxWay = new BExpressionContextWay( rc.serversizing ? 262144 : 32768, meta ); rc.expctxWay = new BExpressionContextWay( rc.serversizing ? 131072 : 32768, meta );
rc.expctxNode = new BExpressionContextNode( rc.serversizing ? 16384 : 4096, meta ); rc.expctxNode = new BExpressionContextNode( rc.serversizing ? 4096 : 1024, meta );
meta.readMetaData( new File( profileDir, "lookups.dat" ) ); meta.readMetaData( new File( profileDir, "lookups.dat" ) );

View file

@ -21,6 +21,7 @@ import java.util.TreeMap;
import btools.util.BitCoderContext; import btools.util.BitCoderContext;
import btools.util.Crc32; import btools.util.Crc32;
import btools.util.IByteArrayUnifier; import btools.util.IByteArrayUnifier;
import btools.util.LruMap;
public abstract class BExpressionContext implements IByteArrayUnifier public abstract class BExpressionContext implements IByteArrayUnifier
@ -49,10 +50,11 @@ public abstract class BExpressionContext implements IByteArrayUnifier
// hash-cache for function results // hash-cache for function results
private byte[][] _arrayBitmap; private CacheNode probeCacheNode = new CacheNode();
private int[] _arrayCrc; private LruMap cache;
private int currentHashBucket = -1; private VarWrapper probeVarSet = new VarWrapper();
private LruMap resultVarCache;
private List<BExpression> expressionList; private List<BExpression> expressionList;
@ -60,20 +62,21 @@ public abstract class BExpressionContext implements IByteArrayUnifier
// build-in variable indexes for fast access // build-in variable indexes for fast access
private int[] buildInVariableIdx; private int[] buildInVariableIdx;
private int nBuildInVars;
private float[][] arrayBuildInVariablesCache; private float[] currentVars;
private float[] hashBucketVars; private int currentVarOffset;
protected void setInverseVars()
{
currentVarOffset = nBuildInVars;
}
abstract String[] getBuildInVariableNames(); abstract String[] getBuildInVariableNames();
protected final float getBuildInVariable( int idx ) protected final float getBuildInVariable( int idx )
{ {
return hashBucketVars[idx]; return currentVars[idx+currentVarOffset];
}
protected final float getInverseBuildInVariable( int idx )
{
return arrayBuildInVariablesCache[currentHashBucket | 1][idx];
} }
private int linenr; private int linenr;
@ -102,9 +105,8 @@ public abstract class BExpressionContext implements IByteArrayUnifier
if ( Boolean.getBoolean( "disableExpressionCache" ) ) hashSize = 1; if ( Boolean.getBoolean( "disableExpressionCache" ) ) hashSize = 1;
// create the expression cache // create the expression cache
_arrayBitmap = new byte[hashSize][]; cache = new LruMap( 4*hashSize, hashSize );
_arrayCrc = new int[hashSize]; resultVarCache = new LruMap( 4096, 4096 );
arrayBuildInVariablesCache = new float[hashSize << 1][];
} }
/** /**
@ -279,116 +281,112 @@ public abstract class BExpressionContext implements IByteArrayUnifier
return "requests=" + requests + " requests2=" + requests2 + " cachemisses=" + cachemisses; return "requests=" + requests + " requests2=" + requests2 + " cachemisses=" + cachemisses;
} }
@Override // @Override
public final byte[] unify( byte[] ab, int offset, int len ) public final byte[] unify( byte[] ab, int offset, int len )
{ {
int crc = Crc32.crc( ab, offset, len ); probeCacheNode.ab = null; // crc based cache lookup only
int hashSize = _arrayBitmap.length; probeCacheNode.crc = Crc32.crc( ab, offset, len );
int idx = ( crc & 0xfffffff ) % hashSize;
byte[] abc = _arrayBitmap[idx]; CacheNode cn = (CacheNode)cache.get( probeCacheNode );
if ( abc != null && abc.length == len ) if ( cn != null )
{ {
int i = 0; byte[] cab = cn.ab;
while (i < len) if ( cab.length == len )
{ {
if ( ab[offset + i] != abc[i] ) for( int i=0; i<len; i++ )
{
if ( cab[i] != ab[i+offset] )
{
cn = null;
break; break;
i++;
} }
if ( i == len ) }
return abc; if ( cn != null )
{
return cn.ab;
}
}
} }
byte[] nab = new byte[len]; byte[] nab = new byte[len];
System.arraycopy( ab, offset, nab, 0, len ); System.arraycopy( ab, offset, nab, 0, len );
return nab; return nab;
} }
/**
* evaluates the data in the given byte array
*
* @return true if the data is equivilant to the last calls data
*/
public final void evaluate( boolean inverseDirection, byte[] ab ) public final void evaluate( boolean inverseDirection, byte[] ab )
{ {
requests++; requests++;
lookupDataValid = false; // this is an assertion for a nasty pifall lookupDataValid = false; // this is an assertion for a nasty pifall
// calc hash bucket from crc probeCacheNode.ab = ab;
int crc = Crc32.crc( ab, 0, ab.length ); probeCacheNode.crc = Crc32.crc( ab, 0, ab.length );
int hashSize = _arrayBitmap.length;
int hashBucket2 = ( crc & 0xfffffff ) % hashSize;
int hashBucket01 = hashBucket2 << 1;
int hashBucket02 = hashBucket01 | 1;
int hashBucket = inverseDirection ? hashBucket02 : hashBucket01;
if ( hashBucket != currentHashBucket ) CacheNode cn = (CacheNode)cache.get( probeCacheNode );
if ( cn == null )
{ {
currentHashBucket = hashBucket;
hashBucketVars = arrayBuildInVariablesCache[hashBucket];
if ( hashBucketVars == null )
{
arrayBuildInVariablesCache[hashBucket01] = new float[buildInVariableIdx.length];
arrayBuildInVariablesCache[hashBucket02] = new float[buildInVariableIdx.length];
hashBucketVars = arrayBuildInVariablesCache[hashBucket];
}
}
if ( crc == _arrayCrc[hashBucket2] )
{
byte[] abBucket = _arrayBitmap[hashBucket2];
if ( ab == abBucket ) // fast identity check
{
return;
}
requests2++;
// compare input value to hash bucket content
boolean hashBucketEquals = false;
int abLen = ab.length;
if ( abBucket != null && abBucket.length == abLen )
{
hashBucketEquals = true;
for ( int i = 0; i < abLen; i++ )
{
if ( abBucket[i] != ab[i] )
{
hashBucketEquals = false;
break;
}
}
}
if ( hashBucketEquals )
{
return;
}
}
cachemisses++; cachemisses++;
_arrayBitmap[hashBucket2] = ab; cn = (CacheNode)cache.removeLru();
_arrayCrc[hashBucket2] = crc; if ( cn == null )
{
cn = new CacheNode();
}
cn.crc = probeCacheNode.crc;
cn.ab = ab;
cache.put( cn );
int nBuildInVars = buildInVariableIdx.length; if ( probeVarSet.vars == null )
{
probeVarSet.vars = new float[2*nBuildInVars];
}
// forward direction // forward direction
decode( lookupData, false, ab ); decode( lookupData, false, ab );
evaluate(); evaluateInto( probeVarSet.vars, 0 );
float[] vars = arrayBuildInVariablesCache[hashBucket01];
for ( int vi = 0; vi < nBuildInVars; vi++ )
{
int idx = buildInVariableIdx[vi];
vars[vi] = idx == -1 ? 0.f : variableData[idx];
}
// inverse direction // inverse direction
lookupData[0] = 2; // inverse shortcut: reuse decoding lookupData[0] = 2; // inverse shortcut: reuse decoding
evaluateInto( probeVarSet.vars, nBuildInVars );
probeVarSet.hash = Arrays.hashCode( probeVarSet.vars );
// unify the result variable set
VarWrapper vw = (VarWrapper)resultVarCache.get( probeVarSet );
if ( vw == null )
{
vw = (VarWrapper)resultVarCache.removeLru();
if ( vw == null )
{
vw = new VarWrapper();
}
vw.hash = probeVarSet.hash;
vw.vars = probeVarSet.vars;
probeVarSet.vars = null;
resultVarCache.put( vw );
}
cn.vars = vw.vars;
}
else
{
if ( ab == cn.ab ) requests2++;
cache.touch( cn );
}
currentVars = cn.vars;
currentVarOffset = inverseDirection ? nBuildInVars : 0;
}
private void evaluateInto( float[] vars, int offset )
{
evaluate(); evaluate();
vars = arrayBuildInVariablesCache[hashBucket02];
for ( int vi = 0; vi < nBuildInVars; vi++ ) for ( int vi = 0; vi < nBuildInVars; vi++ )
{ {
int idx = buildInVariableIdx[vi]; int idx = buildInVariableIdx[vi];
vars[vi] = idx == -1 ? 0.f : variableData[idx]; vars[vi+offset] = idx == -1 ? 0.f : variableData[idx];
}
} }
}
public void dumpStatistics() public void dumpStatistics()
{ {
@ -650,7 +648,8 @@ public abstract class BExpressionContext implements IByteArrayUnifier
// determine the build-in variable indices // determine the build-in variable indices
String[] varNames = getBuildInVariableNames(); String[] varNames = getBuildInVariableNames();
buildInVariableIdx = new int[varNames.length]; nBuildInVars = varNames.length;
buildInVariableIdx = new int[nBuildInVars];
for( int vi=0; vi<varNames.length; vi++ ) for( int vi=0; vi<varNames.length; vi++ )
{ {
buildInVariableIdx[vi] = getVariableIdx( varNames[vi], false ); buildInVariableIdx[vi] = getVariableIdx( varNames[vi], false );

View file

@ -32,8 +32,6 @@ public final class BExpressionContextWay extends BExpressionContext implements T
public float getPriorityClassifier() { return getBuildInVariable(9); } public float getPriorityClassifier() { return getBuildInVariable(9); }
public float getClassifierMask() { return getBuildInVariable(10); } public float getClassifierMask() { return getBuildInVariable(10); }
public float getInverseCostfactor() { return getInverseBuildInVariable(0); }
public BExpressionContextWay( BExpressionMetaData meta ) public BExpressionContextWay( BExpressionMetaData meta )
{ {
super( "way", meta ); super( "way", meta );
@ -56,7 +54,8 @@ public final class BExpressionContextWay extends BExpressionContext implements T
float minCostFactor = getCostfactor(); float minCostFactor = getCostfactor();
if ( minCostFactor >= 9999.f ) if ( minCostFactor >= 9999.f )
{ {
float reverseCostFactor = getInverseCostfactor(); setInverseVars();
float reverseCostFactor = getCostfactor();
if ( reverseCostFactor < minCostFactor ) if ( reverseCostFactor < minCostFactor )
{ {
minCostFactor = reverseCostFactor; minCostFactor = reverseCostFactor;

View file

@ -0,0 +1,33 @@
package btools.expressions;
import java.util.Arrays;
import btools.util.LruMapNode;
public final class CacheNode extends LruMapNode
{
int crc;
byte[] ab;
float[] vars;
@Override
public int hashCode()
{
return crc;
}
@Override
public boolean equals( Object o )
{
CacheNode n = (CacheNode) o;
if ( crc != n.crc )
{
return false;
}
if ( ab == null )
{
return true; // hack: null = crc match only
}
return Arrays.equals( ab, n.ab );
}
}

View file

@ -0,0 +1,28 @@
package btools.expressions;
import java.util.Arrays;
import btools.util.LruMapNode;
public final class VarWrapper extends LruMapNode
{
int hash;
float[] vars;
@Override
public int hashCode()
{
return hash;
}
@Override
public boolean equals( Object o )
{
VarWrapper n = (VarWrapper) o;
if ( hash != n.hash )
{
return false;
}
return Arrays.equals( vars, n.vars );
}
}

View file

@ -107,23 +107,6 @@ public class ByteDataReader
return ( v & 1 ) == 0 ? v >> 1 : -(v >> 1 ); return ( v & 1 ) == 0 ? v >> 1 : -(v >> 1 );
} }
public final int readVarLengthUnsigned_old()
{
int v = 0;
int shift = 0;
for ( ;; )
{
byte b = ab[aboffset++];
v |= ( ( b & 0x7f ) << shift );
if ( ( b & 0x80 ) == 0 )
{
break;
}
shift += 7;
}
return v;
}
public final int readVarLengthUnsigned() public final int readVarLengthUnsigned()
{ {
byte b; byte b;
@ -135,15 +118,7 @@ public class ByteDataReader
if ( b >= 0 ) return v; if ( b >= 0 ) return v;
v |= ( (b=ab[aboffset++]) & 0x7f ) << 21; v |= ( (b=ab[aboffset++]) & 0x7f ) << 21;
if ( b >= 0 ) return v; if ( b >= 0 ) return v;
v |= ( (b=ab[aboffset++]) & 0x7f ) << 28; v |= ( (b=ab[aboffset++]) & 0xf ) << 28;
if ( b >= 0 ) return v;
v |= ( (b=ab[aboffset++]) & 0x7f ) << 35;
if ( b >= 0 ) return v;
v |= ( (b=ab[aboffset++]) & 0x7f ) << 42;
if ( b >= 0 ) return v;
v |= ( (b=ab[aboffset++]) & 0x7f ) << 49;
if ( b >= 0 ) return v;
v |= ( (b=ab[aboffset++]) & 0x7f ) << 56;
return v; return v;
} }

View file

@ -13,7 +13,7 @@ public class ByteDataWriter extends ByteDataReader
super ( byteArray ); super ( byteArray );
} }
public void writeInt( int v ) public final void writeInt( int v )
{ {
ab[aboffset++] = (byte)( (v >> 24) & 0xff ); ab[aboffset++] = (byte)( (v >> 24) & 0xff );
ab[aboffset++] = (byte)( (v >> 16) & 0xff ); ab[aboffset++] = (byte)( (v >> 16) & 0xff );
@ -21,7 +21,7 @@ public class ByteDataWriter extends ByteDataReader
ab[aboffset++] = (byte)( (v ) & 0xff ); ab[aboffset++] = (byte)( (v ) & 0xff );
} }
public void writeLong( long v ) public final void writeLong( long v )
{ {
ab[aboffset++] = (byte)( (v >> 56) & 0xff ); ab[aboffset++] = (byte)( (v >> 56) & 0xff );
ab[aboffset++] = (byte)( (v >> 48) & 0xff ); ab[aboffset++] = (byte)( (v >> 48) & 0xff );
@ -33,35 +33,35 @@ public class ByteDataWriter extends ByteDataReader
ab[aboffset++] = (byte)( (v ) & 0xff ); ab[aboffset++] = (byte)( (v ) & 0xff );
} }
public void writeBoolean( boolean v) public final void writeBoolean( boolean v)
{ {
ab[aboffset++] = (byte)( v ? 1 : 0 ); ab[aboffset++] = (byte)( v ? 1 : 0 );
} }
public void writeByte( int v ) public final void writeByte( int v )
{ {
ab[aboffset++] = (byte)( (v ) & 0xff ); ab[aboffset++] = (byte)( (v ) & 0xff );
} }
public void writeShort( int v ) public final void writeShort( int v )
{ {
ab[aboffset++] = (byte)( (v >> 8) & 0xff ); ab[aboffset++] = (byte)( (v >> 8) & 0xff );
ab[aboffset++] = (byte)( (v ) & 0xff ); ab[aboffset++] = (byte)( (v ) & 0xff );
} }
public void write( byte[] sa ) public final void write( byte[] sa )
{ {
System.arraycopy( sa, 0, ab, aboffset, sa.length ); System.arraycopy( sa, 0, ab, aboffset, sa.length );
aboffset += sa.length; aboffset += sa.length;
} }
public void write( byte[] sa, int offset, int len ) public final void write( byte[] sa, int offset, int len )
{ {
System.arraycopy( sa, offset, ab, aboffset, len ); System.arraycopy( sa, offset, ab, aboffset, len );
aboffset += len; aboffset += len;
} }
public void writeVarBytes( byte[] sa ) public final void writeVarBytes( byte[] sa )
{ {
if ( sa == null ) if ( sa == null )
{ {
@ -75,7 +75,7 @@ public class ByteDataWriter extends ByteDataReader
} }
} }
public void writeModeAndDesc( boolean isReverse, byte[] sa ) public final void writeModeAndDesc( boolean isReverse, byte[] sa )
{ {
int len = sa == null ? 0 : sa.length; int len = sa == null ? 0 : sa.length;
int sizecode = len << 1 | ( isReverse ? 1 : 0 ); int sizecode = len << 1 | ( isReverse ? 1 : 0 );
@ -87,7 +87,7 @@ public class ByteDataWriter extends ByteDataReader
} }
public byte[] toByteArray() public final byte[] toByteArray()
{ {
byte[] c = new byte[aboffset]; byte[] c = new byte[aboffset];
System.arraycopy( ab, 0, c, 0, aboffset ); System.arraycopy( ab, 0, c, 0, aboffset );
@ -102,12 +102,12 @@ public class ByteDataWriter extends ByteDataReader
* *
* @return the offset of the placeholder * @return the offset of the placeholder
*/ */
public int writeSizePlaceHolder() public final int writeSizePlaceHolder()
{ {
return aboffset++; return aboffset++;
} }
public void injectSize( int sizeoffset ) public final void injectSize( int sizeoffset )
{ {
int size = 0; int size = 0;
int datasize = aboffset-sizeoffset-1; int datasize = aboffset-sizeoffset-1;
@ -127,23 +127,47 @@ public class ByteDataWriter extends ByteDataReader
aboffset = sizeoffset + size + datasize; aboffset = sizeoffset + size + datasize;
} }
public int writeVarLengthSigned( int v ) public final void writeVarLengthSigned( int v )
{ {
return writeVarLengthUnsigned( v < 0 ? ( (-v) << 1 ) | 1 : v << 1 ); writeVarLengthUnsigned( v < 0 ? ( (-v) << 1 ) | 1 : v << 1 );
} }
public int writeVarLengthUnsigned( int v ) public final void writeVarLengthUnsigned( int v )
{
int start = aboffset;
do
{ {
int i7 = v & 0x7f; int i7 = v & 0x7f;
v >>= 7; if ( ( v >>>= 7 ) == 0 )
if ( v != 0 ) i7 |= 0x80; {
ab[aboffset++] = (byte)( i7 & 0xff ); ab[aboffset++] = (byte) ( i7 );
return;
} }
while( v != 0 ); ab[aboffset++] = (byte) ( i7 | 0x80 );
return aboffset - start;
i7 = v & 0x7f;
if ( ( v >>>= 7 ) == 0 )
{
ab[aboffset++] = (byte) ( i7 );
return;
}
ab[aboffset++] = (byte) ( i7 | 0x80 );
i7 = v & 0x7f;
if ( ( v >>>= 7 ) == 0 )
{
ab[aboffset++] = (byte) ( i7 );
return;
}
ab[aboffset++] = (byte) ( i7 | 0x80 );
i7 = v & 0x7f;
if ( ( v >>>= 7 ) == 0 )
{
ab[aboffset++] = (byte) ( i7 );
return;
}
ab[aboffset++] = (byte) ( i7 | 0x80 );
ab[aboffset++] = (byte) ( v );
return;
} }
public int size() public int size()

View file

@ -0,0 +1,121 @@
package btools.util;
/**
* Something like LinkedHashMap, but purpose build, less dynamic and memory efficient
*
* @author ab
*/
public final class LruMap
{
private int hashbins;
private int maxsize;
private int size;
private LruMapNode lru;
private LruMapNode mru;
private LruMapNode[] binArray;
public LruMap( int bins, int size)
{
hashbins = bins;
maxsize = size;
binArray = new LruMapNode[hashbins];
}
public LruMapNode get( LruMapNode key )
{
int bin = ( key.hashCode() & 0xfffffff ) % hashbins;
LruMapNode e = binArray[bin];
while ( e != null )
{
if ( key.equals( e ) )
{
return e;
}
e = e.nextInBin;
}
return null;
}
// put e to the mru end of the queue
public void touch( LruMapNode e )
{
LruMapNode n = e.next;
LruMapNode p = e.previous;
if ( n == null )
{
return; // already at mru
}
n.previous = p;
if ( p != null )
{
p.next = n;
}
else
{
lru = n;
}
mru.next = e;
e.previous = mru;
e.next = null;
mru = e;
}
public LruMapNode removeLru()
{
if ( size < maxsize )
{
return null;
}
size--;
// unlink the lru from it's bin-queue
int bin = ( lru.hashCode() & 0xfffffff ) % hashbins;
LruMapNode e = binArray[bin];
if ( e == lru )
{
binArray[bin] = lru.nextInBin;
}
else
{
while( e != null )
{
LruMapNode prev = e;
e = e.nextInBin;
if ( e == lru )
{
prev.nextInBin = lru.nextInBin;
break;
}
}
}
LruMapNode res = lru;
lru = lru.next;
lru.previous = null;
return res;
}
public void put( LruMapNode val )
{
int bin = ( val.hashCode() & 0xfffffff ) % hashbins;
val.nextInBin = binArray[bin];
binArray[bin] = val;
val.previous = mru;
val.next = null;
if ( mru == null )
{
lru = val;
}
else
{
mru.next = val;
}
mru = val;
size++;
}
}

View file

@ -0,0 +1,8 @@
package btools.util;
public abstract class LruMapNode
{
LruMapNode nextInBin; // next entry for hash-bin
LruMapNode next; // next in lru sequence (towards mru)
LruMapNode previous; // previous in lru sequence (towards lru)
}