/* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.sail.nativerdf.datastore; import java.io.File; import java.io.IOException; import info.aduna.io.ByteArrayUtil; import org.openrdf.sail.nativerdf.btree.BTree; import org.openrdf.sail.nativerdf.btree.RecordIterator; import org.openrdf.sail.nativerdf.btree.DefaultRecordComparator; /** * A file-based hash table based on B-Trees. * * @author Arjohn Kampman */ public class HashIndex { /*-----------* * Constants * *-----------*/ // Records consist of 8 bytes: // byte 0-3 : hash code // byte 4-7 : ID private static final int RECORD_LENGTH = 8; private static final int HASH_IDX = 0; private static final int ID_IDX = 4; private static final byte[] SEARCH_MASK = new byte[RECORD_LENGTH]; static { ByteArrayUtil.putInt(0xffffffff, SEARCH_MASK, HASH_IDX); } /*-----------* * Variables * *-----------*/ /** * The file that is used to store the hash index. */ private File file; /** * The BTree that is used to store the hash code records. */ private BTree btree; /*--------------* * Constructors * *--------------*/ public HashIndex(File file) throws IOException { this.file = file; btree = new BTree(file, 4096, RECORD_LENGTH, new DefaultRecordComparator()); } /*---------* * Methods * *---------*/ public File getFile() { return file; } /** * Gets an iterator that iterates over the IDs with hash codes that match the * specified hash code. */ public IDIterator getIDIterator(int hash) throws IOException { return new IDIterator(hash); } /** * Stores an ID under the specified hash code in this hash index. */ public void storeID(int hash, int id) throws IOException { btree.insert(getData(hash, id)); } /** * Removes the specified ID from this hash index. */ public void removeID(int hash, int id) throws IOException { btree.remove(getData(hash, id)); } public void sync() throws IOException { btree.sync(); } public void clear() throws IOException { btree.clear(); } public void close() throws IOException { btree.close(); } private byte[] getData(int hash, int id) { byte[] data = new byte[RECORD_LENGTH]; ByteArrayUtil.putInt(hash, data, HASH_IDX); ByteArrayUtil.putInt(id, data, ID_IDX); return data; } private byte[] getMinValue(int hash) { byte[] minValue = new byte[RECORD_LENGTH]; ByteArrayUtil.putInt(hash, minValue, HASH_IDX); return minValue; } private byte[] getMaxValue(int hash) { byte[] maxValue = new byte[RECORD_LENGTH]; ByteArrayUtil.putInt(hash, maxValue, HASH_IDX); ByteArrayUtil.putInt(0xffffffff, maxValue, ID_IDX); return maxValue; } /*------------------------* * Inner class IDIterator * *------------------------*/ public class IDIterator { private RecordIterator btreeIter; private IDIterator(int hash) throws IOException { byte[] minValue = getMinValue(hash); byte[] maxValue = getMaxValue(hash); btreeIter = btree.iterateRange(minValue, maxValue); } /** * Returns the next ID that has been mapped to the specified hash code, or * <tt>-1</tt> if no more IDs were found. */ public int next() throws IOException { byte[] result = btreeIter.next(); if (result == null) { return -1; } return ByteArrayUtil.getInt(result, ID_IDX); } public void close() throws IOException { btreeIter.close(); } } // End inner class IDIterator }