package com.neocoretechs.bigsack.session; import java.io.IOException; import java.util.Iterator; import com.neocoretechs.bigsack.DBPhysicalConstants; import com.neocoretechs.bigsack.btree.BTreeMain; import com.neocoretechs.bigsack.btree.TreeSearchResult; import com.neocoretechs.bigsack.io.pooled.Datablock; import com.neocoretechs.bigsack.iterator.EntrySetIterator; import com.neocoretechs.bigsack.iterator.HeadSetIterator; import com.neocoretechs.bigsack.iterator.HeadSetKVIterator; import com.neocoretechs.bigsack.iterator.KeySetIterator; import com.neocoretechs.bigsack.iterator.SubSetIterator; import com.neocoretechs.bigsack.iterator.SubSetKVIterator; import com.neocoretechs.bigsack.iterator.TailSetIterator; import com.neocoretechs.bigsack.iterator.TailSetKVIterator; /* * Copyright (c) 2003, NeoCoreTechs * 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 NeoCoreTechs 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 THE COPYRIGHT OWNER 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. * */ /** * Session object. Returned by SessionManager.Connect(). * Responsible for providing generic access to BTreeMain from which other * specific collection types can obtain their functionality. Operations include * handing out iterators, inserting and deleting objects, size, navigation, clearing, * and handling commit and rollback. * @author Groff */ public final class BigSackSession { private boolean DEBUG = false; public static final boolean COMMIT = false; public static final boolean ROLLBACK = true; private int uid; private int gid; private BTreeMain bTree; /** * Create new session * @param tuid The user * @param tgis The group * @exception IOException If global IO problem */ protected BigSackSession(BTreeMain bTree, int uid, int gid) { this.bTree = bTree; this.uid = uid; this.gid = gid; if( DEBUG ) System.out.println("BigSackSession constructed with db:"+getDBPath()+" using remote DB:"+getRemoteDBName()); } public long getTransactionId() { return bTree.getIO().getTransId(); } public String getDBname() { return bTree.getIO().getDBName(); } public String getDBPath() { return bTree.getIO().getDBPath(); } public String getRemoteDBName() { return bTree.getIO().getRemoteDBName(); } @Override public String toString() { return "BigSackSession using DB:"+getDBname()+" path:"+getDBPath()+" remote:"+getRemoteDBName(); } protected int getUid() { return uid; } protected int getGid() { return gid; } public Object getMutexObject() { return bTree; } @SuppressWarnings("rawtypes") public boolean put(Comparable o) throws IOException { return (bTree.add(o) == 0 ? false : true); } @SuppressWarnings("rawtypes") public boolean put(Comparable key, Object o) throws IOException { return (bTree.add(key, o) == 0 ? false : true); } @SuppressWarnings("rawtypes") public Object get(Comparable o) throws IOException { return bTree.seekObject(o); } @SuppressWarnings("rawtypes") public TreeSearchResult locate(Comparable key) throws IOException { TreeSearchResult tsr = bTree.locate(key); return tsr; } /** * Not a real subset, returns iterator vs set. * 'from' element inclusive, 'to' element exclusive * @param fkey Return from fkey * @param tkey Return from fkey to strictly less than tkey * @return The Iterator over the subSet * @exception IOException If we cannot obtain the iterator */ @SuppressWarnings("rawtypes") public Iterator<?> subSet(Comparable fkey, Comparable tkey) throws IOException { return new SubSetIterator(fkey, tkey, bTree); } /** * Not a real subset, returns iterator vs set. * 'from' element inclusive, 'to' element exclusive * @param fkey Return from fkey * @param tkey Return from fkey to strictly less than tkey * @return The KeyValuePair Iterator over the subSet * @exception IOException If we cannot obtain the iterator */ @SuppressWarnings("rawtypes") public Iterator<?> subSetKV(Comparable fkey, Comparable tkey) throws IOException { return new SubSetKVIterator(fkey, tkey, bTree); } /** * Not a real subset, returns iterator * @return The Iterator over the entrySet * @exception IOException If we cannot obtain the iterator */ public Iterator<?> entrySet() throws IOException { return new EntrySetIterator(bTree); } /** * Not a real subset, returns Iterator * @param tkey return from head to strictly less than tkey * @return The Iterator over the headSet * @exception IOException If we cannot obtain the iterator */ @SuppressWarnings("rawtypes") public Iterator<?> headSet(Comparable tkey) throws IOException { return new HeadSetIterator(tkey, bTree); } /** * Not a real subset, returns Iterator * @param tkey return from head to strictly less than tkey * @return The KeyValuePair Iterator over the headSet * @exception IOException If we cannot obtain the iterator */ @SuppressWarnings("rawtypes") public Iterator<?> headSetKV(Comparable tkey) throws IOException { return new HeadSetKVIterator(tkey, bTree); } /** * Return the keyset Iterator over all elements * @return The Iterator over the keySet * @exception IOException If we cannot obtain the iterator */ public Iterator<?> keySet() throws IOException { return new KeySetIterator(bTree); } /** * Not a real subset, returns Iterator * @param fkey return from value to end * @return The Iterator over the tailSet * @exception IOException If we cannot obtain the iterator */ @SuppressWarnings("rawtypes") public Iterator<?> tailSet(Comparable fkey) throws IOException { return new TailSetIterator(fkey, bTree); } /** * Not a real subset, returns Iterator * @param fkey return from value to end * @return The KeyValuePair Iterator over the tailSet * @exception IOException If we cannot obtain the iterator */ @SuppressWarnings("rawtypes") public Iterator<?> tailSetKV(Comparable fkey) throws IOException { return new TailSetKVIterator(fkey, bTree); } /** * Contains * @param o * @return * @throws IOException */ @SuppressWarnings("rawtypes") public boolean contains(Comparable o) throws IOException { Object obj = bTree.seekObject(o); if( obj != null ) { bTree.getIO().deallocOutstanding(); return obj.equals(o); } bTree.getIO().deallocOutstanding(); return false; } /** * @return null or previous object */ @SuppressWarnings("rawtypes") public Object remove(Comparable o) throws IOException { bTree.delete(o); return o; //fluent interface style } public Object first() throws IOException { bTree.rewind(); //if (bTree.gotoNextKey() > 0) // throw new IOException("BigSackSession.first: next key fault"); Object retVal = bTree.getCurrentObject(); bTree.getIO().deallocOutstanding(); return retVal; } @SuppressWarnings("rawtypes") public Comparable firstKey() throws IOException { bTree.rewind(); //if (bTree.gotoNextKey() > 0) // throw new IOException("BigSackSession.firstKey: next key fault"); Comparable retVal = bTree.getCurrentKey(); bTree.getIO().deallocOutstanding(); return retVal; } public Object last() throws IOException { bTree.toEnd(); //if (bTree.gotoPrevKey() > 0) // throw new IOException("BigSackSession.last: prev key fault"); Object retVal = bTree.getCurrentObject(); bTree.getIO().deallocOutstanding(); return retVal; } @SuppressWarnings("rawtypes") public Comparable lastKey() throws IOException { bTree.toEnd(); //if (bTree.gotoPrevKey() > 0) // throw new IOException("BigSackSession.lastKey: prev key fault"); Comparable retVal = bTree.getCurrentKey(); bTree.getIO().deallocOutstanding(); return retVal; } public long size() throws IOException { return bTree.count(); } public boolean isEmpty() throws IOException { return bTree.isEmpty(); } /** * Close this session. * @param rollback true to roll back, false to commit * @exception IOException For low level failure */ public void Close(boolean rollback) throws IOException { rollupSession(rollback); } public void Open() throws IOException { bTree.getIO().getIOManager().Fopen(); } /** * @exception IOException for low level failure */ public void Rollback() throws IOException { Close(true); } /** * Commit the blocks. * @exception IOException For low level failure */ public void Commit() throws IOException { Close(false); } /** * Checkpoint the current transaction * @throws IOException * @throws IllegalAccessException */ public void Checkpoint() throws IllegalAccessException, IOException { for(int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) bTree.getIO().getIOManager().getUlog(i).checkpoint(); } /** * Generic session roll up. Data is committed based on rollback param. * We deallocate the outstanding block * We iterate the tablespaces for each db removing obsolete log files. * @param rollback true to roll back, false to commit * @exception IOException For low level failure */ private void rollupSession(boolean rollback) throws IOException { if (rollback) { bTree.getIO().deallocOutstandingRollback(); for(int i = 0; i < DBPhysicalConstants.DTABLESPACES; i++) bTree.getIO().getIOManager().getUlog(i).getLogToFile().deleteOnlineArchivedLogFiles(); } else { // calls commitbufferflush bTree.getIO().deallocOutstandingCommit(); } } /** * This forces a close with rollback. * for offlining of db's * @exception IOException if low level error occurs */ protected void forceClose() throws IOException { Close(true); } /** * hidden easter egg or dangerous secret, its up to you */ public BTreeMain getBTree() { return bTree; } /** * Scans through tablespaces and analyzes space utilization * BEWARE - doing this under multithreading, well, youre asking for it.. * @exception Exception */ public void analyze(boolean verbose) throws Exception { System.out.println("Begin BigSack analysis verbose:"+verbose); float totutil = 0; Datablock db = new Datablock(DBPhysicalConstants.DBLOCKSIZ); int numberBlks = 1; long minBlock = bTree.getIO().firstTableSpace(); int itab = 0; do { int tnumberBlks = 1; float ttotutil = 0; int zeroBlocks = 0; long fsiz = bTree.getIO().getIOManager().Fsize(itab); //long maxBlock = GlobalDBIO.makeVblock(itab, fsiz); System.out.println("BigSack Analysis|Tablespace number "+itab+" bytes: " + fsiz); while (minBlock < fsiz) { bTree.getIO().getIOManager().FseekAndReadFully(minBlock, db); if( db.getBytesused() == 0 || db.getBytesinuse() == 0 && (db.getData()[0] == 0xAC && db.getData()[1] == 0xED && db.getData()[2] == 0x00 && db.getData()[3] == 0x05) ) { //System.out.println("Block has zero in use values but object stream header for tablespace"+itab+" pos:"+xpos+" Data:"+db+","+db.blockdump()); ++zeroBlocks; } //if( Props.DEBUG ) //if( Props.DEBUG ) System.out.println("Block:" + xblk + ": " + db.toBriefString()); if( verbose ) { System.out.println("BigSack Block tablespace "+itab+" zero blocks:"+zeroBlocks+" pos:"+minBlock+" Data:"+db+","+db.blockdump()); } totutil += ((float) (db.getBytesinuse())); ttotutil += ((float) (db.getBytesinuse())); minBlock += DBPhysicalConstants.DBLOCKSIZ; ++numberBlks; ++tnumberBlks; if( ((float)(tnumberBlks))/1000.0f == (float)(tnumberBlks/1000) ) System.out.print(tnumberBlks+"\r"); } int ttTotal = DBPhysicalConstants.DBLOCKSIZ * tnumberBlks; // bytes total theoretical int taTotal = (int) ((ttotutil / (float)ttTotal) * 100.0); // ratio of total to used System.out.println("BigSack Tablespace "+itab+" utilization: " + (int)ttotutil + " bytes in "+tnumberBlks+" blocks"); System.out.println("Maximum possible utilization is "+ttTotal+" bytes, making data Utilization "+taTotal+"%"); ++itab; } while( (minBlock = bTree.getIO().nextTableSpace(itab)) != 0); System.out.println("Total BigSack utilization: " + (int)totutil + " bytes in "+numberBlks+" blocks"); int tTotal = DBPhysicalConstants.DBLOCKSIZ * numberBlks; // bytes total theoretical int aTotal = (int) ((totutil / (float)tTotal) * 100.0); // ratio of total to used System.out.println("Maximum possible utilization is "+tTotal+" bytes, making data Utilization "+aTotal+"%"); } public boolean equals(Object o) { return( getTransactionId() == ((Long)o).longValue()); } }