// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.pgsnapshot.common; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import org.openstreetmap.osmosis.core.util.FixedPrecisionCoordinateConvertor; /** * An in-memory node location store implementation. * * @author Brett Henderson */ public class InMemoryNodeLocationStore implements NodeLocationStore { private static final Logger LOG = Logger.getLogger(InMemoryNodeLocationStore.class.getName()); private static final int NODE_DATA_SIZE = 9; private static final int BUFFER_ELEMENT_COUNT = 131072; private static final int BUFFER_SIZE = NODE_DATA_SIZE * BUFFER_ELEMENT_COUNT; private List<byte[]> buffers; private NodeLocation invalidNodeLocation; /** * Creates a new instance. */ public InMemoryNodeLocationStore() { buffers = new ArrayList<byte[]>(); invalidNodeLocation = new NodeLocation(); } /** * Writes a summary of the current memory consumption at the specified * logging level. * * @param level * The logging level to write the summary at. */ private void logMemoryConsumption(Level level) { if (LOG.isLoggable(level)) { Runtime runtime; long totalUsed; double percentageUsed; long maxMemory; DecimalFormat percentageFormat; runtime = Runtime.getRuntime(); percentageFormat = new DecimalFormat("#0.##"); // Calculate the percentage of memory currently used. percentageUsed = ((double) runtime.totalMemory()) / runtime.maxMemory() * 100; totalUsed = ((long) buffers.size()) * BUFFER_SIZE / 1048576; maxMemory = runtime.maxMemory() / 1048576; LOG.log( level, "The store contains " + buffers.size() + " buffers of " + (BUFFER_SIZE / 1024) + "KB, total " + totalUsed + "MB."); LOG.log( level, "The JVM is using " + percentageFormat.format(percentageUsed) + "% of the maximum " + maxMemory + "MB of memory."); } } /** * Writes the specified integer to a buffer. * * @param value * The integer to write. * @param buffer * The destination buffer. * @param initialOffset * The buffer offset to begin writing at. */ private void writeIntToBuffer(int value, byte[] buffer, int initialOffset) { int offset; offset = initialOffset; buffer[offset++] = (byte) (value >>> 24); buffer[offset++] = (byte) (value >>> 16); buffer[offset++] = (byte) (value >>> 8); buffer[offset++] = (byte) value; } /** * Reads an integer from a buffer. * * @param buffer * The buffer to read from. * @param initialOffset * The buffer offset to begin reading from. * @return The integer. */ private int readIntFromBuffer(byte[] buffer, int initialOffset) { int offset; offset = initialOffset; return ( buffer[offset++] << 24) + ((buffer[offset++] & 0xFF) << 16) + ((buffer[offset++] & 0xFF) << 8) + (buffer[offset++] & 0xFF); } /** * {@inheritDoc} */ @Override public void addLocation(long nodeId, NodeLocation nodeLocation) { int bufferIndex; byte[] buffer; int bufferOffset; bufferIndex = (int) (nodeId / BUFFER_ELEMENT_COUNT); while (bufferIndex >= buffers.size()) { buffer = new byte[BUFFER_SIZE]; buffers.add(buffer); logMemoryConsumption(Level.FINER); } buffer = buffers.get(bufferIndex); bufferOffset = (int) ((nodeId - (bufferIndex * BUFFER_ELEMENT_COUNT)) * NODE_DATA_SIZE); buffer[bufferOffset++] = 1; writeIntToBuffer( FixedPrecisionCoordinateConvertor.convertToFixed(nodeLocation.getLongitude()), buffer, bufferOffset); bufferOffset += 4; writeIntToBuffer( FixedPrecisionCoordinateConvertor.convertToFixed(nodeLocation.getLatitude()), buffer, bufferOffset); bufferOffset += 4; } /** * {@inheritDoc} */ @Override public NodeLocation getNodeLocation(long nodeId) { NodeLocation nodeLocation; int bufferIndex; nodeLocation = invalidNodeLocation; bufferIndex = (int) (nodeId / BUFFER_ELEMENT_COUNT); if (bufferIndex < buffers.size()) { byte[] buffer; int bufferOffset; byte validFlag; buffer = buffers.get(bufferIndex); bufferOffset = (int) ((nodeId - (bufferIndex * BUFFER_ELEMENT_COUNT)) * NODE_DATA_SIZE); validFlag = buffer[bufferOffset++]; if (validFlag != 0) { int longitude; int latitude; longitude = readIntFromBuffer(buffer, bufferOffset); bufferOffset += 4; latitude = readIntFromBuffer(buffer, bufferOffset); bufferOffset += 4; nodeLocation = new NodeLocation( FixedPrecisionCoordinateConvertor.convertToDouble(longitude), FixedPrecisionCoordinateConvertor.convertToDouble(latitude) ); } } return nodeLocation; } /** * {@inheritDoc} */ @Override public void close() { logMemoryConsumption(Level.FINE); } }