diff --git a/brouter-codec/src/main/java/btools/codec/MicroCache2.java b/brouter-codec/src/main/java/btools/codec/MicroCache2.java index 98653cb..ca5093d 100644 --- a/brouter-codec/src/main/java/btools/codec/MicroCache2.java +++ b/brouter-codec/src/main/java/btools/codec/MicroCache2.java @@ -102,8 +102,7 @@ public final class MicroCache2 extends MicroCache if ( debug ) System.out.println( "*** decoding node with links=" + links ); for( int li=0; li expressionList; @@ -60,20 +62,21 @@ public abstract class BExpressionContext implements IByteArrayUnifier // build-in variable indexes for fast access private int[] buildInVariableIdx; - - private float[][] arrayBuildInVariablesCache; - private float[] hashBucketVars; + private int nBuildInVars; + + private float[] currentVars; + private int currentVarOffset; + + protected void setInverseVars() + { + currentVarOffset = nBuildInVars; + } abstract String[] getBuildInVariableNames(); protected final float getBuildInVariable( int idx ) { - return hashBucketVars[idx]; - } - - protected final float getInverseBuildInVariable( int idx ) - { - return arrayBuildInVariablesCache[currentHashBucket | 1][idx]; + return currentVars[idx+currentVarOffset]; } private int linenr; @@ -102,9 +105,8 @@ public abstract class BExpressionContext implements IByteArrayUnifier if ( Boolean.getBoolean( "disableExpressionCache" ) ) hashSize = 1; // create the expression cache - _arrayBitmap = new byte[hashSize][]; - _arrayCrc = new int[hashSize]; - arrayBuildInVariablesCache = new float[hashSize << 1][]; + cache = new LruMap( 4*hashSize, hashSize ); + resultVarCache = new LruMap( 4096, 4096 ); } /** @@ -279,117 +281,113 @@ public abstract class BExpressionContext implements IByteArrayUnifier return "requests=" + requests + " requests2=" + requests2 + " cachemisses=" + cachemisses; } - @Override + // @Override public final byte[] unify( byte[] ab, int offset, int len ) { - int crc = Crc32.crc( ab, offset, len ); - int hashSize = _arrayBitmap.length; - int idx = ( crc & 0xfffffff ) % hashSize; - byte[] abc = _arrayBitmap[idx]; - if ( abc != null && abc.length == len ) + probeCacheNode.ab = null; // crc based cache lookup only + probeCacheNode.crc = Crc32.crc( ab, offset, len ); + + CacheNode cn = (CacheNode)cache.get( probeCacheNode ); + if ( cn != null ) { - int i = 0; - while (i < len) + byte[] cab = cn.ab; + if ( cab.length == len ) { - if ( ab[offset + i] != abc[i] ) - break; - i++; + for( int i=0; i counts = new TreeMap(); @@ -650,7 +648,8 @@ public abstract class BExpressionContext implements IByteArrayUnifier // determine the build-in variable indices String[] varNames = getBuildInVariableNames(); - buildInVariableIdx = new int[varNames.length]; + nBuildInVars = varNames.length; + buildInVariableIdx = new int[nBuildInVars]; for( int vi=0; vi= 9999.f ) { - float reverseCostFactor = getInverseCostfactor(); + setInverseVars(); + float reverseCostFactor = getCostfactor(); if ( reverseCostFactor < minCostFactor ) { minCostFactor = reverseCostFactor; diff --git a/brouter-expressions/src/main/java/btools/expressions/CacheNode.java b/brouter-expressions/src/main/java/btools/expressions/CacheNode.java new file mode 100644 index 0000000..ff0327a --- /dev/null +++ b/brouter-expressions/src/main/java/btools/expressions/CacheNode.java @@ -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 ); + } +} diff --git a/brouter-expressions/src/main/java/btools/expressions/VarWrapper.java b/brouter-expressions/src/main/java/btools/expressions/VarWrapper.java new file mode 100644 index 0000000..dc479b0 --- /dev/null +++ b/brouter-expressions/src/main/java/btools/expressions/VarWrapper.java @@ -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 ); + } +} diff --git a/brouter-util/src/main/java/btools/util/ByteDataReader.java b/brouter-util/src/main/java/btools/util/ByteDataReader.java index ca51bdc..857a9b2 100644 --- a/brouter-util/src/main/java/btools/util/ByteDataReader.java +++ b/brouter-util/src/main/java/btools/util/ByteDataReader.java @@ -107,23 +107,6 @@ public class ByteDataReader 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() { byte b; @@ -135,15 +118,7 @@ public class ByteDataReader if ( b >= 0 ) return v; v |= ( (b=ab[aboffset++]) & 0x7f ) << 21; if ( b >= 0 ) return v; - v |= ( (b=ab[aboffset++]) & 0x7f ) << 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; + v |= ( (b=ab[aboffset++]) & 0xf ) << 28; return v; } diff --git a/brouter-util/src/main/java/btools/util/ByteDataWriter.java b/brouter-util/src/main/java/btools/util/ByteDataWriter.java index 130c551..1f299f4 100644 --- a/brouter-util/src/main/java/btools/util/ByteDataWriter.java +++ b/brouter-util/src/main/java/btools/util/ByteDataWriter.java @@ -13,7 +13,7 @@ public class ByteDataWriter extends ByteDataReader super ( byteArray ); } - public void writeInt( int v ) + public final void writeInt( int v ) { ab[aboffset++] = (byte)( (v >> 24) & 0xff ); ab[aboffset++] = (byte)( (v >> 16) & 0xff ); @@ -21,7 +21,7 @@ public class ByteDataWriter extends ByteDataReader 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 >> 48) & 0xff ); @@ -33,35 +33,35 @@ public class ByteDataWriter extends ByteDataReader ab[aboffset++] = (byte)( (v ) & 0xff ); } - public void writeBoolean( boolean v) + public final void writeBoolean( boolean v) { ab[aboffset++] = (byte)( v ? 1 : 0 ); } - public void writeByte( int v ) + public final void writeByte( int v ) { 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 ) & 0xff ); } - public void write( byte[] sa ) + public final void write( byte[] sa ) { System.arraycopy( sa, 0, ab, 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 ); aboffset += len; } - public void writeVarBytes( byte[] sa ) + public final void writeVarBytes( byte[] sa ) { 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 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]; System.arraycopy( ab, 0, c, 0, aboffset ); @@ -102,12 +102,12 @@ public class ByteDataWriter extends ByteDataReader * * @return the offset of the placeholder */ - public int writeSizePlaceHolder() + public final int writeSizePlaceHolder() { return aboffset++; } - public void injectSize( int sizeoffset ) + public final void injectSize( int sizeoffset ) { int size = 0; int datasize = aboffset-sizeoffset-1; @@ -127,23 +127,47 @@ public class ByteDataWriter extends ByteDataReader 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; + if ( ( v >>>= 7 ) == 0 ) { - int i7 = v & 0x7f; - v >>= 7; - if ( v != 0 ) i7 |= 0x80; - ab[aboffset++] = (byte)( i7 & 0xff ); + ab[aboffset++] = (byte) ( i7 ); + return; } - while( v != 0 ); - return aboffset - start; + 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 ); + + 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() diff --git a/brouter-util/src/main/java/btools/util/LruMap.java b/brouter-util/src/main/java/btools/util/LruMap.java new file mode 100644 index 0000000..dcf6214 --- /dev/null +++ b/brouter-util/src/main/java/btools/util/LruMap.java @@ -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++; + } +} diff --git a/brouter-util/src/main/java/btools/util/LruMapNode.java b/brouter-util/src/main/java/btools/util/LruMapNode.java new file mode 100644 index 0000000..6a0c368 --- /dev/null +++ b/brouter-util/src/main/java/btools/util/LruMapNode.java @@ -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) +}