mirror of https://github.com/apache/activemq.git
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:
parent
5574d2ad35
commit
6575f2d22d
|
@ -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);
|
||||
|
|
|
@ -99,6 +99,6 @@ public interface ListContainer extends List{
|
|||
* @return true if successful
|
||||
*/
|
||||
public boolean doRemove(int position);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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&¤tWriteFile.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"));
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 < 0 || index >= 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 < 0 || index > 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 < 0 || index >= 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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;
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue