44import java .lang .ref .ReferenceQueue ;
55import java .lang .ref .WeakReference ;
66import java .lang .ref .SoftReference ;
7+ import java .util .HashMap ;
78import java .util .IdentityHashMap ;
89import java .util .LinkedHashMap ;
910import java .util .Map ;
1011
1112import org .dynmap .utils .DynIntHashMap ;
1213
13- // Generic chunk cache
14+ // Generic chunk cache
1415public class GenericChunkCache {
1516 public static class ChunkCacheRec {
1617 public GenericChunk ss ;
@@ -23,22 +24,26 @@ public static class ChunkCacheRec {
2324 private long cache_attempts ;
2425 private long cache_success ;
2526 private boolean softref ;
27+ // World name -> small integer ID, used to build long cache keys without String concatenation.
28+ // Accessed only while holding snapcachelock.
29+ private final HashMap <String , Integer > worldIds = new HashMap <String , Integer >();
30+ private int nextWorldId = 0 ;
2631
2732 private static class CacheRec {
2833 Reference <ChunkCacheRec > ref ;
2934 }
30-
35+
3136 @ SuppressWarnings ("serial" )
32- public class CacheHashMap extends LinkedHashMap <String , CacheRec > {
37+ public class CacheHashMap extends LinkedHashMap <Long , CacheRec > {
3338 private int limit ;
34- private IdentityHashMap <Reference <ChunkCacheRec >, String > reverselookup ;
39+ private IdentityHashMap <Reference <ChunkCacheRec >, Long > reverselookup ;
3540
3641 public CacheHashMap (int lim ) {
3742 super (16 , (float )0.75 , true );
3843 limit = lim ;
39- reverselookup = new IdentityHashMap <Reference <ChunkCacheRec >, String >();
44+ reverselookup = new IdentityHashMap <Reference <ChunkCacheRec >, Long >();
4045 }
41- protected boolean removeEldestEntry (Map .Entry <String , CacheRec > last ) {
46+ protected boolean removeEldestEntry (Map .Entry <Long , CacheRec > last ) {
4247 boolean remove = (size () >= limit );
4348 if (remove && (last != null ) && (last .getValue () != null )) {
4449 reverselookup .remove (last .getValue ().ref );
@@ -56,15 +61,26 @@ public GenericChunkCache(int max_size, boolean softref) {
5661 refqueue = new ReferenceQueue <ChunkCacheRec >();
5762 this .softref = softref ;
5863 }
59- private String getKey (String w , int cx , int cz ) {
60- return w + ":" + cx + ":" + cz ;
64+ /**
65+ * Encode world name + chunk coords as a single long key.
66+ * Worlds are assigned small integer IDs (10 bits) on first use.
67+ * cx and cz are each encoded in 27 bits (signed, supports ±8M chunks / ±128M blocks).
68+ * Must be called while holding snapcachelock.
69+ */
70+ private long getKey (String w , int cx , int cz ) {
71+ Integer wid = worldIds .get (w );
72+ if (wid == null ) {
73+ wid = nextWorldId ++;
74+ worldIds .put (w , wid );
75+ }
76+ return ((long )(wid & 0x3FF ) << 54 ) | ((long )(cx & 0x7FFFFFF ) << 27 ) | (long )(cz & 0x7FFFFFF );
6177 }
6278 /**
6379 * Invalidate cached snapshot, if in cache
6480 */
6581 public void invalidateSnapshot (String w , int x , int y , int z ) {
66- String key = getKey (w , x >>4 , z >>4 );
6782 synchronized (snapcachelock ) {
83+ long key = getKey (w , x >>4 , z >>4 );
6884 CacheRec rec = (snapcache != null ) ? snapcache .remove (key ) : null ;
6985 if (rec != null ) {
7086 snapcache .reverselookup .remove (rec .ref );
@@ -77,10 +93,10 @@ public void invalidateSnapshot(String w, int x, int y, int z) {
7793 * Invalidate cached snapshot, if in cache
7894 */
7995 public void invalidateSnapshot (String w , int x0 , int y0 , int z0 , int x1 , int y1 , int z1 ) {
80- for ( int xx = ( x0 >> 4 ); xx <= ( x1 >> 4 ); xx ++ ) {
81- for (int zz = (z0 >>4 ); zz <= (z1 >>4 ); zz ++) {
82- String key = getKey ( w , xx , zz );
83- synchronized ( snapcachelock ) {
96+ synchronized ( snapcachelock ) {
97+ for (int xx = (x0 >>4 ); xx <= (x1 >>4 ); xx ++) {
98+ for ( int zz = ( z0 >> 4 ); zz <= ( z1 >> 4 ); zz ++) {
99+ long key = getKey ( w , xx , zz );
84100 CacheRec rec = (snapcache != null ) ? snapcache .remove (key ) : null ;
85101 if (rec != null ) {
86102 snapcache .reverselookup .remove (rec .ref );
@@ -95,11 +111,11 @@ public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1,
95111 * Look for chunk snapshot in cache
96112 */
97113 public ChunkCacheRec getSnapshot (String w , int chunkx , int chunkz ) {
98- String key = getKey (w , chunkx , chunkz );
99114 processRefQueue ();
100115 ChunkCacheRec ss = null ;
101116 CacheRec rec ;
102117 synchronized (snapcachelock ) {
118+ long key = getKey (w , chunkx , chunkz );
103119 rec = (snapcache != null ) ? snapcache .get (key ) : null ;
104120 if (rec != null ) {
105121 ss = rec .ref .get ();
@@ -118,14 +134,14 @@ public ChunkCacheRec getSnapshot(String w, int chunkx, int chunkz) {
118134 * Add chunk snapshot to cache
119135 */
120136 public void putSnapshot (String w , int chunkx , int chunkz , ChunkCacheRec ss ) {
121- String key = getKey (w , chunkx , chunkz );
122137 processRefQueue ();
123138 CacheRec rec = new CacheRec ();
124139 if (softref )
125140 rec .ref = new SoftReference <ChunkCacheRec >(ss , refqueue );
126141 else
127142 rec .ref = new WeakReference <ChunkCacheRec >(ss , refqueue );
128143 synchronized (snapcachelock ) {
144+ long key = getKey (w , chunkx , chunkz );
129145 CacheRec prevrec = (snapcache != null ) ? snapcache .put (key , rec ) : null ;
130146 if (prevrec != null ) {
131147 snapcache .reverselookup .remove (prevrec .ref );
@@ -140,7 +156,7 @@ private void processRefQueue() {
140156 Reference <? extends ChunkCacheRec > ref ;
141157 while ((ref = refqueue .poll ()) != null ) {
142158 synchronized (snapcachelock ) {
143- String k = (snapcache != null ) ? snapcache .reverselookup .remove (ref ) : null ;
159+ Long k = (snapcache != null ) ? snapcache .reverselookup .remove (ref ) : null ;
144160 if (k != null ) {
145161 snapcache .remove (k );
146162 }
0 commit comments