package com.neocoretechs.bigsack.session; import java.io.IOException; import java.util.Iterator; import java.util.TreeMap; import com.neocoretechs.bigsack.btree.TreeSearchResult; /* * 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. * */ /** * BufferedTreeMap. * Java TreeMap backed by pooled serialized objects. * UNLESS READ_ONLY Use these one-to-one with a database * DON'T use multiple instances for writing the same db - unpredictable results. * @author Groff (C) NeoCoreTechs 2003 */ public class BufferedTreeMap { @SuppressWarnings({ "unchecked", "rawtypes" }) protected TreeMap<Comparable<?>, Object> table = new TreeMap(); protected BigSackSession session; protected int objectCacheSize; /** * Get instance of BigSack session. * Each new instance of this will connect to the same backing store * with a different in-mem cache. * @param tdbname The database name * @param tobjectCacheSize The maximum size of in-mem cache , then backing store hits go up * @exception IOException if global IO problem * @exception IllegalAccessException if the database has been put offline */ public BufferedTreeMap(String tdbname, int tobjectCacheSize) throws IOException, IllegalAccessException { session = SessionManager.Connect(tdbname, null, true); objectCacheSize = tobjectCacheSize; } public BufferedTreeMap(String tdbname, String tremotename, int tobjectCacheSize) throws IOException, IllegalAccessException { session = SessionManager.Connect(tdbname, tremotename, true); objectCacheSize = tobjectCacheSize; } /** * Put a key/value pair to main cache and pool. We may * toss out an old one when cache size surpasses objectCacheSize * @param tkey The key for the pair * @param tvalue The value for the pair * @exception IOException if put to backing store fails */ @SuppressWarnings("rawtypes") public void put(Comparable tkey, Object tvalue) throws IOException { synchronized (session.getMutexObject()) { if (table.size() >= objectCacheSize) { // throw one out Iterator et = table.keySet().iterator(); //Object remo = et.next(); et.remove(); } // now put new session.put(tkey, tvalue); session.Commit(); table.put(tkey, tvalue); } } @SuppressWarnings("rawtypes") public synchronized TreeSearchResult locate(Comparable tvalue) throws IOException { return session.locate(tvalue); } /** * Get a value from backing store if not in cache. * We may toss out one to make room if size surpasses objectCacheSize * @param tkey The key for the value * @return The value for the key * @exception IOException if get from backing store fails */ @SuppressWarnings("rawtypes") public Object get(Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { Object kvp = session.get(tkey); session.Commit(); if (kvp == null) return null; return kvp; } } /** * Return the number of elements in the backing store * @return A long value of number of elements * @exception IOException If backing store retrieval failure */ public long size() throws IOException { synchronized (session.getMutexObject()) { long siz = session.size(); session.Commit(); return siz; } } /** * Obtain iterator over the entrySet. Retrieve from backing store if not in cache. * @return The Iterator for all elements * @exception IOException if get from backing store fails */ public Iterator<?> entrySet() throws IOException { synchronized (session.getMutexObject()) { return session.entrySet(); } } /** * Get a keySet iterator. Get from backing store if not in cache. * @return The iterator for the keys * @exception IOException if get from backing store fails */ public Iterator<?> keySet() throws IOException { synchronized (session.getMutexObject()) { return session.keySet(); } } /** * Returns true if the collection contains the given key * @param tkey The key to match * @return true or false if in * @exception IOException If backing store fails */ @SuppressWarnings("rawtypes") public boolean containsKey(Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { boolean ret = session.contains(tkey); session.Commit(); return ret; } } /** * Remove object from cache and backing store. * @param tkey The key to match * @return The removed object * @exception IOException If backing store fails */ @SuppressWarnings("rawtypes") public Object remove(Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { Object o = session.remove(tkey); session.Commit(); return o; } } /** * @return First key in set * @exception IOException If backing store retrieval failure */ public Object firstKey() throws IOException { synchronized (session.getMutexObject()) { Object ret = session.firstKey(); session.Commit(); return ret; } } /** * @return Last key in set * @exception IOException If backing store retrieval failure */ public Object lastKey() throws IOException { synchronized (session.getMutexObject()) { Object ret = session.lastKey(); session.Commit(); return ret; } } /** * Return the last element, we have to bypass cache for this because * of our random throwouts * @return A long value of number of elements * @exception IOException If backing store retrieval failure */ public Object last() throws IOException { synchronized (session.getMutexObject()) { Object ret = session.last(); session.Commit(); return ret; } } /** * Return the first element, we have to bypass cache for this because * of our random throwouts * @return A long value of number of elements * @exception IOException If backing store retrieval failure */ public Object first() throws IOException { synchronized (session.getMutexObject()) { Object ret = session.first(); session.Commit(); return ret; } } /** * @param tkey Strictly less than 'to' this element * @return Iterator of first to tkey * @exception IOException If backing store retrieval failure */ @SuppressWarnings("rawtypes") public Iterator<?> headMap(Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { return session.headSet(tkey); } } /** * @param tkey Strictly less than 'to' this element * @return Iterator of first to tkey returning KeyValuePairs * @exception IOException If backing store retrieval failure */ @SuppressWarnings("rawtypes") public Iterator<?> headMapKV(Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { return session.headSetKV(tkey); } } /** * @param fkey Greater or equal to 'from' element * @return Iterator of objects from fkey to end * @exception IOException If backing store retrieval failure */ @SuppressWarnings("rawtypes") public Iterator<?> tailMap(Comparable fkey) throws IOException { synchronized (session.getMutexObject()) { return session.tailSet(fkey); } } /** * @param fkey Greater or equal to 'from' element * @return Iterator of objects from fkey to end which are KeyValuePairs * @exception IOException If backing store retrieval failure */ @SuppressWarnings("rawtypes") public Iterator<?> tailMapKV(Comparable fkey) throws IOException { synchronized (session.getMutexObject()) { return session.tailSetKV(fkey); } } /** * @param fkey 'from' element inclusive * @param tkey 'to' element exclusive * @return Iterator of objects in subset from fkey to tkey * @exception IOException If backing store retrieval failure */ @SuppressWarnings("rawtypes") public Iterator<?> subMap(Comparable fkey, Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { return session.subSet(fkey, tkey); } } /** * @param fkey 'from' element inclusive * @param tkey 'to' element exclusive * @return Iterator of objects in subset from fkey to tkey composed of KeyValuePairs * @exception IOException If backing store retrieval failure */ @SuppressWarnings("rawtypes") public Iterator<?> subMapKV(Comparable fkey, Comparable tkey) throws IOException { synchronized (session.getMutexObject()) { return session.subSetKV(fkey, tkey); } } /** * Return boolean value indicating whether the map is empty * @return true if empty * @exception IOException If backing store retrieval failure */ public boolean isEmpty() throws IOException { synchronized (session.getMutexObject()) { boolean ret = session.isEmpty(); session.Commit(); return ret; } } public String getDBName() { return session.getDBname(); } }