
org.oscim.tiling.source.mapfile.IndexCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vtm Show documentation
Show all versions of vtm Show documentation
OpenGL vector map library written in Java - running on Android, iOS, Desktop and within the browser.
The newest version!
/*
* Copyright 2010, 2011, 2012 mapsforge.org
* Copyright 2017-2020 devemux86
*
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see .
*/
package org.oscim.tiling.source.mapfile;
import org.oscim.tiling.source.mapfile.header.SubFileParameter;
import org.oscim.utils.LRUCache;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A cache for database index blocks with a fixed size and LRU policy.
*/
class IndexCache {
/**
* Number of index entries that one index block consists of.
*/
private static final int INDEX_ENTRIES_PER_BLOCK = 128;
private static final Logger LOG = Logger.getLogger(IndexCache.class.getName());
/**
* Maximum size in bytes of one index block.
*/
private static final int SIZE_OF_INDEX_BLOCK = INDEX_ENTRIES_PER_BLOCK
* SubFileParameter.BYTES_PER_INDEX_ENTRY;
private final Map map;
private final FileChannel fileChannel;
/**
* @param inputChannel the map file from which the index should be read and cached.
* @param capacity the maximum number of entries in the cache.
* @throws IllegalArgumentException if the capacity is negative.
*/
IndexCache(FileChannel inputChannel, int capacity) {
this.fileChannel = inputChannel;
this.map = Collections.synchronizedMap(new LRUCache(capacity));
}
/**
* Destroy the cache at the end of its lifetime.
*/
void destroy() {
this.map.clear();
}
/**
* Returns the index entry of a block in the given map file. If the required
* index entry is not cached, it will be
* read from the map file index and put in the cache.
*
* @param subFileParameter the parameters of the map file for which the index entry is
* needed.
* @param blockNumber the number of the block in the map file.
* @return the index entry or -1 if the block number is invalid.
*/
synchronized long getIndexEntry(SubFileParameter subFileParameter, long blockNumber) {
try {
// check if the block number is out of bounds
if (blockNumber >= subFileParameter.numberOfBlocks) {
return -1;
}
// calculate the index block number
long indexBlockNumber = blockNumber / INDEX_ENTRIES_PER_BLOCK;
// create the cache entry key for this request
IndexCacheEntryKey indexCacheEntryKey = new IndexCacheEntryKey(subFileParameter,
indexBlockNumber);
// check for cached index block
byte[] indexBlock = this.map.get(indexCacheEntryKey);
if (indexBlock == null) {
// cache miss, seek to the correct index block in the file and read it
long indexBlockPosition = subFileParameter.indexStartAddress + indexBlockNumber
* SIZE_OF_INDEX_BLOCK;
int remainingIndexSize = (int) (subFileParameter.indexEndAddress - indexBlockPosition);
int indexBlockSize = Math.min(SIZE_OF_INDEX_BLOCK, remainingIndexSize);
indexBlock = new byte[indexBlockSize];
ByteBuffer indexBlockWrapper = ByteBuffer.wrap(indexBlock, 0, indexBlockSize);
synchronized (this.fileChannel) {
this.fileChannel.position(indexBlockPosition);
if (this.fileChannel.read(indexBlockWrapper) != indexBlockSize) {
LOG.warning("reading the current index block has failed");
return -1;
}
}
// put the index block in the map
this.map.put(indexCacheEntryKey, indexBlock);
}
// calculate the address of the index entry inside the index block
long indexEntryInBlock = blockNumber % INDEX_ENTRIES_PER_BLOCK;
int addressInIndexBlock = (int) (indexEntryInBlock * SubFileParameter.BYTES_PER_INDEX_ENTRY);
// return the real index entry
return Deserializer.getFiveBytesLong(indexBlock, addressInIndexBlock);
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
return -1;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy