tuning around kaha persistence

git-svn-id: https://svn.apache.org/repos/asf/incubator/activemq/trunk@395597 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Davies 2006-04-20 14:15:30 +00:00
parent 5574d2ad35
commit 6575f2d22d
48 changed files with 2955 additions and 1912 deletions

View File

@ -13,8 +13,8 @@
*/
package org.apache.activemq.kaha;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Implementation of a Marshaller for byte arrays
@ -29,7 +29,7 @@ public class BytesMarshaller implements Marshaller{
* @param dataOut
* @throws IOException
*/
public void writePayload(Object object,DataOutputStream dataOut) throws IOException{
public void writePayload(Object object,DataOutput dataOut) throws IOException{
byte[] data=(byte[]) object;
dataOut.writeInt(data.length);
dataOut.write(data);
@ -42,7 +42,7 @@ public class BytesMarshaller implements Marshaller{
* @return unmarshalled object
* @throws IOException
*/
public Object readPayload(DataInputStream dataIn) throws IOException{
public Object readPayload(DataInput dataIn) throws IOException{
int size=dataIn.readInt();
byte[] data=new byte[size];
dataIn.readFully(data);

View File

@ -99,6 +99,6 @@ public interface ListContainer extends List{
* @return true if successful
*/
public boolean doRemove(int position);
}

View File

@ -16,8 +16,8 @@
*/
package org.apache.activemq.kaha;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
@ -34,7 +34,7 @@ public interface Marshaller {
* @param dataOut
* @throws IOException
*/
public void writePayload(Object object, DataOutputStream dataOut) throws IOException;
public void writePayload(Object object, DataOutput dataOut) throws IOException;
/**
@ -43,7 +43,7 @@ public interface Marshaller {
* @return unmarshalled object
* @throws IOException
*/
public Object readPayload(DataInputStream dataIn) throws IOException;
public Object readPayload(DataInput dataIn) throws IOException;
}

View File

@ -15,8 +15,8 @@ package org.apache.activemq.kaha;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
@ -33,7 +33,7 @@ public class ObjectMarshaller implements Marshaller{
* @param dataOut
* @throws IOException
*/
public void writePayload(Object object,DataOutputStream dataOut) throws IOException{
public void writePayload(Object object,DataOutput dataOut) throws IOException{
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ObjectOutputStream objectOut=new ObjectOutputStream(bytesOut);
objectOut.writeObject(object);
@ -50,7 +50,7 @@ public class ObjectMarshaller implements Marshaller{
* @return unmarshalled object
* @throws IOException
*/
public Object readPayload(DataInputStream dataIn) throws IOException{
public Object readPayload(DataInput dataIn) throws IOException{
int size = dataIn.readInt();
byte[] data = new byte[size];
dataIn.readFully(data);

View File

@ -41,8 +41,9 @@ public interface Store{
* Checks if a MapContainer exists
* @param id
* @return new MapContainer
* @throws IOException
*/
public boolean doesMapContainerExist(Object id);
public boolean doesMapContainerExist(Object id) throws IOException;
/**
* Get a MapContainer with the given id - the MapContainer is created if needed
@ -62,15 +63,17 @@ public interface Store{
/**
* Get a Set of call MapContainer Ids
* @return the set of ids
* @throws IOException
*/
public Set getMapContainerIds();
public Set getMapContainerIds() throws IOException;
/**
* Checks if a ListContainer exists
* @param id
* @return new MapContainer
* @throws IOException
*/
public boolean doesListContainerExist(Object id);
public boolean doesListContainerExist(Object id) throws IOException;
/**
* Get a ListContainer with the given id and creates it if it doesn't exist
@ -90,8 +93,9 @@ public interface Store{
/**
* Get a Set of call ListContainer Ids
* @return the set of ids
* @throws IOException
*/
public Set getListContainerIds();
public Set getListContainerIds() throws IOException;
}

View File

@ -15,7 +15,8 @@ package org.apache.activemq.kaha;
import java.io.File;
import java.io.IOException;
import org.apache.activemq.kaha.impl.StoreImpl;
import org.apache.activemq.kaha.impl.KahaStore;
/**
* Factory for creating stores
*
@ -32,16 +33,17 @@ public class StoreFactory{
* @throws IOException
*/
public static Store open(String name,String mode) throws IOException{
return new StoreImpl(name,mode);
return new KahaStore(name,mode);
}
/**
* Delete a database
* @param name of the database
* @return true if successful
* @throws IOException
*/
public static boolean delete(String name){
File file = new File(name);
return file.delete();
public static boolean delete(String name) throws IOException{
KahaStore store = new KahaStore(name,"rw");
return store.delete();
}
}

View File

@ -13,8 +13,8 @@
*/
package org.apache.activemq.kaha;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* Implementation of a Marshaller for Strings
@ -29,7 +29,7 @@ public class StringMarshaller implements Marshaller{
* @param dataOut
* @throws IOException
*/
public void writePayload(Object object,DataOutputStream dataOut) throws IOException{
public void writePayload(Object object,DataOutput dataOut) throws IOException{
dataOut.writeUTF(object.toString());
}
@ -40,7 +40,7 @@ public class StringMarshaller implements Marshaller{
* @return unmarshalled object
* @throws IOException
*/
public Object readPayload(DataInputStream dataIn) throws IOException{
public Object readPayload(DataInput dataIn) throws IOException{
return dataIn.readUTF();
}
}

View File

@ -0,0 +1,155 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.activemq.kaha.RuntimeStoreException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Implementation of a ListContainer
*
* @version $Revision: 1.2 $
*/
public abstract class BaseContainerImpl{
private static final Log log=LogFactory.getLog(BaseContainerImpl.class);
protected IndexItem root;
protected IndexLinkedList list;
protected IndexManager indexManager;
protected DataManager dataManager;
protected Object id;
protected boolean loaded=false;
protected boolean closed=false;
protected final Object mutex=new Object();
protected BaseContainerImpl(Object id,IndexItem root,IndexManager indexManager,DataManager dataManager){
this.id=id;
this.root=root;
this.indexManager=indexManager;
this.dataManager=dataManager;
this.list=new IndexLinkedList(root);
}
public abstract void unload();
public abstract void load();
public abstract int size();
public abstract void clear();
protected abstract Object getValue(IndexItem currentItem);
protected abstract void remove(IndexItem currentItem);
protected final IndexLinkedList getInternalList(){
return list;
}
public final void close(){
unload();
closed=true;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.ListContainer#isLoaded()
*/
public final boolean isLoaded(){
checkClosed();
return loaded;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.ListContainer#getId()
*/
public final Object getId(){
checkClosed();
return id;
}
protected final void expressDataInterest() throws IOException{
long nextItem=root.getNextItem();
while(nextItem!=Item.POSITION_NOT_SET){
IndexItem item=indexManager.getIndex(nextItem);
item.setOffset(nextItem);
dataManager.addInterestInFile(item.getKeyFile());
dataManager.addInterestInFile(item.getValueFile());
nextItem=item.getNextItem();
}
}
protected final void doClear(){
checkClosed();
synchronized(mutex){
loaded=true;
synchronized(mutex){
List list=new ArrayList();
try{
long nextItem=root.getNextItem();
while(nextItem!=Item.POSITION_NOT_SET){
IndexItem item=new IndexItem();
item.setOffset(nextItem);
list.add(item);
nextItem=item.getNextItem();
}
root.setNextItem(Item.POSITION_NOT_SET);
indexManager.updateIndex(root);
for(int i=0;i<list.size();i++){
IndexItem item=(IndexItem) list.get(i);
dataManager.removeInterestInFile(item.getKeyFile());
dataManager.removeInterestInFile(item.getValueFile());
indexManager.freeIndex(item);
}
list.clear();
}catch(IOException e){
log.error("Failed to clear Container "+getId(),e);
throw new RuntimeStoreException(e);
}
}
}
}
protected final void delete(IndexItem key,IndexItem prev,IndexItem next){
try{
dataManager.removeInterestInFile(key.getKeyFile());
dataManager.removeInterestInFile(key.getValueFile());
prev=prev==null?root:prev;
next=next!=root?next:null;
if(next!=null){
prev.setNextItem(next.getOffset());
next.setPreviousItem(prev.getOffset());
indexManager.updateIndex(next);
}else{
prev.setNextItem(Item.POSITION_NOT_SET);
}
indexManager.updateIndex(prev);
indexManager.freeIndex(key);
}catch(IOException e){
log.error("Failed to delete "+key,e);
throw new RuntimeStoreException(e);
}
}
protected final void checkClosed(){
if(closed){
throw new RuntimeStoreException("The store is closed");
}
}
}

View File

@ -1,54 +1,42 @@
/**
*
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.util.ListIterator;
/**
* @author rajdavies
*
*/
public class ContainerListIterator implements ListIterator{
private ListContainerImpl container;
private ListIterator iterator;
private LocatableItem current;
protected ContainerListIterator(ListContainerImpl container,ListIterator iterator){
this.container=container;
this.iterator=iterator;
this.current = container.internalGet(0);
}
/*
* (non-Javadoc)
*
* @see java.util.ListIterator#hasNext()
*/
public boolean hasNext(){
return iterator.hasNext();
}
/*
* (non-Javadoc)
*
* @see java.util.ListIterator#next()
*/
public Object next(){
Object result=null;
current=(LocatableItem) iterator.next();
if(current!=null){
result=container.getValue(current);
}
return result;
/**
* @version $Revision: 1.2 $
*/
public class ContainerListIterator extends ContainerValueCollectionIterator implements ListIterator{
protected ContainerListIterator(ListContainerImpl container,IndexLinkedList list,IndexItem start){
super(container,list,start);
}
/*
* (non-Javadoc)
*
* @see java.util.ListIterator#hasPrevious()
*/
public boolean hasPrevious(){
return iterator.hasPrevious();
return list.getPrevEntry(currentItem) != null;
}
/*
@ -57,12 +45,8 @@ public class ContainerListIterator implements ListIterator{
* @see java.util.ListIterator#previous()
*/
public Object previous(){
Object result=null;
current=(LocatableItem) iterator.previous();
if(current!=null){
result=container.getValue(current);
}
return result;
currentItem = list.getPrevEntry(currentItem);
return currentItem != null ? container.getValue(currentItem) : null;
}
/*
@ -71,7 +55,16 @@ public class ContainerListIterator implements ListIterator{
* @see java.util.ListIterator#nextIndex()
*/
public int nextIndex(){
return iterator.nextIndex();
int result = -1;
if (currentItem != null){
IndexItem next = list.getNextEntry(currentItem);
if (next != null){
result = container.getInternalList().indexOf(next);
}
}
return result;
}
/*
@ -80,29 +73,27 @@ public class ContainerListIterator implements ListIterator{
* @see java.util.ListIterator#previousIndex()
*/
public int previousIndex(){
return iterator.previousIndex();
}
/*
* (non-Javadoc)
*
* @see java.util.ListIterator#remove()
*/
public void remove(){
iterator.remove();
if(current!=null){
container.remove(current);
int result = -1;
if (currentItem != null){
IndexItem prev = list.getPrevEntry(currentItem);
if (prev != null){
result = container.getInternalList().indexOf(prev);
}
}
return result;
}
/*
* (non-Javadoc)
*
* @see java.util.ListIterator#set(E)
*/
public void set(Object o){
LocatableItem item=container.internalSet(previousIndex()+1,o);
iterator.set(item);
IndexItem item=((ListContainerImpl) container).internalSet(previousIndex()+1,o);
currentItem=item;
}
/*
@ -111,7 +102,7 @@ public class ContainerListIterator implements ListIterator{
* @see java.util.ListIterator#add(E)
*/
public void add(Object o){
LocatableItem item=container.internalAdd(previousIndex()+1,o);
iterator.set(item);
IndexItem item=((ListContainerImpl) container).internalSet(previousIndex()+1,o);
currentItem=item;
}
}

View File

@ -42,37 +42,41 @@ class ContainerValueCollection extends ContainerCollectionSupport implements Col
public Iterator iterator(){
LinkedList list=container.getItemList();
list = (LinkedList) list.clone();
return new ContainerValueCollectionIterator(container,list.iterator());
IndexLinkedList list=container.getItemList();
return new ContainerValueCollectionIterator(container,list,list.getRoot());
}
public Object[] toArray(){
Object[] result = null;
List list = container.getItemList();
IndexLinkedList list = container.getItemList();
synchronized(list){
result = new Object[list.size()];
IndexItem item = list.getFirst();
int count = 0;
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
Object value=container.getValue(item);
while (item != null){
Object value=container.getValue(item);
result[count++] = value;
item = list.getNextEntry(item);
}
}
return result;
}
public Object[] toArray(Object[] result){
List list=container.getItemList();
IndexLinkedList list=container.getItemList();
synchronized(list){
if(result.length<=list.size()){
int count=0;
result=(Object[]) java.lang.reflect.Array.newInstance(result.getClass().getComponentType(),list.size());
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
Object value=container.getValue(item);
result[count++]=value;
IndexItem item = list.getFirst();
int count = 0;
while (item != null){
Object value=container.getValue(item);
result[count++] = value;
item = list.getNextEntry(item);
}
}
}

View File

@ -25,20 +25,21 @@ import java.util.Iterator;
* @version $Revision: 1.2 $
*/
public class ContainerValueCollectionIterator implements Iterator{
private MapContainerImpl container;
private Iterator iter;
private LocatableItem currentItem;
ContainerValueCollectionIterator(MapContainerImpl container,Iterator iter){
protected BaseContainerImpl container;
protected IndexLinkedList list;
protected IndexItem currentItem;
ContainerValueCollectionIterator(BaseContainerImpl container,IndexLinkedList list,IndexItem start){
this.container = container;
this.iter = iter;
this.list = list;
this.currentItem = start;
}
public boolean hasNext(){
return iter.hasNext();
return currentItem != null && list.getNextEntry(currentItem) != null;
}
public Object next(){
currentItem = (LocatableItem) iter.next();
currentItem = list.getNextEntry(currentItem);
return container.getValue(currentItem);
}

View File

@ -0,0 +1,97 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* DataFile
*
* @version $Revision: 1.1.1.1 $
*/
class DataFile{
private File file;
private Integer number;
private int referenceCount;
private RandomAccessFile randomAcessFile;
long length=0;
DataFile(File file,int number){
this.file=file;
this.number=new Integer(number);
length=file.exists()?file.length():0;
}
Integer getNumber(){
return number;
}
synchronized RandomAccessFile getRandomAccessFile() throws FileNotFoundException{
if(randomAcessFile==null){
randomAcessFile=new RandomAccessFile(file,"rw");
}
return randomAcessFile;
}
synchronized long getLength(){
return length;
}
synchronized void incrementLength(int size){
length+=size;
}
synchronized void purge() throws IOException{
if(randomAcessFile!=null){
randomAcessFile.close();
randomAcessFile=null;
}
}
synchronized boolean delete() throws IOException{
purge();
return file.delete();
}
synchronized void force() throws IOException{
if(randomAcessFile!=null){
randomAcessFile.getFD().sync();
}
}
synchronized void close() throws IOException{
if(randomAcessFile!=null){
randomAcessFile.close();
}
}
synchronized int increment(){
return ++referenceCount;
}
synchronized int decrement(){
return --referenceCount;
}
synchronized boolean isUnused(){
return referenceCount<=0;
}
public String toString(){
String result = file.getName() + " number = " + number + " , length = " + length + " refCount = " + referenceCount;
return result;
}
}

View File

@ -0,0 +1,110 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import org.apache.activemq.kaha.Marshaller;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
/**
* A a wrapper for a data in the store
*
* @version $Revision: 1.2 $
*/
final class DataItem implements Item{
static final int HEAD_SIZE=6; // magic + len
private int size;
private long offset=POSITION_NOT_SET;
private int file=(int) POSITION_NOT_SET;
DataItem(){}
boolean isValid(){
return file != POSITION_NOT_SET;
}
void writeHeader(DataOutput dataOut) throws IOException{
dataOut.writeShort(MAGIC);
dataOut.writeInt(size);
}
void readHeader(DataInput dataIn) throws IOException{
int magic=dataIn.readShort();
if(magic==MAGIC){
size=dataIn.readInt();
}else{
throw new BadMagicException("Unexpected Magic value: "+magic);
}
}
void writePayload(Marshaller marshaller,Object object,DataOutputStream dataOut) throws IOException{
marshaller.writePayload(object,dataOut);
}
Object readPayload(Marshaller marshaller,DataInputStream dataIn) throws IOException{
return marshaller.readPayload(dataIn);
}
/**
* @return Returns the size.
*/
int getSize(){
return size;
}
/**
* @param size The size to set.
*/
void setSize(int size){
this.size=size;
}
/**
* @return Returns the offset.
*/
long getOffset(){
return offset;
}
/**
* @param offset The offset to set.
*/
void setOffset(long offset){
this.offset=offset;
}
/**
* @return Returns the file.
*/
int getFile(){
return file;
}
/**
* @param file The file to set.
*/
void setFile(int file){
this.file=file;
}
/**
* @return a pretty print
*/
public String toString(){
String result="offset = "+offset+", file = " + file + ", size = "+size;
return result;
}
}

View File

@ -0,0 +1,188 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.activemq.kaha.Marshaller;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Manages DataFiles
*
* @version $Revision: 1.1.1.1 $
*/
final class DataManager{
private static final Log log=LogFactory.getLog(DataManager.class);
protected static long MAX_FILE_LENGTH=1024*1024*16;
private final File dir;
private final String prefix;
private StoreDataReader reader;
private StoreDataWriter writer;
private DataFile currentWriteFile;
Map fileMap=new HashMap();
DataManager(File dir,String pf){
this.dir=dir;
this.prefix=pf;
this.reader=new StoreDataReader(this);
this.writer=new StoreDataWriter(this);
// build up list of current dataFiles
File[] files=dir.listFiles(new FilenameFilter(){
public boolean accept(File dir,String name){
return dir.equals(dir)&&name.startsWith(prefix);
}
});
if(files!=null){
for(int i=0;i<files.length;i++){
File file=files[i];
String name=file.getName();
String numStr=name.substring(prefix.length(),name.length());
int num=Integer.parseInt(numStr);
DataFile dataFile=new DataFile(file,num);
fileMap.put(dataFile.getNumber(),dataFile);
if(currentWriteFile==null||currentWriteFile.getNumber().intValue()<num){
currentWriteFile=dataFile;
}
}
}
}
DataFile findSpaceForData(DataItem item) throws IOException{
if(currentWriteFile==null||((currentWriteFile.getLength()+item.getSize())>MAX_FILE_LENGTH)){
int nextNum=currentWriteFile!=null?currentWriteFile.getNumber().intValue()+1:1;
if(currentWriteFile!=null&&currentWriteFile.isUnused()){
removeDataFile(currentWriteFile);
}
currentWriteFile=createAndAddDataFile(nextNum);
}
item.setOffset(currentWriteFile.getLength());
item.setFile(currentWriteFile.getNumber().intValue());
return currentWriteFile;
}
RandomAccessFile getDataFile(DataItem item) throws IOException{
Integer key=new Integer(item.getFile());
DataFile dataFile=(DataFile) fileMap.get(key);
if(dataFile!=null){
return dataFile.getRandomAccessFile();
}
throw new IOException("Could not locate data file "+prefix+item.getFile());
}
synchronized Object readItem(Marshaller marshaller,DataItem item) throws IOException{
return reader.readItem(marshaller,item);
}
synchronized DataItem storeItem(Marshaller marshaller,Object payload) throws IOException{
return writer.storeItem(marshaller,payload);
}
synchronized void close() throws IOException{
for(Iterator i=fileMap.values().iterator();i.hasNext();){
DataFile dataFile=(DataFile) i.next();
dataFile.force();
}
fileMap.clear();
}
synchronized void force() throws IOException{
for(Iterator i=fileMap.values().iterator();i.hasNext();){
DataFile dataFile=(DataFile) i.next();
dataFile.force();
}
}
synchronized boolean delete() throws IOException{
boolean result=true;
for(Iterator i=fileMap.values().iterator();i.hasNext();){
DataFile dataFile=(DataFile) i.next();
result&=dataFile.delete();
}
fileMap.clear();
return result;
}
synchronized void addInterestInFile(int file) throws IOException{
if(file>=0){
Integer key=new Integer(file);
DataFile dataFile=(DataFile) fileMap.get(key);
if(dataFile==null){
dataFile=createAndAddDataFile(file);
}
addInterestInFile(dataFile);
}
}
void addInterestInFile(DataFile dataFile){
if(dataFile!=null){
dataFile.increment();
}
}
synchronized void removeInterestInFile(int file) throws IOException{
if(file>=0){
Integer key=new Integer(file);
DataFile dataFile=(DataFile) fileMap.get(key);
removeInterestInFile(dataFile);
}
}
synchronized void removeInterestInFile(DataFile dataFile) throws IOException{
if(dataFile!=null){
if(dataFile.decrement()<=0){
if(dataFile!=currentWriteFile){
removeDataFile(dataFile);
}
}
}
}
synchronized void consolidateDataFiles() throws IOException{
List purgeList=new ArrayList();
for(Iterator i=fileMap.values().iterator();i.hasNext();){
DataFile dataFile=(DataFile) i.next();
if(dataFile.isUnused() && dataFile != currentWriteFile){
purgeList.add(dataFile);
}
}
for(int i=0;i<purgeList.size();i++){
DataFile dataFile=(DataFile) purgeList.get(i);
fileMap.remove(dataFile.getNumber());
boolean result=dataFile.delete();
log.info("discarding data file "+dataFile+(result?"successful ":"failed"));
}
}
private DataFile createAndAddDataFile(int num){
String fileName=prefix+num;
File file=new File(dir,fileName);
DataFile result=new DataFile(file,num);
fileMap.put(result.getNumber(),result);
return result;
}
private void removeDataFile(DataFile dataFile) throws IOException{
fileMap.remove(dataFile.getNumber());
boolean result=dataFile.delete();
log.info("discarding data file "+dataFile+(result?"successful ":"failed"));
}
}

View File

@ -1,162 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Free space list in the Store
*
* @version $Revision: 1.2 $
*/
final class FreeSpaceManager{
private static final Log log = LogFactory.getLog(FreeSpaceManager.class);
static final int ROOT_SIZE=64;
static final int RESIZE_INCREMENT=20*1024*1024;
private Map map=new HashMap();
private Map prevMap=new HashMap();
private FreeSpaceTree tree=new FreeSpaceTree();
private StoreWriter writer;
private StoreReader reader;
private long dataEnd=ROOT_SIZE;
private long fileLength=-1;
FreeSpaceManager(StoreWriter writer,StoreReader reader) throws IOException{
this.writer=writer;
this.reader=reader;
this.fileLength=reader.length();
}
final Item getFreeSpace(Item item) throws IOException{
Item result=tree.getNextFreeSpace(item);
if(result==null){
while(dataEnd>=fileLength){
writer.allocateSpace(fileLength+RESIZE_INCREMENT);
fileLength=reader.length();
}
result=new Item();
result.setOffset(dataEnd);
int newSize = ((item.getSize()/8)+1)*8;
result.setSize(newSize);
dataEnd=dataEnd+result.getSize()+Item.HEAD_SIZE;
}else{
removeFreeSpace(result);
}
// reset the item
item.setActive(true);
item.setOffset(result.getOffset());
item.setSize(result.getSize());
return item;
}
final void addFreeSpace(Item item) throws IOException{
long currentOffset=reader.position();
reader.readHeader(item);
item.setActive(false);
// see if we can condense some space together
// first look for free space adjacent up the disk
Long nextKey=new Long(item.getOffset()+item.getSize()+Item.HEAD_SIZE);
Item next=(Item) map.remove(nextKey);
if(next!=null){
tree.removeItem(next);
Long prevKey=new Long(next.getOffset()+next.getSize()+Item.HEAD_SIZE);
prevMap.remove(prevKey);
int newSize=item.getSize()+next.getSize()+Item.HEAD_SIZE;
item.setSize(newSize);
}
// now see if there was a previous item
// in the next map
Long key=new Long(item.getOffset());
Item prev=(Item) prevMap.remove(key);
Long prevKey=prev!=null?new Long(prev.getOffset()):null;
if(prev!=null&&prevKey!=null){
// we can condense the free space
// first we are about to change the item so remove it from the tree
tree.removeItem(prev);
int newSize=prev.getSize()+item.getSize()+Item.HEAD_SIZE;
prev.setSize(newSize);
// update the header
writer.updateHeader(prev);
// put back in the tree
tree.addItem(prev);
}else{
// update the item header
writer.updateHeader(item);
tree.addItem(item);
map.put(key,item);
prevKey=new Long(item.getOffset()+item.getSize()+Item.HEAD_SIZE);
prevMap.put(prevKey,item);
}
reader.position(currentOffset);
}
/**
* validates and builds free list
*
* @throws IOException
*/
final void scanStoredItems() throws IOException{
if(reader.length()>ROOT_SIZE){
long offset=ROOT_SIZE;
while((offset+Item.HEAD_SIZE)<reader.length()){
Item item=new Item();
try{
reader.position(offset);
item.setOffset(offset);
reader.readHeader(item);
}catch(BadMagicException e){
log.error("Got bad magic reading stored items",e);
break;
}
if(item.getSize()>=0){
if(!item.isActive()){
addFreeSpace(item);
}
offset+=item.getSize()+Item.HEAD_SIZE;
}else{
// we've hit free space or end of file
break;
}
}
dataEnd=offset;
}else {
dataEnd = ROOT_SIZE;
}
}
private void removeFreeSpace(Item item){
if(item!=null){
long next=item.getOffset()+item.getSize()+Item.HEAD_SIZE;
Long nextKey=new Long(next);
prevMap.remove(nextKey);
Long key=new Long(item.getOffset());
map.remove(key);
}
}
void dump(PrintWriter printer){
printer.println("FreeSpace: map size = "+map.size()+", tree size = "+tree.size()+", prevMap size = "
+prevMap.size());
for(Iterator i=map.entrySet().iterator();i.hasNext();){
printer.println("map = "+i.next());
}
}
}

View File

@ -1,105 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
/**
* A a wrapper for a TreeMap of free Items - sorted by size This enables us to re-use free Items on disk
*
* @version $Revision: 1.2 $
*/
class FreeSpaceTree{
private Map sizeMap=new HashMap();
private TreeMap tree=new TreeMap();
void addItem(Item item){
Long sizeKey=new Long(item.getSize());
Item old=(Item) tree.put(sizeKey,item);
if(old!=null){
// We'll preserve old items to reuse
List list=(List) sizeMap.get(sizeKey);
if(list==null){
list=new ArrayList();
sizeMap.put(sizeKey,list);
}
list.add(old);
}
}
boolean removeItem(Item item){
boolean result=false;
Long sizeKey=new Long(item.getSize());
Item retrieved=(Item) tree.get(sizeKey);
if(retrieved==item){
Object foo=tree.remove(sizeKey);
result=true;
reconfigureTree(sizeKey);
}else{
List list=(List) sizeMap.get(sizeKey);
if(list!=null){
boolean foo=list.remove(item);
if(list.isEmpty()){
sizeMap.remove(sizeKey);
}
}
}
return result;
}
Item getNextFreeSpace(Item item){
Item result=null;
if(!tree.isEmpty()){
Long sizeKey=new Long(item.getSize());
SortedMap map=tree.tailMap(sizeKey);
if(map!=null&&!map.isEmpty()){
Long resultKey=(Long) map.firstKey();
result=(Item) map.get(resultKey);
if(result!=null){
// remove from the tree
tree.remove(resultKey);
reconfigureTree(resultKey);
}
}
}
return result;
}
void reconfigureTree(Long sizeKey){
List list=(List) sizeMap.get(sizeKey);
if(list!=null){
if(!list.isEmpty()){
Object newItem=list.remove(list.size()-1);
tree.put(sizeKey,newItem);
}
if(list.isEmpty()){
sizeMap.remove(sizeKey);
}
}
}
int size(){
int result=0;
for(Iterator i=sizeMap.values().iterator();i.hasNext();){
List list=(List) i.next();
result+=list.size();
}
return result+tree.size();
}
}

View File

@ -0,0 +1,232 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
/**
* A an Item with a relative postion and location to other Items in the Store
*
* @version $Revision: 1.2 $
*/
final class IndexItem implements Item{
static final int INDEX_SIZE=43;
//used by linked list
IndexItem next;
IndexItem prev;
private long offset=POSITION_NOT_SET;
private long previousItem=POSITION_NOT_SET;
private long nextItem=POSITION_NOT_SET;
private long keyOffset=POSITION_NOT_SET;
private int keyFile=(int) POSITION_NOT_SET;
private long valueOffset=POSITION_NOT_SET;
private int valueFile=(int) POSITION_NOT_SET;
private boolean active=true;
/**
* Default Constructor
*/
IndexItem(){}
void reset(){
previousItem=POSITION_NOT_SET;
nextItem=POSITION_NOT_SET;
keyOffset=POSITION_NOT_SET;
keyFile=(int) POSITION_NOT_SET;
valueOffset=POSITION_NOT_SET;
valueFile=(int) POSITION_NOT_SET;
active=true;
}
DataItem getKeyDataItem(){
DataItem result=new DataItem();
result.setOffset(keyOffset);
result.setFile(keyFile);
return result;
}
DataItem getValueDataItem(){
DataItem result=new DataItem();
result.setOffset(valueOffset);
result.setFile(valueFile);
return result;
}
void setValueData(DataItem item){
valueOffset=item.getOffset();
valueFile=item.getFile();
}
void setKeyData(DataItem item){
keyOffset=item.getOffset();
keyFile=item.getFile();
}
/**
* @param dataOut
* @throws IOException
*/
void write(DataOutput dataOut) throws IOException{
dataOut.writeShort(MAGIC);
dataOut.writeBoolean(active);
dataOut.writeLong(previousItem);
dataOut.writeLong(nextItem);
dataOut.writeInt(keyFile);
dataOut.writeLong(keyOffset);
dataOut.writeInt(valueFile);
dataOut.writeLong(valueOffset);
}
/**
* @param dataIn
* @throws IOException
*/
void read(DataInput dataIn) throws IOException{
if(dataIn.readShort()!=MAGIC){
throw new BadMagicException();
}
active=dataIn.readBoolean();
previousItem=dataIn.readLong();
nextItem=dataIn.readLong();
keyFile=dataIn.readInt();
keyOffset=dataIn.readLong();
valueFile=dataIn.readInt();
valueOffset=dataIn.readLong();
}
/**
* @param newPrevEntry
*/
void setPreviousItem(long newPrevEntry){
previousItem=newPrevEntry;
}
/**
* @return prev item
*/
long getPreviousItem(){
return previousItem;
}
/**
* @param newNextEntry
*/
void setNextItem(long newNextEntry){
nextItem=newNextEntry;
}
/**
* @return next item
*/
long getNextItem(){
return nextItem;
}
/**
* @param newObjectOffset
*/
void setKeyOffset(long newObjectOffset){
keyOffset=newObjectOffset;
}
/**
* @return key offset
*/
long getKeyOffset(){
return keyOffset;
}
/**
* @return Returns the keyFile.
*/
int getKeyFile(){
return keyFile;
}
/**
* @param keyFile The keyFile to set.
*/
void setKeyFile(int keyFile){
this.keyFile=keyFile;
}
/**
* @return Returns the valueFile.
*/
int getValueFile(){
return valueFile;
}
/**
* @param valueFile The valueFile to set.
*/
void setValueFile(int valueFile){
this.valueFile=valueFile;
}
/**
* @return Returns the valueOffset.
*/
long getValueOffset(){
return valueOffset;
}
/**
* @param valueOffset The valueOffset to set.
*/
void setValueOffset(long valueOffset){
this.valueOffset=valueOffset;
}
/**
* @return Returns the active.
*/
boolean isActive(){
return active;
}
/**
* @param active The active to set.
*/
void setActive(boolean active){
this.active=active;
}
/**
* @return Returns the offset.
*/
long getOffset(){
return offset;
}
/**
* @param offset The offset to set.
*/
void setOffset(long offset){
this.offset=offset;
}
/**
* @return eprtty print of 'this'
*/
public String toString(){
String result="offset="+offset+" , keyFile = "+keyFile+" , keyOffset = "+keyOffset+", valueOffset = "
+valueOffset+" , previousItem = "+previousItem+" , nextItem = "+nextItem;
return result;
}
}

View File

@ -0,0 +1,276 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
/**
* A linked list used by IndexItems
*
* @version $Revision: 1.2 $
*/
final class IndexLinkedList implements Cloneable{
private transient IndexItem root;
private transient int size=0;
/**
* Constructs an empty list.
*/
IndexLinkedList(IndexItem header){
this.root = header;
this.root.next=root.prev=root;
}
IndexItem getRoot(){
return root;
}
/**
* Returns the first element in this list.
*
* @return the first element in this list.
*/
IndexItem getFirst(){
if(size==0)
return null;
return root.next;
}
/**
* Returns the last element in this list.
*
* @return the last element in this list.
*/
IndexItem getLast(){
if(size==0)
return null;
return root.prev;
}
/**
* Removes and returns the first element from this list.
*
* @return the first element from this list.
*/
IndexItem removeFirst(){
if(size==0){
return null;
}
IndexItem result=root.next;
remove(root.next);
return result;
}
/**
* Removes and returns the last element from this list.
*
* @return the last element from this list.
*/
Object removeLast(){
if(size==0)
return null;
IndexItem result=root.prev;
remove(root.prev);
return result;
}
/**
* Inserts the given element at the beginning of this list.
*
* @param o the element to be inserted at the beginning of this list.
*/
void addFirst(IndexItem item){
addBefore(item,root.next);
}
/**
* Appends the given element to the end of this list. (Identical in function to the <tt>add</tt> method; included
* only for consistency.)
*
* @param o the element to be inserted at the end of this list.
*/
void addLast(IndexItem item){
addBefore(item,root);
}
/**
* Returns the number of elements in this list.
*
* @return the number of elements in this list.
*/
int size(){
return size;
}
/**
* is the list empty?
*
* @return true if there are no elements in the list
*/
boolean isEmpty(){
return size==0;
}
/**
* Appends the specified element to the end of this list.
*
* @param o element to be appended to this list.
* @return <tt>true</tt> (as per the general contract of <tt>Collection.add</tt>).
*/
boolean add(IndexItem item){
addBefore(item,root);
return true;
}
/**
* Removes all of the elements from this list.
*/
void clear(){
root.next=root.prev=root;
size=0;
}
// Positional Access Operations
/**
* Returns the element at the specified position in this list.
*
* @param index index of element to return.
* @return the element at the specified position in this list.
*
* @throws IndexOutOfBoundsException if the specified index is is out of range (<tt>index &lt; 0 || index &gt;= size()</tt>).
*/
IndexItem get(int index){
return entry(index);
}
/**
* Inserts the specified element at the specified position in this list. Shifts the element currently at that
* position (if any) and any subsequent elements to the right (adds one to their indices).
*
* @param index index at which the specified element is to be inserted.
* @param element element to be inserted.
*
* @throws IndexOutOfBoundsException if the specified index is out of range (<tt>index &lt; 0 || index &gt; size()</tt>).
*/
void add(int index,IndexItem element){
addBefore(element,(index==size?root:entry(index)));
}
/**
* Removes the element at the specified position in this list. Shifts any subsequent elements to the left (subtracts
* one from their indices). Returns the element that was removed from the list.
*
* @param index the index of the element to removed.
* @return the element previously at the specified position.
*
* @throws IndexOutOfBoundsException if the specified index is out of range (<tt>index &lt; 0 || index &gt;= size()</tt>).
*/
Object remove(int index){
IndexItem e=entry(index);
remove(e);
return e;
}
/**
* Return the indexed entry.
*/
private IndexItem entry(int index){
if(index<0||index>=size)
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
IndexItem e=root;
if(index<size/2){
for(int i=0;i<=index;i++)
e=e.next;
}else{
for(int i=size;i>index;i--)
e=e.prev;
}
return e;
}
// Search Operations
/**
* Returns the index in this list of the first occurrence of the specified element, or -1 if the List does not
* contain this element. More formally, returns the lowest index i such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>, or -1 if there is no such index.
*
* @param o element to search for.
* @return the index in this list of the first occurrence of the specified element, or -1 if the list does not
* contain this element.
*/
int indexOf(IndexItem o){
int index=0;
for(IndexItem e=root.next;e!=root;e=e.next){
if(o==e){
return index;
}
index++;
}
return -1;
}
/**
* Retrieve the next entry after this entry
*
* @param entry
* @return next entry
*/
IndexItem getNextEntry(IndexItem entry){
return entry.next != root ? entry.next : null;
}
/**
* Retrive the prev entry after this entry
*
* @param entry
* @return prev entry
*/
IndexItem getPrevEntry(IndexItem entry){
return entry.prev != root ? entry.prev : null;
}
/**
* Insert an Entry before this entry
*
* @param o the elment to insert
* @param e the Entry to insert the object before
*
*/
void addBefore(IndexItem insert,IndexItem e){
insert.next=e;
insert.prev=e.prev;
insert.prev.next=insert;
insert.next.prev=insert;
size++;
}
void remove(IndexItem e){
if(e==root)
return;
e.prev.next=e.next;
e.next.prev=e.prev;
size--;
}
/**
*@return clone
*/
public Object clone(){
IndexLinkedList clone=new IndexLinkedList(this.root);
for(IndexItem e=root.next;e!=root;e=e.next)
clone.add(e);
return clone;
}
}

View File

@ -0,0 +1,121 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.LinkedList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Optimized Store reader
*
* @version $Revision: 1.1.1.1 $
*/
final class IndexManager{
private static final Log log=LogFactory.getLog(IndexManager.class);
private File file;
private RandomAccessFile indexFile;
private StoreIndexReader reader;
private StoreIndexWriter writer;
private LinkedList freeList=new LinkedList();
private long length=0;
IndexManager(File ifile,String mode) throws IOException{
file=ifile;
indexFile=new RandomAccessFile(ifile,mode);
reader=new StoreIndexReader(indexFile);
writer=new StoreIndexWriter(indexFile);
long offset=0;
while((offset+IndexItem.INDEX_SIZE)<=indexFile.length()){
IndexItem index=reader.readItem(offset);
if(!index.isActive()){
index.reset();
freeList.add(index);
}
offset+=IndexItem.INDEX_SIZE;
}
length=offset;
}
synchronized boolean isEmpty() throws IOException{
return freeList.isEmpty()&&length==0;
}
synchronized IndexItem getIndex(long offset) throws IOException{
return reader.readItem(offset);
}
synchronized void freeIndex(IndexItem item) throws IOException{
item.reset();
item.setActive(false);
writer.storeItem(item);
freeList.add(item);
}
synchronized void updateIndex(IndexItem index) throws IOException{
writer.storeItem(index);
}
synchronized IndexItem createNewIndex() throws IOException{
IndexItem result=getNextFreeIndex();
if(result==null){
// allocate one
result=new IndexItem();
result.setOffset(length);
length+=IndexItem.INDEX_SIZE;
}
return result;
}
synchronized void close() throws IOException{
if(indexFile!=null){
indexFile.close();
indexFile=null;
}
}
synchronized void force() throws IOException{
if(indexFile!=null){
indexFile.getFD().sync();
}
}
synchronized boolean delete() throws IOException{
freeList.clear();
if(indexFile!=null){
indexFile.close();
indexFile=null;
}
return file.delete();
}
private IndexItem getNextFreeIndex() throws IOException{
IndexItem result=null;
if(!freeList.isEmpty()){
result=(IndexItem) freeList.removeLast();
result.reset();
}
return result;
}
long getLength(){
return length;
}
void setLength(long value){
this.length=value;
}
}

View File

@ -0,0 +1,120 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import org.apache.activemq.kaha.Marshaller;
import org.apache.activemq.kaha.ObjectMarshaller;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
/**
* A container of roots for other Containers
*
* @version $Revision: 1.2 $
*/
class IndexRootContainer {
private static final Log log=LogFactory.getLog(IndexRootContainer.class);
protected static final Marshaller rootMarshaller = new ObjectMarshaller();
protected IndexItem root;
protected IndexManager indexManager;
protected DataManager dataManager;
protected Map map = new ConcurrentHashMap();
protected LinkedList list = new LinkedList();
IndexRootContainer(IndexItem root,IndexManager im,DataManager dfm) throws IOException{
this.root=root;
this.indexManager=im;
this.dataManager=dfm;
long nextItem=root.getNextItem();
while(nextItem!=Item.POSITION_NOT_SET){
IndexItem item=indexManager.getIndex(nextItem);
DataItem data=item.getKeyDataItem();
Object key=dataManager.readItem(rootMarshaller,data);
map.put(key,item);
list.add(item);
nextItem=item.getNextItem();
dataManager.addInterestInFile(item.getKeyFile());
}
}
Set getKeys(){
return map.keySet();
}
IndexItem addRoot(Object key) throws IOException{
if (map.containsKey(key)){
removeRoot(key);
}
DataItem data = dataManager.storeItem(rootMarshaller, key);
IndexItem index = indexManager.createNewIndex();
index.setKeyData(data);
IndexItem newRoot = indexManager.createNewIndex();
indexManager.updateIndex(newRoot);
index.setValueOffset(newRoot.getOffset());
IndexItem last=list.isEmpty()?null:(IndexItem) list.getLast();
last=last==null?root:last;
long prev=last.getOffset();
index.setPreviousItem(prev);
indexManager.updateIndex(index);
last.setNextItem(index.getOffset());
indexManager.updateIndex(last);
map.put(key, index);
list.add(index);
return newRoot;
}
void removeRoot(Object key) throws IOException{
IndexItem item = (IndexItem) map.remove(key);
if (item != null){
dataManager.removeInterestInFile(item.getKeyFile());
IndexItem rootIndex = indexManager.getIndex(item.getValueOffset());
indexManager.freeIndex(rootIndex);
int index=list.indexOf(item);
IndexItem prev=index>0?(IndexItem) list.get(index-1):root;
prev=prev==null?root:prev;
IndexItem next=index<(list.size()-1)?(IndexItem) list.get(index+1):null;
if(next!=null){
prev.setNextItem(next.getOffset());
next.setPreviousItem(prev.getOffset());
indexManager.updateIndex(next);
}else{
prev.setNextItem(Item.POSITION_NOT_SET);
}
indexManager.updateIndex(prev);
list.remove(item);
}
}
IndexItem getRoot(Object key) throws IOException{
IndexItem index = (IndexItem) map.get(key);
if (index != null){
return indexManager.getIndex(index.getValueOffset());
}
throw new IOException("Cannot find root for key " + key);
}
}

View File

@ -13,104 +13,15 @@
*/
package org.apache.activemq.kaha.impl;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import org.apache.activemq.kaha.Marshaller;
/**
* A a wrapper for a data in the store
*
* @version $Revision: 1.2 $
*/
public class Item{
public interface Item{
static final long POSITION_NOT_SET=-1;
static final short MAGIC=31317;
static final int ACTIVE=22;
static final int FREE=33;
static final int HEAD_SIZE=8; // magic + active + len
static final int LOCATION_SIZE=24;
private long offset=POSITION_NOT_SET;
private int size;
private boolean active;
Item(){}
void writeHeader(DataOutput dataOut) throws IOException{
dataOut.writeShort(MAGIC);
dataOut.writeByte(active?ACTIVE:FREE);
dataOut.writeInt(size);
dataOut.writeByte(0);//padding
}
void readHeader(DataInput dataIn) throws IOException{
int magic=dataIn.readShort();
if(magic==MAGIC){
active=(dataIn.readByte()==ACTIVE);
size=dataIn.readInt();
}else if (magic == 0){
size = -999; //end of data
}else{
throw new BadMagicException("Unexpected Magic value: "+magic);
}
}
void writePayload(Marshaller marshaller,Object object,DataOutputStream dataOut) throws IOException{
marshaller.writePayload(object,dataOut);
}
Object readPayload(Marshaller marshaller,DataInputStream dataIn) throws IOException{
return marshaller.readPayload(dataIn);
}
void readLocation(DataInput dataIn) throws IOException{}
void writeLocation(DataOutput dataOut) throws IOException{}
/**
* @return Returns the size.
*/
int getSize(){
return size;
}
/**
* @param size
* The size to set.
*/
void setSize(int size){
this.size=size;
}
void setOffset(long pos){
offset=pos;
}
long getOffset(){
return offset;
}
/**
* @return Returns the active.
*/
boolean isActive(){
return active;
}
/**
* @param active
* The active to set.
*/
void setActive(boolean active){
this.active=active;
}
/**
* @return a pretty print
*/
public String toString(){
String result="offset = "+offset+" ,active = "+active+" , size = "+size;
return result;
}
}

View File

@ -0,0 +1,205 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
/**
* Optimized writes to a RandomAcessFile
*
* @version $Revision: 1.1.1.1 $
*/
package org.apache.activemq.kaha.impl;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.activemq.kaha.ListContainer;
import org.apache.activemq.kaha.MapContainer;
import org.apache.activemq.kaha.RuntimeStoreException;
import org.apache.activemq.kaha.Store;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
/**
* Optimized Store writer
*
* @version $Revision: 1.1.1.1 $
*/
public class KahaStore implements Store{
DataManager rootData;
DataManager containersData;
IndexManager indexManager;
private IndexRootContainer mapsContainer;
private IndexRootContainer listsContainer;
private Map lists=new ConcurrentHashMap();
private Map maps=new ConcurrentHashMap();
private boolean closed=false;
private String name;
private String mode;
private boolean initialized;
public KahaStore(String name,String mode) throws IOException{
this.name=name;
this.mode=mode;
initialize();
}
public synchronized void close() throws IOException{
if(!closed){
closed=true;
if(initialized){
indexManager.close();
rootData.close();
containersData.close();
}
}
}
public synchronized void force() throws IOException{
if(initialized){
indexManager.force();
rootData.force();
containersData.force();
}
}
public synchronized void clear() throws IOException{
initialize();
for(Iterator i=maps.values().iterator();i.hasNext();){
BaseContainerImpl container=(BaseContainerImpl) i.next();
container.clear();
}
for(Iterator i=lists.values().iterator();i.hasNext();){
BaseContainerImpl container=(BaseContainerImpl) i.next();
container.clear();
}
lists.clear();
maps.clear();
}
public synchronized boolean delete() throws IOException{
initialize();
clear();
boolean result=indexManager.delete();
result&=rootData.delete();
result&=containersData.delete();
initialized=false;
return result;
}
public boolean doesMapContainerExist(Object id) throws IOException{
initialize();
return maps.containsKey(id);
}
public MapContainer getMapContainer(Object id) throws IOException{
initialize();
MapContainer result=(MapContainer) maps.get(id);
if(result==null){
IndexItem root=mapsContainer.addRoot(id);
result=new MapContainerImpl(id,root,indexManager,containersData);
maps.put(id,result);
}
return result;
}
public void deleteMapContainer(Object id) throws IOException{
initialize();
MapContainer container=(MapContainer) maps.remove(id);
if(container!=null){
container.clear();
mapsContainer.removeRoot(id);
}
}
public Set getMapContainerIds() throws IOException{
initialize();
return maps.keySet();
}
public boolean doesListContainerExist(Object id) throws IOException{
initialize();
return lists.containsKey(id);
}
public ListContainer getListContainer(Object id) throws IOException{
initialize();
ListContainer result=(ListContainer) lists.get(id);
if(result==null){
IndexItem root=listsContainer.addRoot(id);
result=new ListContainerImpl(id,root,indexManager,containersData);
lists.put(id,result);
}
return result;
}
public void deleteListContainer(Object id) throws IOException{
initialize();
ListContainer container=(ListContainer) lists.remove(id);
if(container!=null){
container.clear();
listsContainer.removeRoot(id);
}
}
public Set getListContainerIds() throws IOException{
initialize();
return lists.keySet();
}
protected void checkClosed(){
if(closed){
throw new RuntimeStoreException("The store is closed");
}
}
protected synchronized void initialize() throws IOException{
if(!initialized){
initialized=true;
File dir=new File(name);
dir.mkdirs();
File ifile=new File(dir,"kaha.idx");
indexManager=new IndexManager(ifile,mode);
rootData=new DataManager(dir,"roots-data");
containersData=new DataManager(dir,"containers-data");
IndexItem mapRoot=new IndexItem();
IndexItem listRoot=new IndexItem();
if(indexManager.isEmpty()){
mapRoot.setOffset(0);
indexManager.updateIndex(mapRoot);
listRoot.setOffset(IndexItem.INDEX_SIZE);
indexManager.updateIndex(listRoot);
indexManager.setLength(IndexItem.INDEX_SIZE*2);
}else{
mapRoot=indexManager.getIndex(0);
listRoot=indexManager.getIndex(IndexItem.INDEX_SIZE);
}
mapsContainer=new IndexRootContainer(mapRoot,indexManager,rootData);
listsContainer=new IndexRootContainer(listRoot,indexManager,rootData);
rootData.consolidateDataFiles();
for(Iterator i=mapsContainer.getKeys().iterator();i.hasNext();){
Object key=i.next();
IndexItem root=mapsContainer.getRoot(key);
BaseContainerImpl container=new MapContainerImpl(key,root,indexManager,containersData);
container.expressDataInterest();
maps.put(key,container);
}
for(Iterator i=listsContainer.getKeys().iterator();i.hasNext();){
Object key=i.next();
IndexItem root=listsContainer.getRoot(key);
BaseContainerImpl container=new ListContainerImpl(key,root,indexManager,containersData);
container.expressDataInterest();
lists.put(key,container);
}
containersData.consolidateDataFiles();
}
}
}

View File

@ -17,7 +17,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.apache.activemq.kaha.ListContainer;
@ -31,20 +30,13 @@ import org.apache.commons.logging.LogFactory;
*
* @version $Revision: 1.2 $
*/
public class ListContainerImpl implements ListContainer{
private static final Log log=LogFactory.getLog(MapContainerImpl.class);
protected StoreImpl store;
protected LocatableItem root;
protected Object id;
protected LinkedList list=new LinkedList();
protected boolean loaded=false;
final class ListContainerImpl extends BaseContainerImpl implements ListContainer{
private static final Log log=LogFactory.getLog(ListContainerImpl.class);
protected Marshaller marshaller=new ObjectMarshaller();
protected boolean closed = false;
protected ListContainerImpl(Object id,StoreImpl rfs,LocatableItem root) throws IOException{
this.id=id;
this.store=rfs;
this.root=root;
protected ListContainerImpl(Object id,IndexItem root,IndexManager indexManager,DataManager dataManager)
throws IOException{
super(id,root,indexManager,dataManager);
}
/*
@ -55,21 +47,20 @@ public class ListContainerImpl implements ListContainer{
public void load(){
checkClosed();
if(!loaded){
loaded=true;
long start=root.getNextItem();
if(start!=Item.POSITION_NOT_SET){
try{
long nextItem=start;
while(nextItem!=Item.POSITION_NOT_SET){
LocatableItem item=new LocatableItem();
item.setOffset(nextItem);
store.readLocation(item);
list.add(item);
nextItem=item.getNextItem();
synchronized(mutex){
if(!loaded){
loaded=true;
try{
long nextItem=root.getNextItem();
while(nextItem!=Item.POSITION_NOT_SET){
IndexItem item=indexManager.getIndex(nextItem);
list.add(item);
nextItem=item.getNextItem();
}
}catch(IOException e){
log.error("Failed to load container "+getId(),e);
throw new RuntimeStoreException(e);
}
}catch(IOException e){
log.error("Failed to load container "+getId(),e);
throw new RuntimeStoreException(e);
}
}
}
@ -83,25 +74,10 @@ public class ListContainerImpl implements ListContainer{
public void unload(){
checkClosed();
if(loaded){
loaded = false;
loaded=false;
list.clear();
}
}
public void close(){
unload();
closed = true;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.ListContainer#isLoaded()
*/
public boolean isLoaded(){
checkClosed();
return loaded;
}
/*
* (non-Javadoc)
@ -113,33 +89,23 @@ public class ListContainerImpl implements ListContainer{
this.marshaller=marshaller;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.ListContainer#getId()
*/
public Object getId(){
checkClosed();
return id;
}
public boolean equals(Object obj){
checkLoaded();
checkClosed();
boolean result = false;
if (obj != null && obj instanceof List){
List other = (List) obj;
synchronized(list){
result = other.size() == size();
if (result){
for (int i =0; i < list.size(); i++){
Object o1 = other.get(i);
Object o2 = get(i);
result = o1 == o2 || (o1 != null && o2 != null && o1.equals(o2));
if (!result) break;
load();
boolean result=false;
if(obj!=null&&obj instanceof List){
List other=(List) obj;
synchronized(mutex){
result=other.size()==size();
if(result){
for(int i=0;i<list.size();i++){
Object o1=other.get(i);
Object o2=get(i);
result=o1==o2||(o1!=null&&o2!=null&&o1.equals(o2));
if(!result)
break;
}
}
}
}
}
return result;
}
@ -150,8 +116,7 @@ public class ListContainerImpl implements ListContainer{
* @see org.apache.activemq.kaha.ListContainer#size()
*/
public int size(){
checkClosed();
checkLoaded();
load();
return list.size();
}
@ -161,10 +126,9 @@ public class ListContainerImpl implements ListContainer{
* @see org.apache.activemq.kaha.ListContainer#addFirst(java.lang.Object)
*/
public void addFirst(Object o){
checkClosed();
checkLoaded();
LocatableItem item=writeFirst(o);
synchronized(list){
load();
IndexItem item=writeFirst(o);
synchronized(mutex){
list.addFirst(item);
}
}
@ -175,10 +139,9 @@ public class ListContainerImpl implements ListContainer{
* @see org.apache.activemq.kaha.ListContainer#addLast(java.lang.Object)
*/
public void addLast(Object o){
checkClosed();
checkLoaded();
LocatableItem item=writeLast(o);
synchronized(list){
load();
IndexItem item=writeLast(o);
synchronized(mutex){
list.addLast(item);
}
}
@ -189,16 +152,15 @@ public class ListContainerImpl implements ListContainer{
* @see org.apache.activemq.kaha.ListContainer#removeFirst()
*/
public Object removeFirst(){
checkClosed();
checkLoaded();
load();
Object result=null;
synchronized(list){
LocatableItem item=(LocatableItem) list.getFirst();
synchronized(mutex){
IndexItem item=(IndexItem) list.getFirst();
if(item!=null){
result=getValue(item);
int index=list.indexOf(item);
LocatableItem prev=index>0?(LocatableItem) list.get(index-1):root;
LocatableItem next=index<(list.size()-1)?(LocatableItem) list.get(index+1):null;
IndexItem prev=index>0?(IndexItem) list.get(index-1):root;
IndexItem next=index<(list.size()-1)?(IndexItem) list.get(index+1):null;
list.removeFirst();
delete(item,prev,next);
item=null;
@ -213,16 +175,15 @@ public class ListContainerImpl implements ListContainer{
* @see org.apache.activemq.kaha.ListContainer#removeLast()
*/
public Object removeLast(){
checkClosed();
checkLoaded();
load();
Object result=null;
synchronized(list){
LocatableItem item=(LocatableItem) list.getLast();
synchronized(mutex){
IndexItem item=(IndexItem) list.getLast();
if(item!=null){
result=getValue(item);
int index=list.indexOf(item);
LocatableItem prev=index>0?(LocatableItem) list.get(index-1):root;
LocatableItem next=null;
IndexItem prev=index>0?(IndexItem) list.get(index-1):root;
IndexItem next=null;
list.removeLast();
delete(item,prev,next);
item=null;
@ -237,8 +198,7 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#isEmpty()
*/
public boolean isEmpty(){
checkClosed();
checkLoaded();
load();
return list.isEmpty();
}
@ -248,18 +208,18 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#contains(java.lang.Object)
*/
public boolean contains(Object o){
checkClosed();
checkLoaded();
load();
boolean result=false;
if(o!=null){
synchronized(list){
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
Object value=getValue(item);
synchronized(mutex){
IndexItem next=list.getFirst();
while(next!=null){
Object value=getValue(next);
if(value!=null&&value.equals(o)){
result=true;
break;
}
next=list.getNextEntry(next);
}
}
}
@ -272,8 +232,7 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#iterator()
*/
public Iterator iterator(){
checkClosed();
checkLoaded();
load();
return listIterator();
}
@ -283,14 +242,14 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#toArray()
*/
public Object[] toArray(){
checkClosed();
checkLoaded();
load();
List tmp=new ArrayList(list.size());
synchronized(list){
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
Object value=getValue(item);
synchronized(mutex){
IndexItem next=list.getFirst();
while(next!=null){
Object value=getValue(next);
tmp.add(value);
next=list.getNextEntry(next);
}
}
return tmp.toArray();
@ -302,14 +261,14 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#toArray(T[])
*/
public Object[] toArray(Object[] a){
checkClosed();
checkLoaded();
load();
List tmp=new ArrayList(list.size());
synchronized(list){
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
Object value=getValue(item);
synchronized(mutex){
IndexItem next=list.getFirst();
while(next!=null){
Object value=getValue(next);
tmp.add(value);
next=list.getNextEntry(next);
}
}
return tmp.toArray(a);
@ -321,8 +280,7 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#add(E)
*/
public boolean add(Object o){
checkClosed();
checkLoaded();
load();
addLast(o);
return true;
}
@ -333,28 +291,28 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#remove(java.lang.Object)
*/
public boolean remove(Object o){
checkClosed();
checkLoaded();
load();
boolean result=false;
synchronized(list){
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
Object value = getValue(item);
if (value != null && value.equals(o)){
remove(item);
synchronized(mutex){
IndexItem next=list.getFirst();
while(next!=null){
Object value=getValue(next);
if(value!=null&&value.equals(o)){
remove(next);
result=true;
break;
}
next=list.getNextEntry(next);
}
}
return result;
}
protected void remove(LocatableItem item){
synchronized(list){
protected void remove(IndexItem item){
synchronized(mutex){
int index=list.indexOf(item);
LocatableItem prev=index>0?(LocatableItem) list.get(index-1):root;
LocatableItem next=index<(list.size()-1)?(LocatableItem) list.get(index+1):null;
IndexItem prev=index>0?(IndexItem) list.get(index-1):root;
IndexItem next=index<(list.size()-1)?(IndexItem) list.get(index+1):null;
list.remove(index);
delete(item,prev,next);
}
@ -366,10 +324,9 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#containsAll(java.util.Collection)
*/
public boolean containsAll(Collection c){
checkClosed();
checkLoaded();
load();
boolean result=false;
synchronized(list){
synchronized(mutex){
for(Iterator i=c.iterator();i.hasNext();){
Object obj=i.next();
if(!(result=contains(obj))){
@ -387,14 +344,12 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#addAll(java.util.Collection)
*/
public boolean addAll(Collection c){
checkClosed();
checkLoaded();
load();
boolean result=false;
for(Iterator i=c.iterator();i.hasNext();){
add(i.next());
result=true;
}
return result;
return true;
}
/*
@ -403,8 +358,7 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#addAll(int, java.util.Collection)
*/
public boolean addAll(int index,Collection c){
checkClosed();
checkLoaded();
load();
boolean result=false;
ListIterator e1=listIterator(index);
Iterator e2=c.iterator();
@ -421,8 +375,7 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#removeAll(java.util.Collection)
*/
public boolean removeAll(Collection c){
checkClosed();
checkLoaded();
load();
boolean result=true;
for(Iterator i=c.iterator();i.hasNext();){
Object obj=i.next();
@ -437,19 +390,18 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#retainAll(java.util.Collection)
*/
public boolean retainAll(Collection c){
checkClosed();
checkLoaded();
load();
List tmpList=new ArrayList();
synchronized(list){
for(Iterator i = list.iterator(); i.hasNext();){
LocatableItem item = (LocatableItem) i.next();
Object o = getValue(item);
if(!c.contains(o)){
tmpList.add(o);
synchronized(mutex){
IndexItem next=list.getFirst();
while(next!=null){
Object o=getValue(next);
if(!c.contains(o)){
tmpList.add(o);
}
next=list.getNextEntry(next);
}
}
}
for(Iterator i=tmpList.iterator();i.hasNext();){
remove(i.next());
}
@ -463,30 +415,9 @@ public class ListContainerImpl implements ListContainer{
*/
public void clear(){
checkClosed();
synchronized(list){
synchronized(mutex){
list.clear();
try {
long start=root.getNextItem();
if(start!=Item.POSITION_NOT_SET){
long nextItem=start;
while(nextItem!=Item.POSITION_NOT_SET){
LocatableItem item=new LocatableItem();
item.setOffset(nextItem);
list.add(item);
nextItem=item.getNextItem();
}
}
root.setNextItem(Item.POSITION_NOT_SET);
store.updateItem(root);
for(int i=0;i<list.size();i++){
LocatableItem item=(LocatableItem) list.get(i);
store.removeItem(item);
}
list.clear();
}catch(IOException e){
log.error("Failed to clear ListContainer "+getId(),e);
throw new RuntimeStoreException(e);
}
doClear();
}
}
@ -496,10 +427,9 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#get(int)
*/
public Object get(int index){
checkClosed();
checkLoaded();
load();
Object result=null;
LocatableItem item=(LocatableItem) list.get(index);
IndexItem item=(IndexItem) list.get(index);
if(item!=null){
result=getValue(item);
}
@ -512,13 +442,12 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#set(int, E)
*/
public Object set(int index,Object element){
checkClosed();
checkLoaded();
load();
Object result=null;
synchronized(list){
LocatableItem replace=list.isEmpty()?null:(LocatableItem) list.get(index);
LocatableItem prev=(list.isEmpty() || (index-1) < 0)?null:(LocatableItem) list.get(index-1);
LocatableItem next=(list.isEmpty() || (index+1) >= size())?null:(LocatableItem) list.get(index+1);
synchronized(mutex){
IndexItem replace=list.isEmpty()?null:(IndexItem) list.get(index);
IndexItem prev=(list.isEmpty()||(index-1)<0)?null:(IndexItem) list.get(index-1);
IndexItem next=(list.isEmpty()||(index+1)>=size())?null:(IndexItem) list.get(index+1);
result=getValue(replace);
list.remove(index);
delete(replace,prev,next);
@ -526,12 +455,12 @@ public class ListContainerImpl implements ListContainer{
}
return result;
}
protected LocatableItem internalSet(int index,Object element){
synchronized(list){
LocatableItem replace=list.isEmpty()?null:(LocatableItem) list.get(index);
LocatableItem prev=(list.isEmpty() || (index-1) < 0)?null:(LocatableItem) list.get(index-1);
LocatableItem next=(list.isEmpty() || (index+1) >= size())?null:(LocatableItem) list.get(index+1);
protected IndexItem internalSet(int index,Object element){
synchronized(mutex){
IndexItem replace=list.isEmpty()?null:(IndexItem) list.get(index);
IndexItem prev=(list.isEmpty()||(index-1)<0)?null:(IndexItem) list.get(index-1);
IndexItem next=(list.isEmpty()||(index+1)>=size())?null:(IndexItem) list.get(index+1);
list.remove(index);
delete(replace,prev,next);
return internalAdd(index,element);
@ -544,26 +473,25 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#add(int, E)
*/
public void add(int index,Object element){
checkClosed();
checkLoaded();
synchronized(list){
LocatableItem item=insert(index,element);
load();
synchronized(mutex){
IndexItem item=insert(index,element);
list.add(index,item);
}
}
protected LocatableItem internalAdd(int index,Object element){
synchronized(list){
LocatableItem item=insert(index,element);
protected IndexItem internalAdd(int index,Object element){
synchronized(mutex){
IndexItem item=insert(index,element);
list.add(index,item);
return item;
}
}
protected LocatableItem internalGet(int index){
synchronized(list){
if (index >= 0 && index < list.size()){
return (LocatableItem) list.get(index);
protected IndexItem internalGet(int index){
synchronized(mutex){
if(index>=0&&index<list.size()){
return list.get(index);
}
}
return null;
@ -575,17 +503,17 @@ public class ListContainerImpl implements ListContainer{
* @see org.apache.activemq.kaha.ListContainer#doRemove(int)
*/
public boolean doRemove(int index){
checkClosed();
checkLoaded();
load();
boolean result=false;
synchronized(list){
LocatableItem item=(LocatableItem) list.get(index);
synchronized(mutex){
IndexItem item=list.get(index);
if(item!=null){
LocatableItem prev=index>0?(LocatableItem) list.get(index-1):root;
LocatableItem next=index<(list.size()-1)?(LocatableItem) list.get(index+1):null;
result=true;
IndexItem prev=list.getPrevEntry(item);
prev=prev!=null?prev:root;
IndexItem next=list.getNextEntry(prev);
list.remove(index);
delete(item,prev,next);
result=true;
}
}
return result;
@ -597,15 +525,15 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#remove(int)
*/
public Object remove(int index){
checkClosed();
checkLoaded();
load();
Object result=null;
synchronized(list){
LocatableItem item=(LocatableItem) list.get(index);
synchronized(mutex){
IndexItem item=list.get(index);
if(item!=null){
result=getValue(item);
LocatableItem prev=index>0?(LocatableItem) list.get(index-1):root;
LocatableItem next=index<(list.size()-1)?(LocatableItem) list.get(index+1):null;
IndexItem prev=list.getPrevEntry(item);
prev=prev!=null?prev:root;
IndexItem next=list.getNextEntry(prev);
list.remove(index);
delete(item,prev,next);
}
@ -619,19 +547,20 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#indexOf(java.lang.Object)
*/
public int indexOf(Object o){
checkClosed();
checkLoaded();
load();
int result=-1;
if(o!=null){
synchronized(list){
synchronized(mutex){
int count=0;
for(Iterator i=list.iterator();i.hasNext();count++){
LocatableItem item=(LocatableItem) i.next();
Object value=getValue(item);
IndexItem next=list.getFirst();
while(next!=null){
Object value=getValue(next);
if(value!=null&&value.equals(o)){
result=count;
break;
}
count++;
next=list.getNextEntry(next);
}
}
}
@ -644,19 +573,20 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#lastIndexOf(java.lang.Object)
*/
public int lastIndexOf(Object o){
checkClosed();
checkLoaded();
load();
int result=-1;
if(o!=null){
synchronized(list){
synchronized(mutex){
int count=list.size()-1;
for(ListIterator i=list.listIterator();i.hasPrevious();count--){
LocatableItem item=(LocatableItem) i.previous();
Object value=getValue(item);
IndexItem next=list.getLast();
while(next!=null){
Object value=getValue(next);
if(value!=null&&value.equals(o)){
result=count;
break;
}
count--;
next=list.getPrevEntry(next);
}
}
}
@ -669,10 +599,8 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#listIterator()
*/
public ListIterator listIterator(){
checkClosed();
checkLoaded();
ListIterator iter = ((List) list.clone()).listIterator();
return new ContainerListIterator(this,iter);
load();
return new ContainerListIterator(this,list,list.getRoot());
}
/*
@ -681,11 +609,15 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#listIterator(int)
*/
public ListIterator listIterator(int index){
checkClosed();
checkLoaded();
List result = (List) list.clone();
ListIterator iter = result.listIterator(index);
return new ContainerListIterator(this,iter);
load();
IndexItem start=list.get(index);
if(start!=null){
start=list.getPrevEntry(start);
}
if(start==null){
start=root;
}
return new ContainerListIterator(this,list,start);
}
/*
@ -694,95 +626,114 @@ public class ListContainerImpl implements ListContainer{
* @see java.util.List#subList(int, int)
*/
public List subList(int fromIndex,int toIndex){
checkClosed();
checkLoaded();
List tmp = list.subList(fromIndex, toIndex);
LinkedList result = new LinkedList();
for (Iterator i = tmp.iterator(); i.hasNext();){
LocatableItem item = (LocatableItem) i.next();
result.add(getValue(item));
load();
List result=new ArrayList();
int count=fromIndex;
IndexItem next=list.get(fromIndex);
while(next!=null&&count++<toIndex){
result.add(getValue(next));
next=list.getNextEntry(next);
}
return result;
}
protected LocatableItem writeLast(Object value){
long pos=Item.POSITION_NOT_SET;
LocatableItem item=null;
protected IndexItem writeLast(Object value){
IndexItem index=null;
try{
LocatableItem last=list.isEmpty()?null:(LocatableItem) list.getLast();
last=last==null?root:last;
long prev=last.getOffset();
long next=Item.POSITION_NOT_SET;
item=new LocatableItem(prev,next,pos);
next=store.storeItem(marshaller,value,item);
if(last!=null){
last.setNextItem(next);
store.updateItem(last);
if(value!=null){
DataItem data=dataManager.storeItem(marshaller,value);
index=indexManager.createNewIndex();
index.setValueData(data);
IndexItem prev=list.getLast();
prev=prev!=null?prev:root;
IndexItem next=list.getNextEntry(prev);
prev.setNextItem(index.getOffset());
index.setPreviousItem(prev.getOffset());
indexManager.updateIndex(prev);
if(next!=null){
next.setPreviousItem(index.getOffset());
index.setNextItem(next.getOffset());
indexManager.updateIndex(next);
}
indexManager.updateIndex(index);
}
}catch(IOException e){
log.error("Failed to write "+value,e);
throw new RuntimeStoreException(e);
}
return item;
return index;
}
protected LocatableItem writeFirst(Object value){
long pos=Item.POSITION_NOT_SET;
LocatableItem item=null;
protected IndexItem writeFirst(Object value){
IndexItem index=null;
try{
LocatableItem next=list.isEmpty()?null:(LocatableItem) list.getFirst();
LocatableItem last=root;
long prevPos=last.getOffset();
long nextPos=next!=null?next.getOffset():Item.POSITION_NOT_SET;
item=new LocatableItem(prevPos,nextPos,pos);
nextPos=store.storeItem(marshaller,value,item);
if(last!=null){
last.setNextItem(nextPos);
store.updateItem(last);
}
if(next!=null){
next.setPreviousItem(nextPos);
store.updateItem(next);
if(value!=null){
DataItem data=dataManager.storeItem(marshaller,value);
index=indexManager.createNewIndex();
index.setValueData(data);
IndexItem prev=root;
IndexItem next=list.getNextEntry(prev);
prev.setNextItem(index.getOffset());
index.setPreviousItem(prev.getOffset());
indexManager.updateIndex(prev);
if(next!=null){
next.setPreviousItem(index.getOffset());
index.setNextItem(next.getOffset());
indexManager.updateIndex(next);
}
indexManager.updateIndex(index);
}
}catch(IOException e){
log.error("Failed to write "+value,e);
throw new RuntimeStoreException(e);
}
return item;
return index;
}
protected LocatableItem insert(int insertPos,Object value){
protected IndexItem insert(int insertPos,Object value){
long pos=Item.POSITION_NOT_SET;
LocatableItem item=null;
IndexItem index=null;
try{
int lastPos=insertPos-1;
LocatableItem prev=(list.isEmpty() || (insertPos-1) < 0)?null:(LocatableItem) list.get(lastPos);
LocatableItem next=(list.isEmpty() || (insertPos+1) >= size())?null:(LocatableItem) list.get(insertPos+1);
prev=prev==null?root:prev;
long prevPos=prev.getOffset();
long nextPos=next!=null?next.getOffset():Item.POSITION_NOT_SET;
item=new LocatableItem(prevPos,nextPos,pos);
nextPos=store.storeItem(marshaller,value,item);
if(prev!=null){
prev.setNextItem(nextPos);
store.updateItem(prev);
}
if(next!=null){
next.setPreviousItem(nextPos);
store.updateItem(next);
if(value!=null){
DataItem data=dataManager.storeItem(marshaller,value);
index=indexManager.createNewIndex();
index.setValueData(data);
IndexItem prev=null;
IndexItem next=null;
if(insertPos<=0){
prev=root;
next=list.getNextEntry(root);
}else if(insertPos>=list.size()){
prev=list.getLast();
next=null;
}else{
prev=list.get(insertPos);
prev=prev!=null?prev:root;
next=list.getNextEntry(prev);
}
prev.setNextItem(index.getOffset());
index.setPreviousItem(prev.getOffset());
indexManager.updateIndex(prev);
if(next!=null){
next.setPreviousItem(index.getOffset());
index.setNextItem(next.getOffset());
indexManager.updateIndex(next);
}
indexManager.updateIndex(index);
}
}catch(IOException e){
log.error("Failed to insert "+value,e);
throw new RuntimeStoreException(e);
}
return item;
return index;
}
protected Object getValue(LocatableItem item){
protected Object getValue(IndexItem item){
Object result=null;
if(item!=null){
try{
result=store.readItem(marshaller,item);
DataItem data=item.getValueDataItem();
result=dataManager.readItem(marshaller,data);
}catch(IOException e){
log.error("Failed to get value for "+item,e);
throw new RuntimeStoreException(e);
@ -790,33 +741,4 @@ public class ListContainerImpl implements ListContainer{
}
return result;
}
protected void delete(LocatableItem item,LocatableItem prev,LocatableItem next){
try{
prev=prev==null?root:prev;
if(next!=null){
prev.setNextItem(next.getOffset());
next.setPreviousItem(prev.getOffset());
store.updateItem(next);
}else{
prev.setNextItem(Item.POSITION_NOT_SET);
}
store.updateItem(prev);
store.removeItem(item);
}catch(IOException e){
log.error("Failed to delete "+item,e);
throw new RuntimeStoreException(e);
}
}
protected final void checkClosed(){
if (closed){
throw new RuntimeStoreException("The store is closed");
}
}
protected final void checkLoaded(){
if (!loaded){
throw new RuntimeStoreException("The container is not loaded");
}
}
}

View File

@ -1,126 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import org.apache.activemq.kaha.Marshaller;
/**
* A an Item with a relative postion and location to other Items in the Store
*
* @version $Revision: 1.2 $
*/
public final class LocatableItem extends Item implements Externalizable{
private static final long serialVersionUID=-6888731361600185708L;
private long previousItem=POSITION_NOT_SET;
private long nextItem=POSITION_NOT_SET;
private long referenceItem=POSITION_NOT_SET;
public LocatableItem(){}
public LocatableItem(long prev,long next,long objOffset) throws IOException{
this.previousItem=prev;
this.nextItem=next;
this.referenceItem=objOffset;
}
public void writePayload(Marshaller marshaller,Object object,DataOutputStream dataOut) throws IOException{
dataOut.writeLong(previousItem);
dataOut.writeLong(nextItem);
dataOut.writeLong(referenceItem);
super.writePayload(marshaller,object,dataOut);
}
public Object readPayload(Marshaller marshaller,DataInputStream dataIn) throws IOException{
previousItem=dataIn.readLong();
nextItem=dataIn.readLong();
referenceItem=dataIn.readLong();
return super.readPayload(marshaller, dataIn);
}
void readLocation(DataInput dataIn) throws IOException{
previousItem=dataIn.readLong();
nextItem=dataIn.readLong();
referenceItem=dataIn.readLong();
}
public void writeLocation(DataOutput dataOut) throws IOException{
dataOut.writeLong(previousItem);
dataOut.writeLong(nextItem);
}
public void setPreviousItem(long newPrevEntry){
previousItem=newPrevEntry;
}
public long getPreviousItem(){
return previousItem;
}
public void setNextItem(long newNextEntry){
nextItem=newNextEntry;
}
public long getNextItem(){
return nextItem;
}
public void setReferenceItem(long newObjectOffset){
referenceItem=newObjectOffset;
}
public long getReferenceItem(){
return referenceItem;
}
/* (non-Javadoc)
* @see org.apache.activemq.kaha.impl.Item#toString()
*/
public String toString(){
String result=super.toString();
result+=" , referenceItem = "+referenceItem+", previousItem = "+previousItem+" , nextItem = "+nextItem;
return result;
}
/* (non-Javadoc)
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
*/
public void writeExternal(ObjectOutput out) throws IOException{
out.writeLong(previousItem);
out.writeLong(nextItem);
out.writeLong(referenceItem);
}
/* (non-Javadoc)
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
*/
public void readExternal(ObjectInput in) throws IOException,ClassNotFoundException{
previousItem = in.readLong();
nextItem = in.readLong();
referenceItem = in.readLong();
}
}

View File

@ -32,24 +32,15 @@ import org.apache.commons.logging.LogFactory;
*
* @version $Revision: 1.2 $
*/
public class MapContainerImpl implements MapContainer{
final class MapContainerImpl extends BaseContainerImpl implements MapContainer{
private static final Log log=LogFactory.getLog(MapContainerImpl.class);
protected StoreImpl store;
protected LocatableItem root;
protected Object id;
protected Map map=new HashMap();
protected Map valueToKeyMap=new HashMap();
protected LinkedList list=new LinkedList();
protected boolean loaded=false;
protected Marshaller keyMarshaller=new ObjectMarshaller();
protected Marshaller valueMarshaller=new ObjectMarshaller();
protected final Object mutex=new Object();
protected boolean closed=false;
protected MapContainerImpl(Object id,StoreImpl si,LocatableItem root) throws IOException{
this.id=id;
this.store=si;
this.root=root;
protected MapContainerImpl(Object id,IndexItem root,IndexManager indexManager,DataManager dataManager){
super(id,root,indexManager,dataManager);
}
/*
@ -60,25 +51,24 @@ public class MapContainerImpl implements MapContainer{
public void load(){
checkClosed();
if(!loaded){
loaded=true;
synchronized(mutex){
try{
long start=root.getNextItem();
if(start!=Item.POSITION_NOT_SET){
long nextItem=start;
if(!loaded){
loaded=true;
try{
long nextItem=root.getNextItem();
while(nextItem!=Item.POSITION_NOT_SET){
LocatableItem item=new LocatableItem();
item.setOffset(nextItem);
Object key=store.readItem(keyMarshaller,item);
IndexItem item=indexManager.getIndex(nextItem);
DataItem data=item.getKeyDataItem();
Object key=dataManager.readItem(keyMarshaller,data);
map.put(key,item);
valueToKeyMap.put(item,key);
list.add(item);
nextItem=item.getNextItem();
}
}catch(IOException e){
log.error("Failed to load container "+getId(),e);
throw new RuntimeStoreException(e);
}
}catch(IOException e){
log.error("Failed to load container "+getId(),e);
throw new RuntimeStoreException(e);
}
}
}
@ -101,11 +91,6 @@ public class MapContainerImpl implements MapContainer{
}
}
public void close(){
unload();
closed=true;
}
public void setKeyMarshaller(Marshaller keyMarshaller){
checkClosed();
this.keyMarshaller=keyMarshaller;
@ -116,34 +101,13 @@ public class MapContainerImpl implements MapContainer{
this.valueMarshaller=valueMarshaller;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.MapContainer#isLoaded()
*/
public boolean isLoaded(){
checkClosed();
return loaded;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.MapContainer#getId()
*/
public Object getId(){
checkClosed();
return id;
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.MapContainer#size()
*/
public int size(){
checkClosed();
checkLoaded();
load();
return map.size();
}
@ -153,8 +117,7 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#isEmpty()
*/
public boolean isEmpty(){
checkClosed();
checkLoaded();
load();
return map.isEmpty();
}
@ -164,8 +127,7 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#containsKey(java.lang.Object)
*/
public boolean containsKey(Object key){
checkClosed();
checkLoaded();
load();
synchronized(mutex){
return map.containsKey(key);
}
@ -177,12 +139,11 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#get(java.lang.Object)
*/
public Object get(Object key){
checkClosed();
checkLoaded();
load();
Object result=null;
LocatableItem item=null;
IndexItem item=null;
synchronized(mutex){
item=(LocatableItem) map.get(key);
item=(IndexItem) map.get(key);
}
if(item!=null){
result=getValue(item);
@ -196,18 +157,18 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#containsValue(java.lang.Object)
*/
public boolean containsValue(Object o){
checkClosed();
checkLoaded();
load();
boolean result=false;
if(o!=null){
synchronized(list){
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
IndexItem item=list.getFirst();
while(item!=null){
Object value=getValue(item);
if(value!=null&&value.equals(o)){
result=true;
break;
}
item=list.getNextEntry(item);
}
}
}
@ -220,8 +181,7 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#putAll(java.util.Map)
*/
public void putAll(Map t){
checkClosed();
checkLoaded();
load();
if(t!=null){
synchronized(mutex){
for(Iterator i=t.entrySet().iterator();i.hasNext();){
@ -238,8 +198,7 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#keySet()
*/
public Set keySet(){
checkClosed();
checkLoaded();
load();
return new ContainerKeySet(this);
}
@ -249,8 +208,7 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#values()
*/
public Collection values(){
checkClosed();
checkLoaded();
load();
return new ContainerValueCollection(this);
}
@ -260,8 +218,7 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#entrySet()
*/
public Set entrySet(){
checkClosed();
checkLoaded();
load();
return new ContainerEntrySet(this);
}
@ -271,14 +228,13 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#put(java.lang.Object, java.lang.Object)
*/
public Object put(Object key,Object value){
checkClosed();
checkLoaded();
load();
Object result=null;
synchronized(mutex){
if(map.containsKey(key)){
result=remove(key);
}
LocatableItem item=write(key,value);
IndexItem item=write(key,value);
map.put(key,item);
valueToKeyMap.put(item,key);
list.add(item);
@ -292,36 +248,31 @@ public class MapContainerImpl implements MapContainer{
* @see org.apache.activemq.kaha.MapContainer#remove(java.lang.Object)
*/
public Object remove(Object key){
checkClosed();
checkLoaded();
load();
Object result=null;
synchronized(mutex){
LocatableItem item=(LocatableItem) map.get(key);
IndexItem item=(IndexItem) map.get(key);
if(item!=null){
map.remove(key);
valueToKeyMap.remove(item);
result=getValue(item);
int index=list.indexOf(item);
LocatableItem prev=index>0?(LocatableItem) list.get(index-1):root;
LocatableItem next=index<(list.size()-1)?(LocatableItem) list.get(index+1):null;
list.remove(index);
{
delete(item,prev,next);
}
item=null;
IndexItem prev=list.getPrevEntry(item);
prev=prev!=null?prev:root;
IndexItem next=list.getNextEntry(item);
list.remove(item);
delete(item,prev,next);
}
}
return result;
}
public boolean removeValue(Object o){
checkClosed();
checkLoaded();
load();
boolean result=false;
if(o!=null){
synchronized(list){
for(Iterator i=list.iterator();i.hasNext();){
LocatableItem item=(LocatableItem) i.next();
synchronized(mutex){
IndexItem item=list.getFirst();
while(item!=null){
Object value=getValue(item);
if(value!=null&&value.equals(o)){
result=true;
@ -332,13 +283,14 @@ public class MapContainerImpl implements MapContainer{
}
break;
}
item=list.getNextEntry(item);
}
}
}
return result;
}
protected void remove(LocatableItem item){
protected void remove(IndexItem item){
Object key=valueToKeyMap.get(item);
if(key!=null){
remove(key);
@ -358,34 +310,7 @@ public class MapContainerImpl implements MapContainer{
map.clear();
valueToKeyMap.clear();
list.clear();// going to re-use this
try{
long start=root.getNextItem();
if(start!=Item.POSITION_NOT_SET){
long nextItem=start;
while(nextItem!=Item.POSITION_NOT_SET){
LocatableItem item=new LocatableItem();
item.setOffset(nextItem);
list.add(item);
nextItem=item.getNextItem();
}
}
root.setNextItem(Item.POSITION_NOT_SET);
store.updateItem(root);
for(int i=0;i<list.size();i++){
LocatableItem item=(LocatableItem) list.get(i);
if(item.getReferenceItem()!=Item.POSITION_NOT_SET){
Item value=new Item();
value.setOffset(item.getReferenceItem());
store.removeItem(value);
}
store.removeItem(item);
}
list.clear();
}catch(IOException e){
log.error("Failed to clear MapContainer "+getId(),e);
throw new RuntimeStoreException(e);
}
doClear();
}
}
}
@ -394,17 +319,16 @@ public class MapContainerImpl implements MapContainer{
return new HashSet(map.keySet());
}
protected LinkedList getItemList(){
protected IndexLinkedList getItemList(){
return list;
}
protected Object getValue(LocatableItem item){
protected Object getValue(IndexItem item){
Object result=null;
if(item!=null&&item.getReferenceItem()!=Item.POSITION_NOT_SET){
Item rec=new Item();
rec.setOffset(item.getReferenceItem());
if(item!=null){
try{
result=store.readItem(valueMarshaller,rec);
DataItem data=item.getValueDataItem();
result=dataManager.readItem(valueMarshaller,data);
}catch(IOException e){
log.error("Failed to get value for "+item,e);
throw new RuntimeStoreException(e);
@ -413,64 +337,29 @@ public class MapContainerImpl implements MapContainer{
return result;
}
protected LocatableItem write(Object key,Object value){
long pos=Item.POSITION_NOT_SET;
LocatableItem item=null;
protected IndexItem write(Object key,Object value){
IndexItem index=null;
try{
if(value!=null){
Item valueItem=new Item();
pos=store.storeItem(valueMarshaller,value,valueItem);
if(key!=null){
index=indexManager.createNewIndex();
DataItem data=dataManager.storeItem(keyMarshaller,key);
index.setKeyData(data);
}
LocatableItem last=list.isEmpty()?null:(LocatableItem) list.getLast();
if(value!=null){
DataItem data=dataManager.storeItem(valueMarshaller,value);
index.setValueData(data);
}
IndexItem last=list.isEmpty()?null:(IndexItem) list.getLast();
last=last==null?root:last;
long prev=last.getOffset();
long next=Item.POSITION_NOT_SET;
item=new LocatableItem(prev,next,pos);
next=store.storeItem(keyMarshaller,key,item);
if(last!=null){
last.setNextItem(next);
store.updateItem(last);
}
index.setPreviousItem(prev);
indexManager.updateIndex(index);
last.setNextItem(index.getOffset());
indexManager.updateIndex(last);
}catch(IOException e){
e.printStackTrace();
log.error("Failed to write "+key+" , "+value,e);
throw new RuntimeStoreException(e);
}
return item;
}
protected void delete(LocatableItem key,LocatableItem prev,LocatableItem next){
try{
prev=prev==null?root:prev;
if(next!=null){
prev.setNextItem(next.getOffset());
next.setPreviousItem(prev.getOffset());
store.updateItem(next);
}else{
prev.setNextItem(Item.POSITION_NOT_SET);
}
store.updateItem(prev);
if(key.getReferenceItem()!=Item.POSITION_NOT_SET){
Item value=new Item();
value.setOffset(key.getReferenceItem());
store.removeItem(value);
}
store.removeItem(key);
}catch(IOException e){
log.error("Failed to delete "+key,e);
throw new RuntimeStoreException(e);
}
}
protected final void checkClosed(){
if(closed){
throw new RuntimeStoreException("The store is closed");
}
}
protected final void checkLoaded(){
if(!loaded){
throw new RuntimeStoreException("The container is not loaded");
}
return index;
}
}

View File

@ -1,97 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import org.apache.activemq.kaha.Marshaller;
import org.apache.activemq.kaha.ObjectMarshaller;
import org.apache.activemq.kaha.RuntimeStoreException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* A container of roots for other Containers
*
* @version $Revision: 1.2 $
*/
class RootContainer extends MapContainerImpl{
private static final Log log=LogFactory.getLog(RootContainer.class);
protected static final Marshaller rootMarshaller = new ObjectMarshaller();
protected RootContainer(Object id,StoreImpl rfs,LocatableItem root) throws IOException{
super(id,rfs,root);
}
protected void addRoot(Object key,LocatableItem er) throws IOException{
if(map.containsKey(key)){
remove(key);
}
LocatableItem entry=writeRoot(key,er);
map.put(key,entry);
synchronized(list){
list.add(entry);
}
}
protected LocatableItem writeRoot(Object key,LocatableItem value){
long pos=Item.POSITION_NOT_SET;
LocatableItem item=null;
try{
if(value!=null){
pos=store.storeItem(rootMarshaller,value,value);
}
LocatableItem last=list.isEmpty()?null:(LocatableItem) list.getLast();
last=last==null?root:last;
long prev=last.getOffset();
long next=Item.POSITION_NOT_SET;
item=new LocatableItem(prev,next,pos);
if(log.isDebugEnabled())
log.debug("writing root ...");
if(log.isDebugEnabled())
log.debug("root = "+value);
next=store.storeItem(rootMarshaller,key,item);
if(last!=null){
last.setNextItem(next);
store.updateItem(last);
}
}catch(IOException e){
e.printStackTrace();
log.error("Failed to write root",e);
throw new RuntimeStoreException(e);
}
return item;
}
protected Object getValue(LocatableItem item){
LocatableItem result=null;
if(item!=null&&item.getReferenceItem()!=Item.POSITION_NOT_SET){
LocatableItem value=new LocatableItem();
value.setOffset(item.getReferenceItem());
try{
result=(LocatableItem) store.readItem(rootMarshaller,value);
//now read the item
result.setOffset(item.getReferenceItem());
store.readItem(rootMarshaller, result);
}catch(IOException e){
log.error("Could not read item "+item,e);
throw new RuntimeStoreException(e);
}
}
return result;
}
}

View File

@ -11,51 +11,42 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.IOException;
import java.io.InputStream;
import java.io.UTFDataFormatException;
/**
* Optimized ByteArrayInputStream that can be used more than once
*
* @version $Revision: 1.1.1.1 $
*/
public class StoreByteArrayInputStream extends ByteArrayInputStream {
final class StoreByteArrayInputStream extends InputStream implements DataInput{
private byte[] buf;
private int pos;
/**
* Creates a <code>WireByteArrayInputStream</code>.
*
* @param buf the input buffer.
*/
public StoreByteArrayInputStream(byte buf[]) {
super(buf);
public StoreByteArrayInputStream(byte buf[]){
this.buf=buf;
this.pos=0;
}
/**
* Creates <code>WireByteArrayInputStream</code> that uses <code>buf</code> as its buffer array.
*
* @param buf the input buffer.
* @param offset the offset in the buffer of the first byte to read.
* @param length the maximum number of bytes to read from the buffer.
*/
public StoreByteArrayInputStream(byte buf[], int offset, int length) {
super(buf, offset, length);
}
/**
* Creates <code>WireByteArrayInputStream</code> with a minmalist byte array
*/
public StoreByteArrayInputStream() {
super(new byte[0]);
public StoreByteArrayInputStream(){
this(new byte[0]);
}
/**
* @return the current position in the stream
*/
public int position(){
public int size(){
return pos;
}
/**
* @return the underlying data array
*/
@ -66,33 +57,21 @@ public class StoreByteArrayInputStream extends ByteArrayInputStream {
/**
* reset the <code>WireByteArrayInputStream</code> to use an new byte array
*
* @param newBuff buffer to use
* @param offset the offset in the buffer of the first byte to read.
* @param length the maximum number of bytes to read from the buffer.
* @param newBuff
*/
public void restart(byte[] newBuff, int offset, int length) {
buf = newBuff;
pos = offset;
count = Math.min(offset + length, newBuff.length);
mark = offset;
public void restart(byte[] newBuff){
buf=newBuff;
pos=0;
}
/**
* reset the <code>WireByteArrayInputStream</code> to use an new byte array
*
* @param newBuff
*/
public void restart(byte[] newBuff) {
restart(newBuff, 0, newBuff.length);
}
/**
* re-start the input stream - reusing the current buffer
*
* @param size
*/
public void restart(int size){
if (buf == null || buf.length < size){
buf = new byte[size];
if(buf==null||buf.length<size){
buf=new byte[size];
}
restart(buf);
}
@ -106,8 +85,8 @@ public class StoreByteArrayInputStream extends ByteArrayInputStream {
*
* @return the next byte of data, or <code>-1</code> if the end of the stream has been reached.
*/
public int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
public int read(){
return (pos<buf.length)?(buf[pos++]&0xff):-1;
}
/**
@ -117,33 +96,173 @@ public class StoreByteArrayInputStream extends ByteArrayInputStream {
* @param off the start offset of the data.
* @param len the maximum number of bytes read.
* @return the total number of bytes read into the buffer, or <code>-1</code> if there is no more data because the
* end of the stream has been reached.
* end of the stream has been reached.
*/
public int read(byte b[], int off, int len) {
if (b == null) {
public int read(byte b[],int off,int len){
if(b==null){
throw new NullPointerException();
}
else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (pos >= count) {
if(pos>=buf.length){
return -1;
}
if (pos + len > count) {
len = count - pos;
if(pos+len>buf.length){
len=buf.length-pos;
}
if (len <= 0) {
if(len<=0){
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
System.arraycopy(buf,pos,b,off,len);
pos+=len;
return len;
}
/**
* @return the number of bytes that can be read from the input stream without blocking.
*/
public int available() {
return count - pos;
public int available(){
return buf.length-pos;
}
public void readFully(byte[] b){
read(b,0,b.length);
}
public void readFully(byte[] b,int off,int len){
read(b,off,len);
}
public int skipBytes(int n){
if(pos+n>buf.length){
n=buf.length-pos;
}
if(n<0){
return 0;
}
pos+=n;
return n;
}
public boolean readBoolean(){
return read()!=0;
}
public byte readByte(){
return (byte) read();
}
public int readUnsignedByte(){
return read();
}
public short readShort(){
int ch1=read();
int ch2=read();
return (short) ((ch1<<8)+(ch2<<0));
}
public int readUnsignedShort(){
int ch1=read();
int ch2=read();
return ((ch1<<8)+(ch2<<0));
}
public char readChar(){
int ch1=read();
int ch2=read();
return (char) ((ch1<<8)+(ch2<<0));
}
public int readInt(){
int ch1=read();
int ch2=read();
int ch3=read();
int ch4=read();
return ((ch1<<24)+(ch2<<16)+(ch3<<8)+(ch4<<0));
}
public long readLong(){
return (((long) buf[pos++]<<56)+((long) (buf[pos++]&255)<<48)+((long) (buf[pos++]&255)<<40)
+((long) (buf[pos++]&255)<<32)+((long) (buf[pos++]&255)<<24)+((buf[pos++]&255)<<16)
+((buf[pos++]&255)<<8)+((buf[pos++]&255)<<0));
}
public float readFloat() throws IOException{
return Float.intBitsToFloat(readInt());
}
public double readDouble() throws IOException{
return Double.longBitsToDouble(readLong());
}
public String readLine(){
int start=pos;
while(pos<buf.length){
int c=read();
if(c=='\n'){
break;
}
if(c=='\r'){
c=read();
if(c!='\n'&&c!=-1){
pos--;
}
break;
}
}
return new String(buf,start,pos);
}
public String readUTF() throws IOException{
int length=readUnsignedShort();
char[] characters=new char[length];
int c,c2,c3;
int count=0;
int total=pos+length;
while(pos<total){
c=(int) buf[pos]&0xff;
if(c>127)
break;
pos++;
characters[count++]=(char) c;
}
while(pos<total){
c=(int) buf[pos]&0xff;
switch(c>>4){
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
pos++;
characters[count++]=(char) c;
break;
case 12:
case 13:
pos+=2;
if(pos>length)
throw new UTFDataFormatException("bad string");
c2=(int) buf[pos-1];
if((c2&0xC0)!=0x80)
throw new UTFDataFormatException("bad string");
characters[count++]=(char) (((c&0x1F)<<6)|(c2&0x3F));
break;
case 14:
pos+=3;
if(pos>length)
throw new UTFDataFormatException("bad string");
c2=(int) buf[pos-2];
c3=(int) buf[pos-1];
if(((c2&0xC0)!=0x80)||((c3&0xC0)!=0x80))
throw new UTFDataFormatException("bad string");
characters[count++]=(char) (((c&0x0F)<<12)|((c2&0x3F)<<6)|((c3&0x3F)<<0));
break;
default:
throw new UTFDataFormatException("bad string");
}
}
return new String(characters,0,count);
}
}

View File

@ -11,22 +11,20 @@
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UTFDataFormatException;
/**
* Optimized ByteArrayOutputStream
*
* @version $Revision: 1.1.1.1 $
*/
public class StoreByteArrayOutputStream extends ByteArrayOutputStream {
/**
* Creates a new byte array output stream.
*/
public StoreByteArrayOutputStream() {
super(16 * 1024);
}
final class StoreByteArrayOutputStream extends OutputStream implements DataOutput{
private byte buf[];
private int pos;
/**
* Creates a new byte array output stream, with a buffer capacity of the specified size, in bytes.
@ -34,8 +32,18 @@ public class StoreByteArrayOutputStream extends ByteArrayOutputStream {
* @param size the initial size.
* @exception IllegalArgumentException if size is negative.
*/
public StoreByteArrayOutputStream(int size) {
super(size);
public StoreByteArrayOutputStream(int size){
if(size<0){
throw new IllegalArgumentException("Invalid size: "+size);
}
buf=new byte[size];
}
/**
* Creates a new byte array output stream.
*/
public StoreByteArrayOutputStream(){
this(16*1024);
}
/**
@ -43,9 +51,9 @@ public class StoreByteArrayOutputStream extends ByteArrayOutputStream {
*
* @param size
*/
public void restart(int size) {
buf = new byte[size];
count = 0;
public void restart(int size){
buf=new byte[size];
pos=0;
}
/**
@ -53,15 +61,11 @@ public class StoreByteArrayOutputStream extends ByteArrayOutputStream {
*
* @param b the byte to be written.
*/
public void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
System.arraycopy(buf, 0, newbuf, 0, count);
buf = newbuf;
}
buf[count] = (byte) b;
count = newcount;
public void write(int b){
int newcount=pos+1;
ensureEnoughBuffer(newcount);
buf[pos]=(byte) b;
pos=newcount;
}
/**
@ -72,47 +76,155 @@ public class StoreByteArrayOutputStream extends ByteArrayOutputStream {
* @param off the start offset in the data.
* @param len the number of bytes to write.
*/
public void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
else if (len == 0) {
public void write(byte b[],int off,int len){
if(len==0){
return;
}
int newcount = count + len;
if (newcount > buf.length) {
byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];
System.arraycopy(buf, 0, newbuf, 0, count);
buf = newbuf;
}
System.arraycopy(b, off, buf, count, len);
count = newcount;
int newcount=pos+len;
ensureEnoughBuffer(newcount);
System.arraycopy(b,off,buf,pos,len);
pos=newcount;
}
/**
* @return the underlying byte[] buffer
*/
public byte[] getData() {
public byte[] getData(){
return buf;
}
/**
* reset the output stream
*/
public void reset(){
count = 0;
pos=0;
}
/**
* Set the current position for writing
*
* @param offset
*/
public void position(int offset){
if (offset > buf.length) {
byte newbuf[] = new byte[Math.max(buf.length << 1, offset)];
System.arraycopy(buf, 0, newbuf, 0, count);
buf = newbuf;
ensureEnoughBuffer(offset);
pos=offset;
}
public int size(){
return pos;
}
public void writeBoolean(boolean v){
ensureEnoughBuffer(1);
buf[pos++]=(byte) (v?1:0);
}
public void writeByte(int v){
ensureEnoughBuffer(1);
buf[pos++]=(byte) (v>>>0);
}
public void writeShort(int v){
ensureEnoughBuffer(2);
buf[pos++]=(byte) (v>>>8);
buf[pos++]=(byte) (v>>>0);
}
public void writeChar(int v){
ensureEnoughBuffer(2);
buf[pos++]=(byte) (v>>>8);
buf[pos++]=(byte) (v>>>0);
}
public void writeInt(int v){
ensureEnoughBuffer(4);
buf[pos++]=(byte) (v>>>24);
buf[pos++]=(byte) (v>>>16);
buf[pos++]=(byte) (v>>>8);
buf[pos++]=(byte) (v>>>0);
}
public void writeLong(long v){
ensureEnoughBuffer(8);
buf[pos++]=(byte) (v>>>56);
buf[pos++]=(byte) (v>>>48);
buf[pos++]=(byte) (v>>>40);
buf[pos++]=(byte) (v>>>32);
buf[pos++]=(byte) (v>>>24);
buf[pos++]=(byte) (v>>>16);
buf[pos++]=(byte) (v>>>8);
buf[pos++]=(byte) (v>>>0);
}
public void writeFloat(float v) throws IOException{
writeInt(Float.floatToIntBits(v));
}
public void writeDouble(double v) throws IOException{
writeLong(Double.doubleToLongBits(v));
}
public void writeBytes(String s){
int length=s.length();
for(int i=0;i<length;i++){
write((byte) s.charAt(i));
}
}
public void writeChars(String s){
int length=s.length();
for(int i=0;i<length;i++){
int c=s.charAt(i);
write((c>>>8)&0xFF);
write((c>>>0)&0xFF);
}
}
public void writeUTF(String str) throws IOException{
int strlen=str.length();
int encodedsize=0;
int c;
for(int i=0;i<strlen;i++){
c=str.charAt(i);
if((c>=0x0001)&&(c<=0x007F)){
encodedsize++;
}else if(c>0x07FF){
encodedsize+=3;
}else{
encodedsize+=2;
}
}
if(encodedsize>65535)
throw new UTFDataFormatException("encoded string too long: "+encodedsize+" bytes");
ensureEnoughBuffer(encodedsize+2);
writeShort(encodedsize);
int i=0;
for(i=0;i<strlen;i++){
c=str.charAt(i);
if(!((c>=0x0001)&&(c<=0x007F)))
break;
buf[pos++]=(byte) c;
}
for(;i<strlen;i++){
c=str.charAt(i);
if((c>=0x0001)&&(c<=0x007F)){
buf[pos++]=(byte) c;
}else if(c>0x07FF){
buf[pos++]=(byte) (0xE0|((c>>12)&0x0F));
buf[pos++]=(byte) (0x80|((c>>6)&0x3F));
buf[pos++]=(byte) (0x80|((c>>0)&0x3F));
}else{
buf[pos++]=(byte) (0xC0|((c>>6)&0x1F));
buf[pos++]=(byte) (0x80|((c>>0)&0x3F));
}
}
}
private void ensureEnoughBuffer(int newcount){
if(newcount>buf.length){
byte newbuf[]=new byte[Math.max(buf.length<<1,newcount)];
System.arraycopy(buf,0,newbuf,0,pos);
buf=newbuf;
}
count = offset;
}
}

View File

@ -0,0 +1,50 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.apache.activemq.kaha.Marshaller;
/**
* Optimized Store reader
*
* @version $Revision: 1.1.1.1 $
*/
final class StoreDataReader{
private DataManager dataManager;
private StoreByteArrayInputStream dataIn;
private byte[] header=new byte[DataItem.HEAD_SIZE];
/**
* Construct a Store reader
*
* @param file
*/
StoreDataReader(DataManager fileManager){
this.dataManager=fileManager;
this.dataIn=new StoreByteArrayInputStream();
}
protected Object readItem(Marshaller marshaller,DataItem item) throws IOException{
RandomAccessFile file=dataManager.getDataFile(item);
file.seek(item.getOffset());
file.readFully(header);
dataIn.restart(header);
item.readHeader(dataIn);
byte[] data=new byte[item.getSize()];
file.readFully(data);
dataIn.restart(data);
return marshaller.readPayload(dataIn);
}
}

View File

@ -0,0 +1,59 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
/**
* Optimized writes to a RandomAcessFile
*
* @version $Revision: 1.1.1.1 $
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import org.apache.activemq.kaha.Marshaller;
/**
* Optimized Store writer
*
* @version $Revision: 1.1.1.1 $
*/
final class StoreDataWriter{
private StoreByteArrayOutputStream dataOut;
private DataManager dataManager;
/**
* Construct a Store writer
*
* @param file
*/
StoreDataWriter(DataManager fileManager){
this.dataManager=fileManager;
this.dataOut=new StoreByteArrayOutputStream();
}
DataItem storeItem(Marshaller marshaller,Object payload) throws IOException{
dataOut.reset();
dataOut.position(DataItem.HEAD_SIZE);
marshaller.writePayload(payload,dataOut);
int size=dataOut.size();
int payloadSize=size-DataItem.HEAD_SIZE;
DataItem item=new DataItem();
item.setSize(payloadSize);
DataFile dataFile=dataManager.findSpaceForData(item);
dataOut.reset();
item.writeHeader(dataOut);
dataFile.getRandomAccessFile().seek(item.getOffset());
dataFile.getRandomAccessFile().write(dataOut.getData(),0,size);
dataFile.incrementLength(size);
dataManager.addInterestInFile(dataFile);
return item;
}
}

View File

@ -1,384 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.apache.activemq.kaha.ListContainer;
import org.apache.activemq.kaha.MapContainer;
import org.apache.activemq.kaha.Marshaller;
import org.apache.activemq.kaha.RuntimeStoreException;
import org.apache.activemq.kaha.Store;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
/**
* Implementation of a Store
*
* @version $Revision: 1.2 $
*/
public class StoreImpl implements Store{
private static final Log log = LogFactory.getLog(StoreImpl.class);
private final Object mutex=new Object();
private RandomAccessFile dataFile;
private Map mapContainers=new ConcurrentHashMap();
private Map listContainers=new ConcurrentHashMap();
private RootContainer rootMapContainer;
private RootContainer rootListContainer;
private String name;
private StoreReader reader;
private StoreWriter writer;
private FreeSpaceManager freeSpaceManager;
protected boolean closed=false;
protected Thread shutdownHook;
public StoreImpl(String name,String mode) throws IOException{
this.name=name;
this.dataFile=new RandomAccessFile(name,mode);
this.reader = new StoreReader(this.dataFile);
this.writer = new StoreWriter(this.dataFile);
File file = new File(name);
log.info("Kaha Store opened " + file.getAbsolutePath());
freeSpaceManager=new FreeSpaceManager(this.writer,this.reader);
initialization();
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#close()
*/
public void close() {
synchronized(mutex){
if(!closed){
try {
for(Iterator i=mapContainers.values().iterator();i.hasNext();){
MapContainerImpl container=(MapContainerImpl) i.next();
container.close();
}
for(Iterator i=listContainers.values().iterator();i.hasNext();){
ListContainerImpl container=(ListContainerImpl) i.next();
container.close();
}
force();
dataFile.close();
closed=true;
}catch(IOException e){
log.debug("Failed to close the store cleanly",e);
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#force()
*/
public void force() throws IOException{
checkClosed();
synchronized(mutex){
dataFile.getFD().sync();
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#clear()
*/
public void clear(){
checkClosed();
for(Iterator i=mapContainers.values().iterator();i.hasNext();){
MapContainer container=(MapContainer) i.next();
container.clear();
}
for(Iterator i=listContainers.values().iterator();i.hasNext();){
ListContainer container=(ListContainer) i.next();
container.clear();
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#delete()
*/
public boolean delete() throws IOException{
checkClosed();
dataFile.close();
File file=new File(name);
return file.delete();
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#doesMapContainerExist(java.lang.Object)
*/
public boolean doesMapContainerExist(Object id){
return mapContainers.containsKey(id);
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#getContainer(java.lang.Object)
*/
public MapContainer getMapContainer(Object id) throws IOException{
checkClosed();
synchronized(mutex){
MapContainer result=(MapContainerImpl) mapContainers.get(id);
if(result==null){
LocatableItem root=new LocatableItem();
rootMapContainer.addRoot(id,root);
result=new MapContainerImpl(id,this,root);
mapContainers.put(id,result);
}
return result;
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#deleteContainer(java.lang.Object)
*/
public void deleteMapContainer(Object id) throws IOException{
checkClosed();
synchronized(mutex){
if(doesMapContainerExist(id)){
MapContainer container=getMapContainer(id);
if(container!=null){
container.load();
container.clear();
rootMapContainer.remove(id);
mapContainers.remove(id);
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#getContainerKeys()
*/
public Set getMapContainerIds(){
checkClosed();
return java.util.Collections.unmodifiableSet(mapContainers.keySet());
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#doesListContainerExist(java.lang.Object)
*/
public boolean doesListContainerExist(Object id){
return listContainers.containsKey(id);
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#getListContainer(java.lang.Object)
*/
public ListContainer getListContainer(Object id) throws IOException{
checkClosed();
synchronized(mutex){
ListContainer result=(ListContainerImpl) listContainers.get(id);
if(result==null){
LocatableItem root=new LocatableItem();
rootListContainer.addRoot(id,root);
result=new ListContainerImpl(id,this,root);
listContainers.put(id,result);
}
return result;
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#deleteListContainer(java.lang.Object)
*/
public void deleteListContainer(Object id) throws IOException{
checkClosed();
synchronized(mutex){
if(doesListContainerExist(id)){
ListContainer container=getListContainer(id);
if(container!=null){
container.load();
container.clear();
rootListContainer.remove(id);
listContainers.remove(id);
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.apache.activemq.kaha.Store#getListContainerIds()
*/
public Set getListContainerIds(){
checkClosed();
return java.util.Collections.unmodifiableSet(listContainers.keySet());
}
public void dumpFreeSpace(PrintWriter printer){
checkClosed();
synchronized(mutex){
freeSpaceManager.dump(printer);
}
}
protected long storeItem(Marshaller marshaller,Object payload,Item item) throws IOException{
synchronized(mutex){
int payloadSize = writer.loadPayload(marshaller, payload, item);
item.setSize(payloadSize);
// free space manager will set offset and write any headers required
// so the position should now be correct for writing
item=freeSpaceManager.getFreeSpace(item);
writer.storeItem(item,payloadSize);
}
return item.getOffset();
}
protected Object readItem(Marshaller marshaller,Item item) throws IOException{
synchronized(mutex){
return reader.readItem(marshaller, item);
}
}
protected void readHeader(Item item) throws IOException{
synchronized(mutex){
reader.readHeader(item);
}
}
protected void readLocation(Item item) throws IOException{
synchronized(mutex){
reader.readLocation(item);
}
}
protected void updateItem(Item item) throws IOException{
synchronized(mutex){
writer.updatePayload(item);
}
}
protected void removeItem(Item item) throws IOException{
synchronized(mutex){
freeSpaceManager.addFreeSpace(item);
}
}
private void initialization() throws IOException{
//add shutdown hook
addShutdownHook();
// check for new file
LocatableItem mapRoot=new LocatableItem();
LocatableItem listRoot=new LocatableItem();
if(dataFile.length()==0){
writer.allocateSpace(FreeSpaceManager.RESIZE_INCREMENT);
storeItem(RootContainer.rootMarshaller,"mapRoot",mapRoot);
storeItem(RootContainer.rootMarshaller,"listRoot",listRoot);
}else{
freeSpaceManager.scanStoredItems();
dataFile.seek(FreeSpaceManager.ROOT_SIZE);
mapRoot.setOffset(FreeSpaceManager.ROOT_SIZE);
readItem(RootContainer.rootMarshaller,mapRoot);
listRoot.setOffset(dataFile.getFilePointer());
readItem(RootContainer.rootMarshaller,listRoot);
}
rootMapContainer=new RootContainer("root",this,mapRoot);
rootMapContainer.load();
Set keys=rootMapContainer.keySet();
for(Iterator i=keys.iterator();i.hasNext();){
Object id=i.next();
if(id!=null){
LocatableItem item=(LocatableItem) rootMapContainer.get(id);
if(item!=null){
MapContainer container=new MapContainerImpl(id,this,item);
mapContainers.put(id,container);
}
}
}
rootListContainer=new RootContainer("root",this,listRoot);
rootListContainer.load();
keys=rootListContainer.keySet();
for(Iterator i=keys.iterator();i.hasNext();){
Object id=i.next();
if(id!=null){
LocatableItem item=(LocatableItem) rootListContainer.get(id);
if(item!=null){
ListContainer container=new ListContainerImpl(id,this,item);
listContainers.put(id,container);
}
}
}
}
protected void checkClosed(){
if(closed){
throw new RuntimeStoreException("The store is closed");
}
}
protected void addShutdownHook() {
shutdownHook = new Thread("Kaha Store implementation is shutting down") {
public void run() {
if (!closed){
try{
//this needs to be really quick so ...
closed = true;
dataFile.close();
}catch(Throwable e){
log.error("Failed to close data file",e);
}
}
}
};
Runtime.getRuntime().addShutdownHook(shutdownHook);
}
protected void removeShutdownHook() {
if (shutdownHook != null) {
try {
Runtime.getRuntime().removeShutdownHook(shutdownHook);
}
catch (Exception e) {
log.warn("Failed to run shutdown hook",e);
}
}
}
}

View File

@ -0,0 +1,47 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* Optimized Store reader
*
* @version $Revision: 1.1.1.1 $
*/
class StoreIndexReader{
protected RandomAccessFile file;
protected StoreByteArrayInputStream dataIn;
protected byte[] buffer=new byte[IndexItem.INDEX_SIZE];
/**
* Construct a Store reader
*
* @param file
*/
StoreIndexReader(RandomAccessFile file){
this.file=file;
this.dataIn=new StoreByteArrayInputStream();
}
protected IndexItem readItem(long offset) throws IOException{
file.seek(offset);
file.readFully(buffer);
dataIn.restart(buffer);
IndexItem result=new IndexItem();
result.setOffset(offset);
result.read(dataIn);
return result;
}
}

View File

@ -0,0 +1,48 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
/**
* Optimized writes to a RandomAcessFile
*
* @version $Revision: 1.1.1.1 $
*/
package org.apache.activemq.kaha.impl;
import java.io.IOException;
import java.io.RandomAccessFile;
/**
* Optimized Store writer
*
* @version $Revision: 1.1.1.1 $
*/
class StoreIndexWriter{
protected StoreByteArrayOutputStream dataOut;
protected RandomAccessFile file;
/**
* Construct a Store index writer
*
* @param file
*/
StoreIndexWriter(RandomAccessFile file){
this.file=file;
this.dataOut=new StoreByteArrayOutputStream();
}
void storeItem(IndexItem index) throws IOException{
dataOut.reset();
index.write(dataOut);
file.seek(index.getOffset());
file.write(dataOut.getData(),0,IndexItem.INDEX_SIZE);
}
}

View File

@ -1,75 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.apache.activemq.kaha.Marshaller;
/**
* Optimized Store reader
*
* @version $Revision: 1.1.1.1 $
*/
class StoreReader{
protected RandomAccessFile dataFile;
protected StoreByteArrayInputStream bytesIn;
protected DataInputStream dataIn;
/**
* Construct a Store reader
*
* @param file
*/
StoreReader(RandomAccessFile file){
this.dataFile=file;
this.bytesIn=new StoreByteArrayInputStream();
this.dataIn=new DataInputStream(bytesIn);
}
protected void readHeader(Item item) throws IOException{
dataFile.seek(item.getOffset());
bytesIn.restart(Item.HEAD_SIZE);
dataFile.readFully(bytesIn.getRawData(),0,Item.HEAD_SIZE);
item.readHeader(dataIn);
}
protected void readLocation(Item item) throws IOException{
readHeader(item);
bytesIn.restart(Item.LOCATION_SIZE);
dataFile.readFully(bytesIn.getRawData(),0,Item.LOCATION_SIZE);
item.readLocation(dataIn);
}
protected Object readItem(Marshaller marshaller,Item item) throws IOException{
readHeader(item);
byte[] data=new byte[item.getSize()];
dataFile.readFully(data);
bytesIn.restart(data);
return item.readPayload(marshaller,dataIn);
}
long length() throws IOException{
return dataFile.length();
}
long position() throws IOException{
return dataFile.getFilePointer();
}
void position(long newPosition) throws IOException{
dataFile.seek(newPosition);
}
}

View File

@ -1,119 +0,0 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
/**
* Optimized writes to a RandomAcessFile
*
* @version $Revision: 1.1.1.1 $
*/
package org.apache.activemq.kaha.impl;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import org.apache.activemq.kaha.Marshaller;
/**
* Optimized Store writer
*
* @version $Revision: 1.1.1.1 $
*/
class StoreWriter{
protected RandomAccessFile dataFile;
protected StoreByteArrayOutputStream bytesOut;
protected DataOutputStream dataOut;
/**
* Construct a Store writer
* @param file
*/
StoreWriter(RandomAccessFile file){
this.dataFile = file;
this.bytesOut = new StoreByteArrayOutputStream();
this.dataOut = new DataOutputStream(bytesOut);
}
void updateHeader(Item item) throws IOException{
bytesOut.reset();
item.writeHeader(dataOut);
dataFile.seek(item.getOffset());
dataFile.write(bytesOut.getData(),0,bytesOut.size());
}
void updatePayload(Item item) throws IOException{
bytesOut.reset();
dataFile.seek(item.getOffset() + Item.HEAD_SIZE);
item.writeLocation(dataOut);
dataFile.write(bytesOut.getData(),0,bytesOut.size());
}
int loadPayload(Marshaller marshaller, Object payload,Item item) throws IOException{
bytesOut.reset();
bytesOut.position(Item.HEAD_SIZE);
item.writePayload(marshaller, payload, dataOut);
return bytesOut.size() - Item.HEAD_SIZE;
}
void storeItem(Item item,int payloadSize) throws IOException{
bytesOut.reset();
item.writeHeader(dataOut);
dataFile.seek(item.getOffset());
dataFile.write(bytesOut.getData(),0,payloadSize+Item.HEAD_SIZE);
}
void writeShort(long offset, int value) throws IOException{
bytesOut.reset();
dataFile.seek(offset);
dataOut.writeShort(value);
dataFile.write(bytesOut.getData(),0,bytesOut.size());
}
void writeInt(long offset,int value) throws IOException{
bytesOut.reset();
dataFile.seek(offset);
dataOut.writeInt(value);
dataFile.write(bytesOut.getData(),0,bytesOut.size());
}
void writeLong(long offset,long value) throws IOException{
bytesOut.reset();
dataFile.seek(offset);
dataOut.writeLong(value);
dataFile.write(bytesOut.getData(),0,bytesOut.size());
}
long length() throws IOException{
return dataFile.length();
}
long position() throws IOException{
return dataFile.getFilePointer();
}
void position(long newPosition) throws IOException{
dataFile.seek(newPosition);
}
void allocateSpace(long newLength) throws IOException{
dataFile.getFD().sync();
long currentOffset=dataFile.getFilePointer();
dataFile.seek(newLength);
dataFile.write(0);
dataFile.seek(currentOffset);
dataFile.getFD().sync();
}
}

View File

@ -18,8 +18,8 @@
package org.apache.activemq.store.kahadaptor;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.activemq.kaha.Marshaller;
import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
@ -32,13 +32,13 @@ import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicInteger;
public class AtomicIntegerMarshaller implements Marshaller{
public void writePayload(Object object,DataOutputStream dataOut) throws IOException{
public void writePayload(Object object,DataOutput dataOut) throws IOException{
AtomicInteger ai = (AtomicInteger) object;
dataOut.writeInt(ai.get());
}
public Object readPayload(DataInputStream dataIn) throws IOException{
public Object readPayload(DataInput dataIn) throws IOException{
int value = dataIn.readInt();
return new AtomicInteger(value);
}

View File

@ -17,10 +17,9 @@
package org.apache.activemq.store.kahadaptor;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.activeio.command.WireFormat;
import org.apache.activeio.packet.ByteArrayPacket;
import org.apache.activeio.packet.Packet;
@ -38,7 +37,7 @@ public class CommandMarshaller implements Marshaller{
}
public void writePayload(Object object,DataOutputStream dataOut) throws IOException{
public void writePayload(Object object,DataOutput dataOut) throws IOException{
Packet packet = wireFormat.marshal(object);
byte[] data = packet.sliceAsBytes();
dataOut.writeInt(data.length);
@ -46,7 +45,7 @@ public class CommandMarshaller implements Marshaller{
}
public Object readPayload(DataInputStream dataIn) throws IOException{
public Object readPayload(DataInput dataIn) throws IOException{
int size=dataIn.readInt();
byte[] data=new byte[size];
dataIn.readFully(data);

View File

@ -18,7 +18,6 @@ import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.activeio.command.WireFormat;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ActiveMQQueue;
@ -33,6 +32,8 @@ import org.apache.activemq.store.MessageStore;
import org.apache.activemq.store.PersistenceAdapter;
import org.apache.activemq.store.TopicMessageStore;
import org.apache.activemq.store.TransactionStore;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
/**
* @org.apache.xbean.XBean
@ -40,6 +41,7 @@ import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
* @version $Revision: 1.4 $
*/
public class KahaPersistentAdaptor implements PersistenceAdapter{
private static final Log log=LogFactory.getLog(KahaPersistentAdaptor.class);
static final String PREPARED_TRANSACTIONS_NAME="PreparedTransactions";
KahaTransactionStore transactionStore;
ConcurrentHashMap topics=new ConcurrentHashMap();
@ -58,13 +60,18 @@ public class KahaPersistentAdaptor implements PersistenceAdapter{
}
public Set getDestinations(){
Set rc=new HashSet();
try {
for(Iterator i=store.getMapContainerIds().iterator();i.hasNext();){
Object obj=i.next();
if(obj instanceof ActiveMQDestination){
rc.add(obj);
}
}
}catch(IOException e){
log.error("Failed to get destinations " ,e);
}
return rc;
}
@ -89,7 +96,6 @@ public class KahaPersistentAdaptor implements PersistenceAdapter{
MapContainer ackContainer=store.getMapContainer(destination.toString()+"-Acks");
ackContainer.setKeyMarshaller(new StringMarshaller());
ackContainer.setValueMarshaller(new AtomicIntegerMarshaller());
ackContainer.load();
rc=new KahaTopicMessageStore(store,messageContainer,ackContainer,subsContainer,destination);
messageStores.put(destination, rc);
if(transactionStore!=null){
@ -137,10 +143,7 @@ public class KahaPersistentAdaptor implements PersistenceAdapter{
public void deleteAllMessages() throws IOException{
if(store!=null){
store.clear();
}
if(transactionStore!=null){
transactionStore.delete();
store.delete();
}
}

View File

@ -23,6 +23,7 @@ import org.apache.activemq.command.MessageId;
import org.apache.activemq.command.SubscriptionInfo;
import org.apache.activemq.kaha.ListContainer;
import org.apache.activemq.kaha.MapContainer;
import org.apache.activemq.kaha.Marshaller;
import org.apache.activemq.kaha.Store;
import org.apache.activemq.kaha.StringMarshaller;
import org.apache.activemq.store.MessageRecoveryListener;
@ -71,7 +72,8 @@ public class KahaTopicMessageStore extends KahaMessageStore implements TopicMess
String id=messageId.toString();
ListContainer container=(ListContainer) subscriberAcks.get(subcriberId);
if(container!=null){
container.remove(id);
//container.remove(id);
container.removeFirst();
AtomicInteger count=(AtomicInteger) ackContainer.remove(id);
if(count!=null){
if(count.decrementAndGet()>0){
@ -96,7 +98,11 @@ public class KahaTopicMessageStore extends KahaMessageStore implements TopicMess
info.setSelector(selector);
info.setSubcriptionName(subscriptionName);
String key=getSubscriptionKey(clientId,subscriptionName);
subscriberContainer.put(key,info);
// if already exists - won't add it again as it causes data files
// to hang around
if(!subscriberContainer.containsKey(key)){
subscriberContainer.put(key,info);
}
addSubscriberAckContainer(key);
}
@ -122,15 +128,19 @@ public class KahaTopicMessageStore extends KahaMessageStore implements TopicMess
throws Exception{
String key=getSubscriptionKey(clientId,subscriptionName);
ListContainer list=(ListContainer) subscriberAcks.get(key);
for(Iterator i=list.iterator();i.hasNext();){
Object msg=messageContainer.get(i.next());
if(msg!=null){
if(msg.getClass()==String.class){
listener.recoverMessageReference((String) msg);
}else{
listener.recoverMessage((Message) msg);
if(list!=null){
for(Iterator i=list.iterator();i.hasNext();){
Object msg=messageContainer.get(i.next());
if(msg!=null){
if(msg.getClass()==String.class){
listener.recoverMessageReference((String) msg);
}else{
listener.recoverMessage((Message) msg);
}
}
listener.finished();
}
}else{
listener.finished();
}
}
@ -154,8 +164,8 @@ public class KahaTopicMessageStore extends KahaMessageStore implements TopicMess
protected void addSubscriberAckContainer(Object key) throws IOException{
ListContainer container=store.getListContainer(key);
container.setMarshaller(new StringMarshaller());
container.load();
Marshaller marshaller=new StringMarshaller();
container.setMarshaller(marshaller);
subscriberAcks.put(key,container);
}
}

View File

@ -17,12 +17,11 @@
package org.apache.activemq.store.kahadaptor;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.activeio.command.WireFormat;
import org.apache.activeio.packet.ByteArrayPacket;
import org.apache.activeio.packet.Packet;
@ -41,7 +40,7 @@ public class TransactionMarshaller implements Marshaller{
}
public void writePayload(Object object,DataOutputStream dataOut) throws IOException{
public void writePayload(Object object,DataOutput dataOut) throws IOException{
KahaTransaction kt = (KahaTransaction) object;
List list = kt.getList();
dataOut.writeInt(list.size());
@ -62,7 +61,7 @@ public class TransactionMarshaller implements Marshaller{
}
public Object readPayload(DataInputStream dataIn) throws IOException{
public Object readPayload(DataInput dataIn) throws IOException{
KahaTransaction result = new KahaTransaction();
List list = new ArrayList();
result.setList(list);

View File

@ -16,7 +16,7 @@ package org.apache.activemq.kaha;
import java.io.IOException;
import java.io.PrintWriter;
import junit.framework.TestCase;
import org.apache.activemq.kaha.impl.StoreImpl;
import org.apache.activemq.kaha.impl.KahaStore;
import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
/**
* Store test
@ -27,7 +27,7 @@ public class LoadTest extends TestCase{
static final int COUNT=10000;
static final int NUM_LOADERS=2;
protected String name="load.db";
protected StoreImpl store;
protected KahaStore store;
/*
* Test method for 'org.apache.activemq.kaha.Store.close()'
@ -40,11 +40,10 @@ public class LoadTest extends TestCase{
loader.start();
}
stop.await();
store.dumpFreeSpace(new PrintWriter(System.out));
}
protected StoreImpl getStore() throws IOException{
return (StoreImpl) StoreFactory.open(name,"rw");
protected KahaStore getStore() throws IOException{
return (KahaStore) StoreFactory.open(name,"rw");
}
protected void setUp() throws Exception{

View File

@ -21,7 +21,6 @@ import org.apache.activemq.kaha.MapContainer;
import org.apache.activemq.kaha.Marshaller;
import org.apache.activemq.kaha.Store;
import org.apache.activemq.kaha.StringMarshaller;
import org.apache.activemq.kaha.impl.StoreImpl;
import edu.emory.mathcs.backport.java.util.concurrent.CountDownLatch;
import junit.framework.TestCase;
/**

View File

@ -0,0 +1,261 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.kaha.impl;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
/**
* @version $Revision: 1.2 $
*/
public class IndexLinkedListTest extends TestCase{
static final int NUMBER = 10;
private IndexItem root;
private List testData = new ArrayList();
private IndexLinkedList list;
protected void setUp() throws Exception{
super.setUp();
for (int i =0; i < NUMBER; i++){
testData.add(new IndexItem());
}
root = new IndexItem();
list = new IndexLinkedList(root);
}
protected void tearDown() throws Exception{
super.tearDown();
testData.clear();
list = null;
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.getFirst()'
*/
public void testGetFirst(){
for (int i =0; i < testData.size(); i++){
list.add((IndexItem) testData.get(i));
}
assertTrue(list.getFirst()==testData.get(0));
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.getLast()'
*/
public void testGetLast(){
for (int i =0; i < testData.size(); i++){
list.add((IndexItem) testData.get(i));
}
assertTrue(list.getLast()==testData.get(testData.size()-1));
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.removeFirst()'
*/
public void testRemoveFirst(){
for (int i =0; i < testData.size(); i++){
list.add((IndexItem) testData.get(i));
}
assertTrue(list.removeFirst()==testData.get(0));
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.removeLast()'
*/
public void testRemoveLast(){
for (int i =0; i < testData.size(); i++){
list.add((IndexItem) testData.get(i));
}
assertTrue(list.removeLast()==testData.get(testData.size()-1));
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.addFirst(IndexItem)'
*/
public void testAddFirst(){
for (int i =0; i < testData.size(); i++){
list.addFirst((IndexItem) testData.get(i));
}
int count = 0;
for (int i =testData.size()-1; i>=0; i--){
assertTrue(testData.get(i)==list.get(count++));
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.addLast(IndexItem)'
*/
public void testAddLast(){
for (int i =0; i < testData.size(); i++){
list.addLast((IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
assertTrue(testData.get(i)==list.get(i));
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.size()'
*/
public void testSize(){
for (int i =0; i < testData.size(); i++){
list.addLast((IndexItem) testData.get(i));
assertTrue(list.size()==i+1);
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.isEmpty()'
*/
public void testIsEmpty(){
for (int i =0; i < testData.size(); i++){
list.addLast((IndexItem) testData.get(i));
assertTrue(list.size()==i+1);
}
list.clear();
assertTrue(list.isEmpty());
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.add(IndexItem)'
*/
public void testAddIndexItem(){
for (int i =0; i < testData.size(); i++){
list.add((IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
assertTrue(testData.get(i)==list.get(i));
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.clear()'
*/
public void testClear(){
for (int i =0; i < testData.size(); i++){
list.addLast((IndexItem) testData.get(i));
assertTrue(list.size()==i+1);
}
list.clear();
assertTrue(list.isEmpty());
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.add(int, IndexItem)'
*/
public void testAddIntIndexItem(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
assertTrue(testData.get(i)==list.get(i));
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.remove(int)'
*/
public void testRemoveInt(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
list.remove(0);
}
assertTrue(list.isEmpty());
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
list.remove(list.size()-1);
}
assertTrue(list.isEmpty());
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.indexOf(IndexItem)'
*/
public void testIndexOf(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
assertTrue(list.indexOf((IndexItem) testData.get(i))==i);
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.getNextEntry(IndexItem)'
*/
public void testGetNextEntry(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
IndexItem next = list.getFirst();
int count = 0;
while (next != null){
assertTrue(next==testData.get(count++));
next = list.getNextEntry(next);
assertTrue(next != root);
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.getPrevEntry(IndexItem)'
*/
public void testGetPrevEntry(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
IndexItem next = list.getLast();
int count = testData.size()-1;
while (next != null){
assertTrue(next==testData.get(count--));
next = list.getPrevEntry(next);
assertTrue(next != root);
}
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.addBefore(IndexItem, IndexItem)'
*/
public void testAddBefore(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
IndexItem test = new IndexItem();
list.addBefore(test, list.getFirst());
assertTrue(list.size()==testData.size()+1);
assertTrue(list.getFirst()==test);
}
/*
* Test method for 'org.apache.activemq.kaha.impl.IndexLinkedList.remove(IndexItem)'
*/
public void testRemoveIndexItem(){
for (int i =0; i < testData.size(); i++){
list.add(i,(IndexItem) testData.get(i));
}
for (int i =0; i < testData.size(); i++){
list.remove((IndexItem)testData.get(i));
assertTrue(list.size()==testData.size()-i-1);
}
}
}

View File

@ -16,21 +16,15 @@
*/
package org.apache.activemq.perf;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import org.apache.activemq.ActiveMQConnectionFactory;
import java.io.File;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.xbean.BrokerFactoryBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.apache.activemq.store.kahadaptor.KahaPersistentAdaptor;
/**
* @version $Revision: 1.3 $
*/
public class KahaDurableTopicTest extends SimpleDurableTopicTest {
/*
protected BrokerService createBroker() throws Exception{
Resource resource=new ClassPathResource( "org/apache/activemq/perf/kahaBroker.xml");
BrokerFactoryBean factory=new BrokerFactoryBean(resource);
@ -39,6 +33,14 @@ public class KahaDurableTopicTest extends SimpleDurableTopicTest {
result.start();
return result;
}
*/
protected void configureBroker(BrokerService answer) throws Exception{
KahaPersistentAdaptor adaptor = new KahaPersistentAdaptor(new File("activemq-data/perfTest"));
answer.setPersistenceAdapter(adaptor);
answer.addConnector(bindAddress);
answer.setDeleteAllMessagesOnStartup(true);
}

View File

@ -0,0 +1,38 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.perf;
import java.io.File;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
import org.apache.activemq.broker.BrokerService;
import org.apache.activemq.store.kahadaptor.KahaPersistentAdaptor;
/**
* @version $Revision: 1.3 $
*/
public class KahaQueueTest extends SimpleQueueTest{
protected void configureBroker(BrokerService answer) throws Exception{
KahaPersistentAdaptor adaptor = new KahaPersistentAdaptor(new File("activemq-data/perfTest"));
answer.setPersistenceAdapter(adaptor);
answer.addConnector(bindAddress);
answer.setDeleteAllMessagesOnStartup(true);
}
}

View File

@ -0,0 +1,103 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.perf;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TemporaryQueue;
import javax.jms.TemporaryTopic;
import junit.framework.TestCase;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.broker.BrokerService;
/**
* @version $Revision: 1.3 $
*/
public class MemoryAllocationTest extends TestCase{
protected static final int MESSAGE_COUNT=2000;
protected BrokerService broker;
protected String bindAddress="vm://localhost";
protected int topicCount=0;
public void testPerformance() throws Exception{
ConnectionFactory factory=createConnectionFactory();
Connection connection=factory.createConnection();
for(int i=0;i<MESSAGE_COUNT;i++){
Session session=connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination dest=session.createTemporaryTopic();
MessageConsumer mc=session.createConsumer(dest);
MessageProducer mp=session.createProducer(dest);
Message msg=session.createTextMessage("test"+i);
mp.send(msg);
session.close();
releaseDestination(dest);
if (i%500==0)System.out.println("Iterator "+i);
}
connection.close();
}
protected Destination getDestination(Session session) throws JMSException{
String topicName=getClass().getName()+"."+topicCount++;
return session.createTopic(topicName);
}
protected void releaseDestination(Destination dest) throws JMSException{
if(dest instanceof TemporaryTopic){
TemporaryTopic tt=(TemporaryTopic) dest;
tt.delete();
}else if(dest instanceof TemporaryQueue){
TemporaryQueue tq=(TemporaryQueue) dest;
tq.delete();
}
}
protected void setUp() throws Exception{
if(broker==null){
broker=createBroker();
}
super.setUp();
}
protected void tearDown() throws Exception{
super.tearDown();
if(broker!=null){
broker.stop();
}
}
protected ActiveMQConnectionFactory createConnectionFactory() throws Exception{
ActiveMQConnectionFactory cf=new ActiveMQConnectionFactory(bindAddress);
return cf;
}
protected BrokerService createBroker() throws Exception{
BrokerService answer=new BrokerService();
configureBroker(answer);
answer.start();
return answer;
}
protected void configureBroker(BrokerService answer) throws Exception{
answer.setPersistent(false);
answer.addConnector(bindAddress);
answer.setDeleteAllMessagesOnStartup(true);
}
}

View File

@ -34,7 +34,10 @@ import org.apache.commons.logging.LogFactory;
public class SimpleTopicTest extends TestCase{
private static final Log log=LogFactory.getLog(SimpleTopicTest.class);
protected BrokerService broker;
protected String bindAddress="tcp://localhost:61616";
protected String bindAddress="tcp://localhost:61616?wireFormat.cacheEnabled=true&wireFormat.tightEncodingEnabled=true";
//protected String bindAddress="tcp://localhost:61616?wireFormat.cacheEnabled=true&wireFormat.tightEncodingEnabled=false";
//protected String bindAddress="vm://localhost?marshal=true";
//protected String bindAddress="vm://localhost";
protected PerfProducer[] producers;
protected PerfConsumer[] consumers;
protected String DESTINATION_NAME=getClass().toString();
@ -42,7 +45,7 @@ public class SimpleTopicTest extends TestCase{
protected int NUMBER_OF_PRODUCERS=1;
protected BytesMessage payload;
protected int PAYLOAD_SIZE=1024;
protected int MESSAGE_COUNT=1000000;
protected int MESSAGE_COUNT=100000;
protected byte[] array=null;
protected ConnectionFactory factory;
protected Destination destination;
@ -121,6 +124,7 @@ public class SimpleTopicTest extends TestCase{
protected void configureBroker(BrokerService answer) throws Exception{
answer.addConnector(bindAddress);
answer.setDeleteAllMessagesOnStartup(true);
}
protected ActiveMQConnectionFactory createConnectionFactory() throws Exception{
@ -133,7 +137,7 @@ public class SimpleTopicTest extends TestCase{
public void testPerformance() throws JMSException{
for(int i=0;i<MESSAGE_COUNT;i++){
if(i%5000==0){
if(i%10000==0){
dumpProducerRate();
dumpConsumerRate();
}

View File

@ -0,0 +1,31 @@
/**
*
* Copyright 2005-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package org.apache.activemq.perf;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Session;
/**
* @version $Revision: 1.3 $
*/
public class TemporaryTopicMemoryAllocationTest extends MemoryAllocationTest{
public TemporaryTopicMemoryAllocationTest(){
super();
// TODO Auto-generated constructor stub
}
protected Destination getDestination(Session session) throws JMSException{
return session.createTemporaryTopic();
}
}