blob: 3976120525fc15dd13896a88a157d4d6404862f7 [file] [log] [blame]
/* Copyright (c) 2001-2010, The HSQL Development Group
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the HSQL Development Group nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.hsqldb.store;
/**
* A chained bucket hash index implementation.
*
* hashTable and linkTable are arrays of signed integral types. This
* implementation uses int as the type but short or byte can be used for
* smaller index sizes (cardinality).
*
* hashTable[index] contains the pointer to the first node with
* (index == hash modulo hashTable.length) or -1 if there is no corresponding
* node. linkTable[{0,newNodePointer}] (the range between 0 and newNodePointer)
* contains either the pointer to the next node or -1 if there is no
* such node. reclaimedNodeIndex contains a pointer to an element
* of linkTable which is the first element in the list of reclaimed nodes
* (nodes no longer in index) or -1 if there is no such node.
*
* elemenet at and above linkTable[newNodePointer] have never been used
* as a node and their contents is not significant.
*
* @author Fred Toussi (fredt@users dot sourceforge.net)
* @version 1.9.0
* @since 1.7.2
*/
class HashIndex {
int[] hashTable;
int[] linkTable;
int newNodePointer;
int elementCount;
int reclaimedNodePointer = -1;
boolean fixedSize;
boolean modified;
HashIndex(int hashTableSize, int capacity, boolean fixedSize) {
if (capacity < hashTableSize) {
capacity = hashTableSize;
}
reset(hashTableSize, capacity);
this.fixedSize = fixedSize;
}
/**
* Reset the structure with a new size as empty.
*
* @param hashTableSize
* @param capacity
*/
void reset(int hashTableSize, int capacity) {
int[] newHT = new int[hashTableSize];
int[] newLT = new int[capacity];
// allocate memory before assigning
hashTable = newHT;
linkTable = newLT;
resetTables();
}
void resetTables() {
int to = hashTable.length;
int[] intArray = hashTable;
while (--to >= 0) {
intArray[to] = -1;
}
newNodePointer = 0;
elementCount = 0;
reclaimedNodePointer = -1;
modified = false;
}
/**
* Reset the index as empty.
*/
void clear() {
int to = linkTable.length;
int[] intArray = linkTable;
while (--to >= 0) {
intArray[to] = 0;
}
resetTables();
}
/**
* @param hash
*/
int getHashIndex(int hash) {
return (hash & 0x7fffffff) % hashTable.length;
}
/**
* Return the array index for a hash.
*
* @param hash the hash value used for indexing
* @return either -1 or the first node for this hash value
*/
int getLookup(int hash) {
if (elementCount == 0) {
return -1;
}
int index = (hash & 0x7fffffff) % hashTable.length;
return hashTable[index];
}
/**
* This looks from a given node, so the parameter is always > -1.
*
* @param lookup A valid node to look from
* @return either -1 or the next node from this node
*/
int getNextLookup(int lookup) {
return linkTable[lookup];
}
/**
* Link a new node to the end of the linked for a hash index.
*
* @param index an index into hashTable
* @param lastLookup either -1 or the node to which the new node will be linked
* @return the new node
*/
int linkNode(int index, int lastLookup) {
// get the first reclaimed slot
int lookup = reclaimedNodePointer;
if (lookup == -1) {
lookup = newNodePointer++;
} else {
// reset the first reclaimed slot
reclaimedNodePointer = linkTable[lookup];
}
// link the node
if (lastLookup == -1) {
hashTable[index] = lookup;
} else {
linkTable[lastLookup] = lookup;
}
linkTable[lookup] = -1;
elementCount++;
modified = true;
return lookup;
}
/**
* Unlink a node from a linked list and link into the reclaimed list.
*
* @param index an index into hashTable
* @param lastLookup either -1 or the node to which the target node is linked
* @param lookup the node to remove
*/
void unlinkNode(int index, int lastLookup, int lookup) {
// unlink the node
if (lastLookup == -1) {
hashTable[index] = linkTable[lookup];
} else {
linkTable[lastLookup] = linkTable[lookup];
}
// add to reclaimed list
linkTable[lookup] = reclaimedNodePointer;
reclaimedNodePointer = lookup;
elementCount--;
}
/**
* Remove a node that has already been unlinked. This is not required
* for index operations. It is used only when the row needs to be removed
* from the data structures that store the actual indexed data and the
* nodes need to be contiguous.
*
* @param lookup the node to remove
* @return true if node found in unlinked state
*/
boolean removeEmptyNode(int lookup) {
boolean found = false;
int lastLookup = -1;
for (int i = reclaimedNodePointer; i >= 0;
lastLookup = i, i = linkTable[i]) {
if (i == lookup) {
if (lastLookup == -1) {
reclaimedNodePointer = linkTable[lookup];
} else {
linkTable[lastLookup] = linkTable[lookup];
}
found = true;
break;
}
}
if (!found) {
return false;
}
for (int i = 0; i < newNodePointer; i++) {
if (linkTable[i] > lookup) {
linkTable[i]--;
}
}
System.arraycopy(linkTable, lookup + 1, linkTable, lookup,
newNodePointer - lookup - 1);
linkTable[newNodePointer - 1] = 0;
newNodePointer--;
for (int i = 0; i < hashTable.length; i++) {
if (hashTable[i] > lookup) {
hashTable[i]--;
}
}
return true;
}
}