diff --git a/source/de/anomic/kelondro/kelondroMHashMap.java b/source/de/anomic/kelondro/kelondroMHashMap.java new file mode 100644 index 000000000..9fa5421ba --- /dev/null +++ b/source/de/anomic/kelondro/kelondroMHashMap.java @@ -0,0 +1,340 @@ +// kelondroMHashMap.java +// ----------------------- +// part of YaCy +// (C) by Michael Peter Christen; mc@anomic.de +// first published on http://www.anomic.de +// Frankfurt, Germany, 2005 +// Created 08.12.2005 +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// Using this software in any meaning (reading, learning, copying, compiling, +// running) means that you agree that the Author(s) is (are) not responsible +// for cost, loss of data or any harm that may be caused directly or indirectly +// by usage of this softare or this documentation. The usage of this software +// is on your own risk. The installation and usage (starting/running) of this +// software may allow other people or application to access your computer and +// any attached devices and is highly dependent on the configuration of the +// software which must be done by the user of the software; the author(s) is +// (are) also not responsible for proper configuration and usage of the +// software, even if provoked by documentation provided together with +// the software. +// +// Any changes to this file according to the GPL as documented in the file +// gpl.txt aside this file in the shipment you received can be done to the +// lines that follows this copyright notice here, but changes must not be +// done inside the copyright notive above. A re-distribution must contain +// the intact and unchanged copyright notice. +// Contributions and changes to the program code must be marked as such. + +package de.anomic.kelondro; + +import java.util.Iterator; +import java.util.Random; + +public class kelondroMHashMap { + + private int keylen, valuelen, reclen, count; + private byte[] mem; + private byte[] emptykey; + + public kelondroMHashMap(int valuelen) { + // initializes a hash map with integer access key + this(4, valuelen); + } + + public kelondroMHashMap(int keylen, int valuelen) { + this.keylen = keylen; + this.valuelen = valuelen; + this.reclen = keylen + valuelen; + this.mem = new byte[1 * reclen]; + this.count = 0; + this.emptykey = new byte[keylen]; + for (int i = 0; i < keylen; i++) emptykey[i] = 0; + for (int i = 0; i < (mem.length / reclen); i++) System.arraycopy(emptykey, 0, mem, i * reclen, keylen); + } + + private boolean equals(int posKeyInMem, byte[] otherkey) { + assert (otherkey.length == keylen); + int pos = posKeyInMem * reclen; + int i = 0; + while (i < keylen) if (mem[pos++] != otherkey[i++]) return false; + return true; + } + + private int rehashtry() { + return 1 + mem.length / 2; + } + + private int capacity() { + return mem.length / reclen; + } + + private static int hashkey(byte[] key, int capacity) { + int h = 0; + for (int i = 0; i < key.length; i++) h = h * 15 + (0xff & key[i]); + //System.out.println("hash code of key " + new String(key) + " is " + h); + return h % capacity; + } + + private static int rehash(int previousKey, int capacity) { + if (previousKey == 0) previousKey = capacity; + return previousKey - 1; + } + + public int size() { + return count; + } + + private int findExisting(byte[] key) { + // returns an index position if found; -1 otherwise + int hash = hashkey(key, capacity()); + //System.out.println("first guess for key " + new String(key) + ": " + hash + "( capacity is " + capacity() + " )"); + int testcount = 0; + while (testcount++ < rehashtry()) { + if (mem[hash * reclen] == 0) return -1; + if (equals(hash, key)) return hash; + hash = rehash(hash, capacity()); + } + return -1; + } + + private int findSpace(byte[] key) { + // returns an new index position which is empty + // if there is no space left -1 is returned + int hash = hashkey(key, capacity()); + int testcount = 0; + while (testcount++ < rehashtry()) { + if (mem[hash * reclen] == 0) return hash; + hash = rehash(hash, capacity()); + } + return -1; + } + + private static int findSpace(byte[] m, byte[] key, int rl, int trycount, int capacity) { + // returns an new index position which is empty + // if there is no space left -1 is returned + int hash = hashkey(key, capacity); + int testcount = 0; + while (testcount++ < trycount) { + if (m[hash * rl] == 0) return hash; + hash = rehash(hash, capacity); + } + return -1; + } + + private static byte[] toByteKey(int v) { + assert (v >= 0); + v = v | 0x80000000; // set bit in first byte + return new byte[]{(byte) ((v >>> 24) & 0xFF), (byte) ((v >>> 16) & 0xFF), + (byte) ((v >>> 8) & 0xFF), (byte) ((v >>> 0) & 0xFF)}; + } + + public void put(int key, byte[] value) { + put(toByteKey(key), value); + } + + public void put(byte[] key, byte[] value) { + // inserts a new value or overwrites existing + // if the hash is full, a RuntimeException is thrown + // this method does not return the old value to avoid generation of objects + assert (key.length == keylen); + assert (value.length == valuelen); + + int hash = findExisting(key); + if (hash < 0) { + // insert new entry + hash = findSpace(key); + if (hash < 0) { + // increase space of hashtable + // create temporary bigger hashtable and insert all + synchronized (mem) { + System.out.println("increasing space to " + mem.length * 2); + int newspace = mem.length * 2; + int newcapacity = capacity() * 2; + byte[] newmem = new byte[newspace]; + Iterator i = entries(); + kelondroMHashMap.entry e; + int mempos; + while (i.hasNext()) { + e = (kelondroMHashMap.entry) i.next(); + hash = findSpace(newmem, e.key, reclen, newspace, newcapacity); + mempos = hash * reclen; + System.arraycopy(e.key, 0, newmem, mempos, keylen); + System.arraycopy(e.value, 0, newmem, mempos + keylen, valuelen); + } + // finally insert new value + hash = findSpace(newmem, key, reclen, newspace, newcapacity); + mempos = hash * reclen; + System.arraycopy(key, 0, newmem, mempos, keylen); + System.arraycopy(value, 0, newmem, mempos + keylen, valuelen); + // move newmem to mem + mem = newmem; + newmem = null; + } + } else { + // there is enough space + //System.out.println("put " + new String(key) + " into cell " + hash); + int mempos = hash * reclen; + System.arraycopy(key, 0, mem, mempos, keylen); + System.arraycopy(value, 0, mem, mempos + keylen, valuelen); + } + count++; + } else { + // overwrite old entry + int mempos = hash * reclen; + System.arraycopy(key, 0, mem, mempos, keylen); + System.arraycopy(value, 0, mem, mempos + keylen, valuelen); + } + } + + public byte[] get(int key) { + return get(toByteKey(key)); + } + + public byte[] get(byte[] key) { + assert (key.length == keylen); + + int hash = findExisting(key); + //System.out.println("get " + new String(key) + " from cell " + hash); + if (hash < 0) { + return null; + } else { + // read old entry + byte[] value = new byte[valuelen]; + System.arraycopy(mem, hash * reclen + keylen, value, 0, valuelen); + return value; + } + } + + public void remove(int key) { + remove(toByteKey(key)); + } + + public void remove(byte[] key) { + assert (key.length == keylen); + + System.out.println("REMOVE!"); + int hash = findExisting(key); + if (hash >= 0) { + // overwrite old key + System.arraycopy(emptykey, 0, mem, hash * reclen, keylen); + count--; + } + } + + Iterator entries() { + return new entryIterator(); + } + + public class entryIterator implements Iterator { + + int hashkey; + + public entryIterator() { + hashkey = anyhashpos(0); + } + + public boolean hasNext() { + return hashkey >= 0; + } + + public Object next() { + int i = hashkey; + hashkey = anyhashpos(hashkey + 1); + return new entry(i); + } + + public void remove() { + mem[hashkey * reclen] = 0; + } + + } + + public void removeany() { + //System.out.println("CALLED REMOVEANY"); + int start = 0; + while (start < capacity()) { + if (mem[start * reclen] != 0) { + System.arraycopy(emptykey,0, mem, start * reclen, keylen); + count--; + return; + } + start++; + } + return; + } + + private int anyhashpos(int start) { + while (start < capacity()) { + if (mem[start * reclen] != 0) return start; + start++; + } + return -1; + } + + public byte[] anykey() { + int hash = 0; + int mempos; + while (hash < capacity()) { + mempos = hash * reclen; + if (mem[mempos] != 0) { + byte[] key = new byte[keylen]; + System.arraycopy(mem, mempos, key, 0, keylen); + return key; + } + hash++; + } + return null; + } + + public class entry { + public byte[] key, value; + + public entry(int index) { + this.key = new byte[keylen]; + this.value = new byte[valuelen]; + int mempos = index * (reclen); + System.arraycopy(mem, mempos, key, 0, keylen); + System.arraycopy(mem, mempos + keylen, value, 0, valuelen); + } + + public entry(byte[] key, byte[] value) { + this.key = key; + this.value = value; + } + } + + + public static void main(String[] args) { + long start = System.currentTimeMillis(); + kelondroMHashMap map = new kelondroMHashMap(4); + for (int i = 0; i < 100; i++) map.put(3333 + i, ("" + (1000 + i)).getBytes()); + Iterator i = map.entries(); + kelondroMHashMap.entry e; + System.out.println("AufzŠhlung der Elemente: count=" + map.size()); + int c = 0; + while (i.hasNext()) { + e = (kelondroMHashMap.entry) i.next(); + System.out.println("key=" + new String(e.key) + ", value=" + new String(e.value) + ", retrieved=" + new String(map.get(e.key))); + c++; + } + System.out.println("c = " + c + "; re-catch:"); + for (int j = 0; j < 100; j++) { + System.out.println("key=" + j + ", retrieved=" + new String(map.get(3333 + j))); + } + System.out.println("runtime = " + (System.currentTimeMillis() - start)); + } +} diff --git a/source/de/anomic/kelondro/kelondroNIOFileRA.java b/source/de/anomic/kelondro/kelondroNIOFileRA.java index 91aa02d0c..c270557a0 100644 --- a/source/de/anomic/kelondro/kelondroNIOFileRA.java +++ b/source/de/anomic/kelondro/kelondroNIOFileRA.java @@ -76,8 +76,8 @@ public class kelondroNIOFileRA extends kelondroAbstractRA implements kelondroRA this.tailCurrSize = 0; this.mapBody = mapBody; this.RAFile = new RandomAccessFile(file, "rw"); - this.RAChannel = RAFile.getChannel(); - this.bufferHead = RAChannel.map(FileChannel.MapMode.READ_WRITE, 0, (int) bodyOffset); + this.RAChannel = RAFile.getChannel(); + this.bufferHead = RAChannel.map(FileChannel.MapMode.READ_WRITE, 0, (int) bodyOffset); if (mapBody) this.bufferBody = RAChannel.map(FileChannel.MapMode.READ_WRITE, bodyOffset, (int) (tailOffset - bodyOffset)); else diff --git a/source/de/anomic/kelondro/kelondroTree.java b/source/de/anomic/kelondro/kelondroTree.java index 91719be6b..9fe900190 100644 --- a/source/de/anomic/kelondro/kelondroTree.java +++ b/source/de/anomic/kelondro/kelondroTree.java @@ -76,7 +76,7 @@ public class kelondroTree extends kelondroRecords implements Comparator, kelondr private static int root = 0; // pointer for FHandles-array: pointer to root node private Search writeSearchObj = new Search(); - private kelondroLock writeLock = new kelondroLock(); + //private kelondroLock writeLock = new kelondroLock(); public kelondroTree(File file, long buffersize, int key, int value) throws IOException { this(file, buffersize, new int[] { key, value }, 1, 8);