// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.pgsimple.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);
}
}