📄 dxdiskhashmap.java
字号:
// You can redistribute this software and/or modify it under the terms of// the Ozone Library License version 1 published by ozone-db.org.//// The original code and portions created by SMB are// Copyright (C) 1997-2000 by SMB GmbH. All rights reserved.//// $Id: DxDiskHashMap.java,v 1.16 2000/11/10 17:03:17 daniela Exp $package org.ozoneDB.DxLib;import java.io.*;/** * @author <a href="http://www.softwarebuero.de/">SMB</a> * @version $Revision: 1.16 $Date: 2000/11/10 17:03:17 $ */public class DxDiskHashMap extends DxAbstractMap { final static long serialVersionUID = 2; public final static String ROOT_TABLE_NAME = ".rootTable"; private String baseFileName; private long subTableNameCount = System.currentTimeMillis(); private DxDiskSubTable rootTable; private int itemCount = 0; // cache related stuff private int cacheBits = 10; private int cacheMask; private DxKeyData[] cache; // buffer related stuff protected int maxBufferSize = 10; protected DxSet buffer = new DxHashSet(); public int bufferAccesses; public int bufferHits; public int cacheAccesses; public int cacheHits; public int tableBitSize = 8; public DxDiskHashMap( String _baseFileName, int _maxBufferSize, int _cacheBits, int _tableBitSize ) { baseFileName = _baseFileName; maxBufferSize = _maxBufferSize; tableBitSize = _tableBitSize; cacheBits = _cacheBits; cacheMask = ((int)Math.pow( 2, cacheBits ) - 1); cache = new DxKeyData[(int)Math.pow( 2, cacheBits )]; rootTable = new DxDiskSubTable( this, 0, tableBitSize ); buffer.add( rootTable ); } public DxDiskHashNodeLeaf newNodeLeaf() { return new DxDiskHashNodeLeaf( this ); } public DxDiskHashNodeBranch newNodeBranch() { return new DxDiskHashNodeBranch(); } public DxKeyData newKeyData() { return new DxKeyData(); } public boolean isDirtyTable( DxDiskSubTable table ) { // in general we don't know if and when the data objects stored in // this table has been changed since last write, so we have to assume // it is always dirty return true; } /** * Reuse an existing table from disk. To do so a previously created table * has to be correctly closed. Once a hash map has been re-used it has to * closed before opening again. */ public synchronized void re_use() throws Exception { File f = new File( baseFileName + ROOT_TABLE_NAME ); ObjectInputStream in = new ObjectInputStream( new BufferedInputStream( new FileInputStream( f ) ) ); try { itemCount = in.readInt(); rootTable.readExternal( in ); rootTable.grandParent = this; } finally { in.close(); } } /** * Close this hash map. Write all changed tables to the disk. Store also * all information that are needed to re-initialize this object from the * disk data. */ public synchronized void close() throws Exception { writeAllTables(); setReusable( true ); } public void setReusable( boolean flag ) throws Exception { File f = new File( baseFileName + ROOT_TABLE_NAME ); if (flag) { ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( f ) ) ); try { out.writeInt( itemCount ); rootTable.writeExternal( out ); } finally { out.close(); } } else { if (f.exists() && !f.delete()) { throw new IOException( "Unable to delete file." ); } } } public Object clone() { throw new RuntimeException( getClass().getName() + ".clone() is not implemented yet." ); } private final Object cachedElementForKey( Object key, int hashCode ) { cacheAccesses++; if (cacheMask == 0) { return null; } int cacheIndex = hashCode & cacheMask; DxKeyData entry = cache[cacheIndex]; if (entry != null && (entry.key == key || entry.key.equals( key ))) { // System.out.print ("."); cacheHits ++; return entry.data; } else { return null; } } private final void addElementToCache( Object obj, Object key, int hashCode ) { if (cacheMask == 0) { return; } synchronized (cache) { int cacheIndex = hashCode & cacheMask; DxKeyData entry = cache[cacheIndex]; if (entry != null) { entry.set( key, obj ); } else { entry = newKeyData(); entry.set( key, obj ); cache[cacheIndex] = entry; } } } private final void removeElementFromCache( Object key ) { if (cacheMask == 0) { return; } synchronized (cache) { int cacheIndex = key.hashCode() & cacheMask; cache[cacheIndex] = null; } } public void printStatistics() { System.out.println( "DxDiskHastable statistics:" ); System.out.println( " sub-table accesses: " + bufferAccesses + " hits: " + bufferHits + " loads: " + (bufferAccesses - bufferHits) ); System.out.println( " cache accesses: " + cacheAccesses + " hits: " + cacheHits ); } /** * Eine sub-tabelle will nachladen. Wenn der buffer voll ist, * muss eine andere verworfen werden. Die "aelteste" table ist * immer ein blatt, da die zeiten mmer beim rekursiven aufstieg * gesetzt werden. */ protected synchronized void readRequest( DxDiskSubTable subTable ) throws Exception { if (buffer.count() > maxBufferSize) { //die blatt-sub-tabelle mit der aeltesten zugriffszeit //suchen long time = Long.MAX_VALUE; DxIterator it = buffer.iterator(); DxDiskSubTable table; DxDiskSubTable bestMatch = null; while ((table = (DxDiskSubTable)it.next()) != null) { if (table.accessTime < time) { time = table.accessTime; bestMatch = table; } } // System.out.println (" - " + time); //test ob noch sub-tabels da sind // for (int i=0; i<DxDiskSubTable.SIZE; i++) { // DxDiskHashNode node = bestMatch.table[i]; // if (node != null) { // if (node.element == null && node.subTable.table == null) { // System.out.println ("Node is not a leaf!"); // break; // } // } // } //schreiben, leer-machen und aus buffer loeschen if (isDirtyTable( bestMatch )) { bestMatch.writeTable(); } deleteRequest( bestMatch ); } // subTable.touch(); buffer.add( subTable ); } /** * The specified sub-table was deleted from the tree. So we have * to delete it from the table buffer too. */ public synchronized void deleteRequest( DxDiskSubTable subTable ) { subTable.empty(); buffer.remove( subTable ); } public String newSubTableFileName() { return baseFileName + "." + String.valueOf( subTableNameCount++ ); } /** * Delete all the files used by this hashtable. */ public void cleanFiles() { String baseName = new File( baseFileName ).getName(); File path = new File( new File( baseFileName ).getParent() ); String[] fileList = path.list(); for (int i = 0; i < fileList.length; i++) { if (fileList[i].startsWith( baseName )) { new File( path, fileList[i] ).delete(); } } } public synchronized void writeAllTables() throws Exception { DxIterator it = buffer.iterator(); DxDiskSubTable table = null; while ((table = (DxDiskSubTable)it.next()) != null) { table.writeTable(); } } public synchronized boolean addForKey( Object obj, Object key ) { try { if (rootTable.addForKey( obj, key )) { itemCount++; addElementToCache( obj, key, key.hashCode() ); return true; } else { return false; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException( e.toString() ); } } /** * Gives the element for the specified key.<p> * * * Note: This method is synchronized because the cache of subtables may * change. */ public synchronized Object elementForKey( Object key ) { try { int hashCode = key.hashCode(); Object cacheEntry = cachedElementForKey( key, hashCode ); if (cacheEntry != null) { return cacheEntry; } else { Object answer = rootTable.elementForKey( key, hashCode ); addElementToCache( answer, key, hashCode ); return answer; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException( e.toString() ); } } protected synchronized void elementDone( DxDiskHashCompatible obj ) { rootTable.elementDone( obj ); } public Object keyForElement( Object obj ) { throw new RuntimeException( "keyForElement() not implemented." ); } public synchronized boolean remove( Object obj ) { throw new RuntimeException( "remove() not implemented." ); } public synchronized Object removeForKey( Object key ) { try { Object obj = rootTable.removeForKey( key ); if (obj != null) { itemCount--; removeElementFromCache( key ); } return obj; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException( e.toString() ); } } public DxIterator iterator() { throw new RuntimeException( "iterator() not implemented." ); // return new DxDIterator (this); } public int count() { return itemCount; } public boolean isEmpty() { return itemCount == 0; } public boolean containsKey( Object key ) { return elementForKey( key ) != null; } public synchronized void clear() { throw new RuntimeException( getClass().getName() + ".clear() is not implemented yet." ); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -