From 05aa0960f2c5ca68e52e59366aebbac8f9cfd7a7 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Sat, 10 Dec 2011 14:14:52 +0800 Subject: [PATCH] Various performance and concurrency optimizations --- src/main/java/org/dynmap/TileHashManager.java | 62 ++++++++++---- .../org/dynmap/hdmap/DefaultHDLighting.java | 4 +- .../org/dynmap/hdmap/DefaultHDShader.java | 8 +- .../org/dynmap/hdmap/IsoHDPerspective.java | 28 ++++--- .../org/dynmap/hdmap/TexturePackHDShader.java | 4 +- .../org/dynmap/utils/FileLockManager.java | 83 +++++++++++-------- 6 files changed, 115 insertions(+), 74 deletions(-) diff --git a/src/main/java/org/dynmap/TileHashManager.java b/src/main/java/org/dynmap/TileHashManager.java index d3354421..a97bc99f 100644 --- a/src/main/java/org/dynmap/TileHashManager.java +++ b/src/main/java/org/dynmap/TileHashManager.java @@ -2,6 +2,7 @@ package org.dynmap; import java.io.File; import java.io.RandomAccessFile; import java.util.Arrays; +import java.util.LinkedList; import java.io.IOException; import java.util.zip.CRC32; @@ -59,26 +60,34 @@ public class TileHashManager { } /* Write to file */ public void writeToFile(File tiledir, byte[] crcbuf) { + RandomAccessFile fd = null; try { - RandomAccessFile fd = new RandomAccessFile(getHashFile(tiledir), "rw"); + fd = new RandomAccessFile(getHashFile(tiledir), "rw"); fd.seek(0); fd.write(crcbuf); - fd.close(); } catch (IOException iox) { Log.severe("Error writing hash file - " + getHashFile(tiledir).getPath()); + } finally { + if(fd != null) { + try { fd.close(); } catch (IOException iox) {} + } } } /* Read from file */ public void readFromFile(File tiledir, byte[] crcbuf) { + RandomAccessFile fd = null; try { - RandomAccessFile fd = new RandomAccessFile(getHashFile(tiledir), "r"); + fd = new RandomAccessFile(getHashFile(tiledir), "r"); fd.seek(0); fd.read(crcbuf); - fd.close(); } catch (IOException iox) { Arrays.fill(crcbuf, (byte)0xFF); writeToFile(tiledir, crcbuf); + } finally { + if(fd != null) { + try { fd.close(); } catch (IOException iox) {} + } } } /* Read CRC */ @@ -100,8 +109,8 @@ public class TileHashManager { private static final int MAX_CACHED_TILEHASHFILES = 25; private Object lock = new Object(); private LRULinkedHashMap tilehash = new LRULinkedHashMap(MAX_CACHED_TILEHASHFILES); - private CRC32 crc32 = new CRC32(); - private byte[] crcworkbuf = new byte[8192]; + private LinkedList crcworkbufs = new LinkedList(); + private LinkedList crcs = new LinkedList(); public TileHashManager(File tileroot, boolean enabled) { tiledir = tileroot; @@ -130,22 +139,41 @@ public class TileHashManager { if(!enabled) { return 0; /* Return value that doesn't match */ } + CRC32 crc32; + byte[] crcworkbuf; synchronized(lock) { - if(crcworkbuf.length < (4*newbuf.length)){ + if(crcworkbufs.isEmpty()) { crcworkbuf = new byte[4*newbuf.length]; } - for(int i = 0, off = 0; i < newbuf.length; i++) { - int v = newbuf[i]; - crcworkbuf[off++] = (byte)v; - crcworkbuf[off++] = (byte)(v>>8); - crcworkbuf[off++] = (byte)(v>>16); - crcworkbuf[off++] = (byte)(v>>24); + else { + crcworkbuf = crcworkbufs.removeFirst(); + } + if(crcs.isEmpty()) { + crc32 = new CRC32(); + } + else { + crc32 = crcs.removeFirst(); + crc32.reset(); } - /* Calculate CRC-32 for buffer */ - crc32.reset(); - crc32.update(crcworkbuf, 0, 4*newbuf.length); - return crc32.getValue(); } + if(crcworkbuf.length < (4*newbuf.length)){ + crcworkbuf = new byte[4*newbuf.length]; + } + for(int i = 0, off = 0; i < newbuf.length; i++) { + int v = newbuf[i]; + crcworkbuf[off++] = (byte)v; + crcworkbuf[off++] = (byte)(v>>8); + crcworkbuf[off++] = (byte)(v>>16); + crcworkbuf[off++] = (byte)(v>>24); + } + /* Calculate CRC-32 for buffer */ + crc32.update(crcworkbuf, 0, 4*newbuf.length); + long v = crc32.getValue(); + synchronized(lock) { + crcworkbufs.addFirst(crcworkbuf); + crcs.addFirst(crc32); + } + return v; } /* Update hashcode for given tile */ public void updateHashCode(String key, String subtype, int tx, int ty, long newcrc) { diff --git a/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java b/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java index 92b2fb8b..2a62d045 100644 --- a/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java +++ b/src/main/java/org/dynmap/hdmap/DefaultHDLighting.java @@ -21,8 +21,8 @@ public class DefaultHDLighting implements HDLighting { /* Apply lighting to given pixel colors (1 outcolor if normal, 2 if night/day) */ public void applyLighting(HDPerspectiveState ps, HDShaderState ss, Color incolor, Color[] outcolor) { - for(Color oc: outcolor) - oc.setColor(incolor); + for(int i = 0; i < outcolor.length; i++) + outcolor[i].setColor(incolor); } /* Test if Biome Data is needed for this renderer */ diff --git a/src/main/java/org/dynmap/hdmap/DefaultHDShader.java b/src/main/java/org/dynmap/hdmap/DefaultHDShader.java index c29da3fa..3693af87 100644 --- a/src/main/java/org/dynmap/hdmap/DefaultHDShader.java +++ b/src/main/java/org/dynmap/hdmap/DefaultHDShader.java @@ -117,8 +117,8 @@ public class DefaultHDShader implements HDShader { * Reset renderer state for new ray */ public void reset(HDPerspectiveState ps) { - for(Color c: color) - c.setTransparent(); + for(int i = 0; i < color.length; i++) + color[i].setTransparent(); pixelodd = (ps.getPixelX() & 0x3) + (ps.getPixelY()<<1); } @@ -169,8 +169,8 @@ public class DefaultHDShader implements HDShader { lighting.applyLighting(ps, this, c, tmpcolor); /* If we got alpha from subblock model, use it instead */ if(subalpha >= 0) { - for(Color clr : tmpcolor) - clr.setAlpha(Math.max(subalpha,clr.getAlpha())); + for(int j = 0; j < tmpcolor.length; j++) + tmpcolor[j].setAlpha(Math.max(subalpha,tmpcolor[j].getAlpha())); } /* Blend color with accumulated color (weighted by alpha) */ if(!transparency) { /* No transparency support */ diff --git a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java index 771bc918..10c96fd3 100644 --- a/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java +++ b/src/main/java/org/dynmap/hdmap/IsoHDPerspective.java @@ -145,7 +145,8 @@ public class IsoHDPerspective implements HDPerspective { BlockStep [] steps = { BlockStep.Y_PLUS, BlockStep.X_MINUS, BlockStep.X_PLUS, BlockStep.Z_MINUS, BlockStep.Z_PLUS }; emitlevel = skylevel = 0; - for(BlockStep s : steps) { + for(int i = 0; i < steps.length; i++) { + BlockStep s = steps[i]; mapiter.stepPosition(s); int v = mapiter.getBlockEmittedLight(); if(v > emitlevel) emitlevel = v; @@ -448,7 +449,8 @@ public class IsoHDPerspective implements HDPerspective { mapiter.getBlockTypeIDAt(BlockStep.X_MINUS) }; /* To north */ int flags = 0; for(int i = 0; i < 4; i++) - if(ids[i] == REDSTONE_BLKTYPEID) flags |= (1< baoslist = new LinkedList(); private static Object baos_lock = new Object(); /** * Wrapper for IOImage.write - implements retries for busy files @@ -150,45 +151,55 @@ public class FileLockManager { int retrycnt = 0; boolean done = false; byte[] rslt; + ByteArrayOutputStream baos; synchronized(baos_lock) { - baos.reset(); - ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */ - if(fmt.getFileExt().equals("jpg")) { - WritableRaster raster = img.getRaster(); - WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), - img.getHeight(), 0, 0, new int[] {0, 1, 2}); - DirectColorModel cm = (DirectColorModel)img.getColorModel(); - DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), - cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask()); - // now create the new buffer that is used ot write the image: - BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null); - - // Find a jpeg writer - ImageWriter writer = null; - Iterator iter = ImageIO.getImageWritersByFormatName("jpg"); - if (iter.hasNext()) { - writer = (ImageWriter)iter.next(); - } - if(writer == null) { - Log.severe("No JPEG ENCODER - Java VM does not support JPEG encoding"); - return; - } - ImageWriteParam iwp = writer.getDefaultWriteParam(); - iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); - iwp.setCompressionQuality(fmt.getQuality()); - - ImageOutputStream ios = ImageIO.createImageOutputStream(baos); - writer.setOutput(ios); - - writer.write(null, new IIOImage(rgbBuffer, null, null), iwp); - writer.dispose(); - - rgbBuffer.flush(); + if(baoslist.isEmpty()) { + baos = new ByteArrayOutputStream(); } else { - ImageIO.write(img, fmt.getFileExt(), baos); /* Write to byte array stream - prevent bogus I/O errors */ + baos = baoslist.removeFirst(); + baos.reset(); } - rslt = baos.toByteArray(); + } + ImageIO.setUseCache(false); /* Don't use file cache - too small to be worth it */ + if(fmt.getFileExt().equals("jpg")) { + WritableRaster raster = img.getRaster(); + WritableRaster newRaster = raster.createWritableChild(0, 0, img.getWidth(), + img.getHeight(), 0, 0, new int[] {0, 1, 2}); + DirectColorModel cm = (DirectColorModel)img.getColorModel(); + DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(), + cm.getRedMask(), cm.getGreenMask(), cm.getBlueMask()); + // now create the new buffer that is used ot write the image: + BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null); + + // Find a jpeg writer + ImageWriter writer = null; + Iterator iter = ImageIO.getImageWritersByFormatName("jpg"); + if (iter.hasNext()) { + writer = (ImageWriter)iter.next(); + } + if(writer == null) { + Log.severe("No JPEG ENCODER - Java VM does not support JPEG encoding"); + return; + } + ImageWriteParam iwp = writer.getDefaultWriteParam(); + iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + iwp.setCompressionQuality(fmt.getQuality()); + + ImageOutputStream ios = ImageIO.createImageOutputStream(baos); + writer.setOutput(ios); + + writer.write(null, new IIOImage(rgbBuffer, null, null), iwp); + writer.dispose(); + + rgbBuffer.flush(); + } + else { + ImageIO.write(img, fmt.getFileExt(), baos); /* Write to byte array stream - prevent bogus I/O errors */ + } + rslt = baos.toByteArray(); + synchronized(baos_lock) { + baoslist.addFirst(baos); } while(!done) { RandomAccessFile f = null;