All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.graphhopper.storage.RAMDataAccess Maven / Gradle / Ivy

Go to download

GraphHopper is a fast and memory efficient Java road routing engine working seamlessly with OpenStreetMap data.

There is a newer version: 10.0
Show newest version
/*
 *  Licensed to GraphHopper GmbH under one or more contributor
 *  license agreements. See the NOTICE file distributed with this work for
 *  additional information regarding copyright ownership.
 *
 *  GraphHopper GmbH licenses this file to you under the Apache License,
 *  Version 2.0 (the "License"); you may not use this file except in
 *  compliance with the License. You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.graphhopper.storage;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

/**
 * This is an in-memory byte-based data structure with the possibility to be stored on flush().
 * Read thread-safe.
 * 

* * @author Peter Karich */ public class RAMDataAccess extends AbstractDataAccess { private byte[][] segments = new byte[0][]; private boolean store; RAMDataAccess(String name, String location, boolean store, int segmentSize) { super(name, location, segmentSize); this.store = store; } /** * @param store true if in-memory data should be saved when calling flush */ public RAMDataAccess store(boolean store) { this.store = store; return this; } @Override public boolean isStoring() { return store; } @Override public RAMDataAccess create(long bytes) { if (segments.length > 0) throw new IllegalThreadStateException("already created"); ensureCapacity(Math.max(10 * 4, bytes)); return this; } @Override public boolean ensureCapacity(long bytes) { if (bytes < 0) throw new IllegalArgumentException("new capacity has to be strictly positive"); long cap = getCapacity(); long newBytes = bytes - cap; if (newBytes <= 0) return false; int segmentsToCreate = (int) (newBytes / segmentSizeInBytes); if (newBytes % segmentSizeInBytes != 0) segmentsToCreate++; try { byte[][] newSegs = Arrays.copyOf(segments, segments.length + segmentsToCreate); for (int i = segments.length; i < newSegs.length; i++) { newSegs[i] = new byte[1 << segmentSizePower]; } segments = newSegs; } catch (OutOfMemoryError err) { throw new OutOfMemoryError(err.getMessage() + " - problem when allocating new memory. Old capacity: " + cap + ", new bytes:" + newBytes + ", segmentSizeIntsPower:" + segmentSizePower + ", new segments:" + segmentsToCreate + ", existing:" + segments.length); } return true; } @Override public boolean loadExisting() { if (segments.length > 0) throw new IllegalStateException("already initialized"); if (isClosed()) throw new IllegalStateException("already closed"); if (!store) return false; File file = new File(getFullName()); if (!file.exists() || file.length() == 0) return false; try { try (RandomAccessFile raFile = new RandomAccessFile(getFullName(), "r")) { long byteCount = readHeader(raFile) - HEADER_OFFSET; if (byteCount < 0) return false; raFile.seek(HEADER_OFFSET); // raFile.readInt() <- too slow int segmentCount = (int) (byteCount / segmentSizeInBytes); if (byteCount % segmentSizeInBytes != 0) segmentCount++; segments = new byte[segmentCount][]; for (int s = 0; s < segmentCount; s++) { byte[] bytes = new byte[segmentSizeInBytes]; int read = raFile.read(bytes); if (read <= 0) throw new IllegalStateException("segment " + s + " is empty? " + toString()); segments[s] = bytes; } return true; } } catch (IOException ex) { throw new RuntimeException("Problem while loading " + getFullName(), ex); } } @Override public void flush() { if (closed) throw new IllegalStateException("already closed"); if (!store) return; try { try (RandomAccessFile raFile = new RandomAccessFile(getFullName(), "rw")) { long len = getCapacity(); writeHeader(raFile, len, segmentSizeInBytes); raFile.seek(HEADER_OFFSET); // raFile.writeInt() <- too slow, so copy into byte array for (int s = 0; s < segments.length; s++) { byte[] area = segments[s]; raFile.write(area); } } } catch (Exception ex) { throw new RuntimeException("Couldn't store bytes to " + toString(), ex); } } @Override public final void setInt(long bytePos, int value) { assert segmentSizePower > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); if (index + 4 > segmentSizeInBytes) throw new IllegalStateException("Padding required. Currently an int cannot be distributed over two segments. " + bytePos); bitUtil.fromInt(segments[bufferIndex], value, index); } @Override public final int getInt(long bytePos) { assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); if (index + 4 > segmentSizeInBytes) throw new IllegalStateException("Padding required. Currently an int cannot be distributed over two segments. " + bytePos); return bitUtil.toInt(segments[bufferIndex], index); } @Override public final void setShort(long bytePos, short value) { assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); if (index + 2 > segmentSizeInBytes) { // special case if short has to be written into two separate segments segments[bufferIndex][index] = (byte) (value); segments[bufferIndex + 1][0] = (byte) (value >>> 8); } else { bitUtil.fromShort(segments[bufferIndex], value, index); } } @Override public final short getShort(long bytePos) { assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); if (index + 2 > segmentSizeInBytes) return (short) ((segments[bufferIndex + 1][0] & 0xFF) << 8 | (segments[bufferIndex][index] & 0xFF)); else return bitUtil.toShort(segments[bufferIndex], index); } @Override public void setBytes(long bytePos, byte[] values, int length) { assert length <= segmentSizeInBytes : "the length has to be smaller or equal to the segment size: " + length + " vs. " + segmentSizeInBytes; assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); byte[] seg = segments[bufferIndex]; int delta = index + length - segmentSizeInBytes; if (delta > 0) { length -= delta; System.arraycopy(values, 0, seg, index, length); seg = segments[bufferIndex + 1]; System.arraycopy(values, length, seg, 0, delta); } else { System.arraycopy(values, 0, seg, index, length); } } @Override public void getBytes(long bytePos, byte[] values, int length) { assert length <= segmentSizeInBytes : "the length has to be smaller or equal to the segment size: " + length + " vs. " + segmentSizeInBytes; assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); byte[] seg = segments[bufferIndex]; int delta = index + length - segmentSizeInBytes; if (delta > 0) { length -= delta; System.arraycopy(seg, index, values, 0, length); seg = segments[bufferIndex + 1]; System.arraycopy(seg, 0, values, length, delta); } else { System.arraycopy(seg, index, values, 0, length); } } @Override public final void setByte(long bytePos, byte value) { assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); segments[bufferIndex][index] = value; } @Override public final byte getByte(long bytePos) { assert segments.length > 0 : "call create or loadExisting before usage!"; int bufferIndex = (int) (bytePos >>> segmentSizePower); int index = (int) (bytePos & indexDivisor); return segments[bufferIndex][index]; } @Override public void close() { super.close(); segments = new byte[0][]; closed = true; } @Override public long getCapacity() { return (long) getSegments() * segmentSizeInBytes; } @Override public int getSegments() { return segments.length; } @Override public DAType getType() { if (isStoring()) return DAType.RAM_STORE; return DAType.RAM; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy