Reformated the code, adding the missing ASL 2.0 headers
git-svn-id: https://svn.apache.org/repos/asf/directory/apacheds/branches/apacheds-jdbm@1162916 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java
index 3ee24f5..e16e8ad 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java
+++ b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java
@@ -312,7 +312,7 @@
if ( ! allowsDuplicates )
{
return ( V ) bt.find( key );
- }
+ }
DupsContainer<V> values = getDupsContainer( ( byte[] ) bt.find( key ) );
@@ -467,11 +467,13 @@
* be the previous tuple if it exists.
*/
TupleBrowser browser = bt.browse( tuple.getKey() );
+
if ( browser.getPrevious( tuple ) )
{
this.closeBrowser( browser );
return true;
}
+
this.closeBrowser( browser );
}
@@ -566,6 +568,7 @@
{
return;
}
+
if ( set.size() > numDupLimit )
{
BTree tree = convertToBTree( set );
@@ -632,6 +635,7 @@
{
LOG.debug( "<--- Remove NULL key " + name );
}
+
return;
}
@@ -673,6 +677,7 @@
{
bt.insert( key, (V)marshaller.serialize( set ), true );
}
+
count--;
if ( LOG.isDebugEnabled() )
@@ -774,6 +779,7 @@
recMan.delete( tree.getRecordId() );
duplicateBtrees.remove( tree.getRecordId() );
+
return;
}
else
@@ -841,6 +847,7 @@
}
ArrayTree<V> set = marshaller.deserialize( serialized );
+
return new KeyTupleArrayCursor<K,V>( set, key );
}
@@ -866,6 +873,7 @@
}
byte[] serialized = ( byte[] ) raw;
+
if ( BTreeRedirectMarshaller.isRedirect( serialized ) )
{
BTree tree = getBTree( BTreeRedirectMarshaller.INSTANCE.deserialize( serialized ) );
@@ -930,6 +938,7 @@
}
DupsContainer<V> values = getDupsContainer( ( byte[] ) bt.find( key ) );
+
if ( values.isBTreeRedirect() )
{
return true;
@@ -976,6 +985,7 @@
BTree<K, V> tree = new BTree<K, V>().load( recMan, redirect.getRecId() );
((SerializableComparator<K>)tree.getComparator()).setSchemaManager( schemaManager );
duplicateBtrees.put( redirect.getRecId(), tree );
+
return tree;
}
@@ -1014,6 +1024,7 @@
* which is the only chance for returning true.
*/
V firstKey = ( V ) tuple.getKey();
+
return valueComparator.compare( key, firstKey ) == 0;
}
}
@@ -1038,6 +1049,7 @@
}
this.closeBrowser( browser );
+
return avlTree;
}
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java
index b6b805c..35512a8 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java
+++ b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyBTreeCursor.java
@@ -158,6 +158,7 @@
public boolean previous() throws Exception
{
checkNotClosed( "previous()" );
+
if ( browser == null )
{
browser = btree.browse( null );
@@ -178,6 +179,7 @@
public boolean next() throws Exception
{
checkNotClosed( "next()" );
+
if ( browser == null )
{
browser = btree.browse();
@@ -190,6 +192,7 @@
else
{
clearValue();
+
return false;
}
}
@@ -199,6 +202,7 @@
public E get() throws Exception
{
checkNotClosed( "get()" );
+
if ( valueAvailable )
{
return ( E ) tuple.getKey();
@@ -228,6 +232,7 @@
this.closeBrowser( browser );
}
+
private void closeBrowser(TupleBrowser browser)
{
if ( browser != null )
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
index 83c7ebd..f747ad8 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
+++ b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
@@ -334,6 +334,7 @@
super.close( cause );
this.closeBrowser( browser );
}
+
private void closeBrowser(TupleBrowser browser)
{
diff --git a/jdbm/src/main/java/jdbm/ActionRecordManager.java b/jdbm/src/main/java/jdbm/ActionRecordManager.java
index 225197a..1bb5117 100644
--- a/jdbm/src/main/java/jdbm/ActionRecordManager.java
+++ b/jdbm/src/main/java/jdbm/ActionRecordManager.java
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm;
import jdbm.helper.ActionContext;
@@ -12,7 +31,6 @@
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public interface ActionRecordManager extends RecordManager
-
{
/**
* Initializes the context for the action. Implicity sets the
@@ -20,10 +38,11 @@
*
* @param readOnly true if action does not do any modification
* @param whoStarted caller can use this for debugging
- * @return
+ * @return The created action context
*/
ActionContext beginAction( boolean readOnly, String whoStarted );
+
/**
* Ends the action associated with the context.
* ReadWrite actions' changes are made visible
@@ -33,6 +52,7 @@
*/
void endAction( ActionContext context );
+
/**
* Aborts the given action. For write actions, actions's changes
* should not be made visible to readers.
@@ -41,6 +61,7 @@
*/
void abortAction( ActionContext context );
+
/**
* Set the context as the current action context for
* the given thread
@@ -49,6 +70,7 @@
*/
public void setCurrentActionContext( ActionContext context );
+
/**
* Unsets the context as the current action context.
* Given context should be current action context for the
diff --git a/jdbm/src/main/java/jdbm/btree/BPage.java b/jdbm/src/main/java/jdbm/btree/BPage.java
index 3363561..2af8474 100644
--- a/jdbm/src/main/java/jdbm/btree/BPage.java
+++ b/jdbm/src/main/java/jdbm/btree/BPage.java
@@ -47,23 +47,19 @@
package jdbm.btree;
-import jdbm.btree.BTree.EmptyBrowser;
-import jdbm.btree.BTree.MetaRoot;
-import jdbm.helper.LRUCache;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import jdbm.helper.ActionContext;
import jdbm.helper.Serializer;
import jdbm.helper.Tuple;
import jdbm.helper.TupleBrowser;
-import jdbm.helper.ActionContext;
-
-import java.io.IOException;
-import java.io.ByteArrayOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-import java.util.concurrent.atomic.AtomicInteger;
import org.apache.directory.server.i18n.I18n;
@@ -374,6 +370,7 @@
height -= 1;
BPage<K,V> pageNewCopy = null;
+
if ( height == 0 )
{
pageNewCopy = btree.copyOnWrite( this );
@@ -417,6 +414,7 @@
// non-leaf BPage
BPage<K, V> child = childBPage( index );
result = child.insert( height, key, value, replace );
+
if( result.pageNewCopy != null)
{
child = result.pageNewCopy;
@@ -469,6 +467,7 @@
}
btree.recordManager.update( recordId, pageNewCopy, this );
+
return result;
}
@@ -476,7 +475,6 @@
int half = btree.pageSize >> 1;
BPage<K, V> newPage = new BPage<K, V>( btree, pageNewCopy.isLeaf );
-
if ( index < half )
{
// move lower-half of entries to overflow BPage,
@@ -585,7 +583,8 @@
height -= 1;
- BPage<K,V> pageNewCopy = btree.copyOnWrite( this );;
+ BPage<K,V> pageNewCopy = btree.copyOnWrite( this );
+
if ( height == 0 )
{
// remove leaf entry
@@ -1362,6 +1361,7 @@
data = baos.toByteArray();
oos.close();
baos.close();
+
return data;
}
@@ -1605,7 +1605,6 @@
else
{
boolean isFirst = true;
- //int index = 0;
for ( K key : keys )
{
@@ -1620,8 +1619,6 @@
sb.append( "<" );
sb.append( key );
- //sb.append( "/" );
- //sb.append( values[index] );
sb.append( ">" );
}
}
diff --git a/jdbm/src/main/java/jdbm/btree/BTree.java b/jdbm/src/main/java/jdbm/btree/BTree.java
index 2d5ffd0..8c4712b 100644
--- a/jdbm/src/main/java/jdbm/btree/BTree.java
+++ b/jdbm/src/main/java/jdbm/btree/BTree.java
@@ -47,28 +47,27 @@
package jdbm.btree;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.io.Serializable;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
+import java.io.Serializable;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
-import jdbm.RecordManager;
import jdbm.ActionRecordManager;
+import jdbm.RecordManager;
+import jdbm.helper.ActionContext;
import jdbm.helper.Serializer;
import jdbm.helper.Tuple;
import jdbm.helper.TupleBrowser;
import jdbm.helper.WrappedRuntimeException;
-import jdbm.helper.ActionContext;
-
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
import org.apache.directory.server.i18n.I18n;
@@ -286,6 +285,7 @@
BTree<K, V> btree = null;
boolean abortedAction = false;
ActionContext context = this.beginAction( false, "load" );
+
try
{
btree = (BTree<K, V>) recman.fetch( recid );
@@ -305,10 +305,11 @@
finally
{
if ( !abortedAction )
+ {
this.endAction( context );
+ }
}
-
return btree;
}
@@ -343,7 +344,9 @@
if ( !isActionCapable )
+ {
bigLock.lock();
+ }
try
{
@@ -363,13 +366,17 @@
nbEntries.set( 1 );
recordManager.update( recordId, this );
updateMetaRoot( this.rootId, this.bTreeHeight );
+
return null;
}
else
{
BPage.InsertResult<K, V> insert = rootPage.insert( bTreeHeight, key, value, replace );
+
if ( insert.pageNewCopy != null )
+ {
rootPage = insert.pageNewCopy;
+ }
boolean dirty = false;
@@ -412,14 +419,16 @@
finally
{
if ( !abortedAction )
+ {
this.endAction( context );
+ }
if ( !isActionCapable )
+ {
bigLock.unlock();
+ }
}
-
}
-
/**
@@ -441,11 +450,12 @@
ActionContext context = this.beginAction( false, "remove" );
if ( !isActionCapable )
+ {
bigLock.lock();
+ }
try
{
-
BPage<K, V> rootPage = getRoot();
if ( rootPage == null )
@@ -455,8 +465,11 @@
boolean dirty = false;
BPage.RemoveResult<K, V> remove = rootPage.remove( bTreeHeight, key );
+
if ( remove.pageNewCopy != null )
+ {
rootPage = remove.pageNewCopy;
+ }
if ( remove.underflow && rootPage.isEmpty() )
{
@@ -498,12 +511,15 @@
finally
{
if ( !abortedAction )
+ {
this.endAction( context );
+ }
if ( !isActionCapable )
+ {
bigLock.unlock();
+ }
}
-
}
@@ -524,7 +540,9 @@
}
if ( !isActionCapable )
+ {
bigLock.lock();
+ }
try
{
@@ -553,10 +571,14 @@
finally
{
if ( browser != null )
- browser.close();
+ {
+ browser.close();
+ }
if ( !isActionCapable )
+ {
bigLock.unlock();
+ }
}
}
@@ -583,9 +605,12 @@
}
if ( !isActionCapable )
+ {
bigLock.lock();
+ }
tuple = new Tuple<K, V>( null, null );
+
try
{
browser = browse( key );
@@ -603,11 +628,14 @@
finally
{
if ( browser != null )
- browser.close();
+ {
+ browser.close();
+ }
if ( !isActionCapable )
+ {
bigLock.unlock();
-
+ }
}
}
@@ -624,7 +652,8 @@
public TupleBrowser<K, V> browse() throws IOException
{
TupleBrowser<K, V> browser = null;
- ActionContext context = this.beginAction( true, "browse" );
+ ActionContext context = this.beginAction( true, "browse" );
+
try
{
MetaRoot meta = this.getMetaRoot();
@@ -635,7 +664,8 @@
this.endAction( context );
return new EmptyBrowser(){};
}
- browser = rootPage.findFirst( context );
+
+ browser = rootPage.findFirst( context );
}
catch( IOException e )
{
@@ -663,7 +693,8 @@
public TupleBrowser<K, V> browse( K key ) throws IOException
{
TupleBrowser<K, V> browser = null;
- ActionContext context = this.beginAction( true, "browse key" );
+ ActionContext context = this.beginAction( true, "browse key" );
+
try
{
MetaRoot meta = this.getMetaRoot();
@@ -708,7 +739,7 @@
/**
- * Return the root BPage<Object, Object>, or null if it doesn't exist.
+ * @return the root BPage<Object, Object>, or null if it doesn't exist.
*/
BPage<K, V> getRoot( ) throws IOException
{
@@ -726,8 +757,14 @@
return root;
}
+
+ /**
+ * @param meta The root to search for
+ *
+ * @return the root BPage<Object, Object>, or null if it doesn't exist.
+ */
BPage<K, V> getRoot( MetaRoot meta ) throws IOException
- {
+ {
if ( meta.rootID == 0 )
{
return null;
@@ -740,26 +777,27 @@
return root;
}
+
/**
*
* Returns the meta root that can be used to fetch the root page
*
- * @return meta root
- * @throws IOException
+ * @return meta root The meta root to search for
+ * @throws IOException If we had an exception during the fetch operation
*/
MetaRoot getMetaRoot() throws IOException
{
if ( isActionCapable )
+ {
return ( MetaRoot )recordManager.fetch( -this.recordId );
+ }
else
+ {
return metaRoot;
+ }
}
-
-
-
-
/**
* Implement Externalizable interface.
*/
@@ -822,7 +860,6 @@
}
-
void setAsCurrentAction( ActionContext context )
{
if ( context != null )
@@ -832,6 +869,7 @@
}
}
+
void unsetAsCurrentAction( ActionContext context )
{
if ( context != null )
@@ -845,10 +883,12 @@
ActionContext beginAction( boolean readOnly, String whoStarted )
{
ActionContext context = null;
+
if ( isActionCapable )
{
context = ( ( ActionRecordManager )recordManager ).beginAction( readOnly, whoStarted );
}
+
return context;
}
@@ -862,6 +902,7 @@
}
}
+
void abortAction( ActionContext context )
{
if ( context != null )
@@ -879,6 +920,7 @@
}
+
private MetaRoot copyOnWrite( MetaRoot oldMetaRoot )
{
MetaRoot newMetaRoot = new MetaRoot();
@@ -888,6 +930,7 @@
return newMetaRoot;
}
+
private void updateMetaRoot( long newRootId, int newTreeHeight ) throws IOException
{
metaRoot = this.copyOnWrite( metaRoot );
@@ -895,12 +938,14 @@
metaRoot.treeHeight = newTreeHeight;
if ( isActionCapable )
+ {
recordManager.update( -this.recordId, metaRoot );
+ }
}
+
V copyValue( V value) throws IOException
{
-
byte[] array;
V valueCopy = null;
@@ -934,24 +979,32 @@
finally
{
if ( bout != null )
+ {
bout.close();
+ }
if ( out != null )
+ {
out.close();
+ }
if ( bin != null )
+ {
bin.close();
+ }
if ( in != null )
+ {
in.close();
+ }
}
- }
- return valueCopy;
+ }
+
+ return valueCopy;
}
-
public String toString()
{
StringBuilder sb = new StringBuilder();
@@ -1000,7 +1053,7 @@
}
/**
- * Used to poin to the root page that the reader needs based on the reader's
+ * Used to point to the root page that the reader needs based on the reader's
* read action context. ReadWrite actions always use the latest root.
*/
class MetaRoot
diff --git a/jdbm/src/main/java/jdbm/helper/ActionContext.java b/jdbm/src/main/java/jdbm/helper/ActionContext.java
index 6758da3..a59406d 100644
--- a/jdbm/src/main/java/jdbm/helper/ActionContext.java
+++ b/jdbm/src/main/java/jdbm/helper/ActionContext.java
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
/**
@@ -6,56 +25,57 @@
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ActionContext
- {
-
- /** track whether action is read only */
- boolean readOnly;
-
- /** Version associated with the context */
- ActionVersioning.Version version;
-
- /** Who started the action. Usefule for debugging */
- String whoStarted;
-
- public void beginAction( boolean readOnly, ActionVersioning.Version version, String whoStarted )
- {
- this.readOnly = readOnly;
- this.version = version;
- this.whoStarted = whoStarted;
- }
-
- public void endAction()
- {
- assert( version != null );
- version = null;
- }
-
- public boolean isReadOnlyAction()
- {
- return ( readOnly && this.version != null );
- }
-
- public boolean isWriteAction()
- {
- return ( !readOnly && this.version != null );
-
- }
-
- public boolean isActive()
- {
- return ( this.version != null );
- }
-
- public ActionVersioning.Version getVersion()
- {
- return version;
- }
-
- public String getWhoStarted()
- {
- return whoStarted;
- }
+{
+ /** track whether action is read only */
+ boolean readOnly;
-
+ /** Version associated with the context */
+ ActionVersioning.Version version;
+
+ /** Who started the action. Usefule for debugging */
+ String whoStarted;
+
+ public void beginAction( boolean readOnly, ActionVersioning.Version version, String whoStarted )
+ {
+ this.readOnly = readOnly;
+ this.version = version;
+ this.whoStarted = whoStarted;
}
-
\ No newline at end of file
+
+
+ public void endAction()
+ {
+ assert( version != null );
+ version = null;
+ }
+
+
+ public boolean isReadOnlyAction()
+ {
+ return ( readOnly && ( version != null ) );
+ }
+
+
+ public boolean isWriteAction()
+ {
+ return ( !readOnly && ( version != null ) );
+ }
+
+
+ public boolean isActive()
+ {
+ return ( version != null );
+ }
+
+
+ public ActionVersioning.Version getVersion()
+ {
+ return version;
+ }
+
+
+ public String getWhoStarted()
+ {
+ return whoStarted;
+ }
+}
diff --git a/jdbm/src/main/java/jdbm/helper/ActionVersioning.java b/jdbm/src/main/java/jdbm/helper/ActionVersioning.java
index b1311b8..f50bcc6 100644
--- a/jdbm/src/main/java/jdbm/helper/ActionVersioning.java
+++ b/jdbm/src/main/java/jdbm/helper/ActionVersioning.java
@@ -1,9 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
-import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
-
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -18,10 +35,8 @@
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-
public class ActionVersioning
{
-
/** Current write version */
private Version nextVersion;
@@ -78,7 +93,7 @@
listLock.lock();
versions.addLast( newNextVersion.getVersionsLink() );
- if ( oldReadVersion.getNumActions().get() == 0 &&
+ if ( ( oldReadVersion.getNumActions().get() == 0 ) &&
oldReadVersion.getVersionsLink().isLinked() )
{
versions.remove( oldReadVersion.getVersionsLink() );
@@ -92,6 +107,7 @@
return minVersion;
}
+
/**
* Returns a version that can be used by the read only action
*
@@ -111,18 +127,20 @@
if ( readVersion != readReference.get() )
{
listLock.lock();
+
if ( readVersion.getVersionsLink().isUnLinked() )
{
readVersion = readReference.get();
readVersion.getNumActions().incrementAndGet();
}
+
listLock.unlock();
-
}
return readVersion;
}
+
/**
* Called when the read action with the given action is ended.
* Checks whether the minimum read version advanced
@@ -137,9 +155,7 @@
assert( numActions >= 0 );
-
-
- if ( numActions > 0 || version == readReference.get() )
+ if ( ( numActions > 0 ) || ( version == readReference.get() ) )
{
// minimum read version did not change for sure
return null;
@@ -147,19 +163,21 @@
Version minVersion = null;
listLock.lock();
- if ( version.getNumActions().get() == 0 &&
+
+ if ( ( version.getNumActions().get() == 0 ) &&
version.getVersionsLink().isLinked() )
{
version.getVersionsLink().remove();
version.getVersionsLink().uninit();
}
+
minVersion = versions.begin().getElement();
listLock.unlock();
return minVersion;
-
}
+
public static class Version
{
/** Represented version */
@@ -181,16 +199,19 @@
numActions = new AtomicInteger( 0 );
}
+
private ExplicitList.Link<Version> getVersionsLink()
{
return versionsLink;
}
+
private AtomicInteger getNumActions()
{
return numActions;
}
+
public long getVersion()
{
return version;
diff --git a/jdbm/src/main/java/jdbm/helper/EntryIO.java b/jdbm/src/main/java/jdbm/helper/EntryIO.java
index 706baff..61011cf 100644
--- a/jdbm/src/main/java/jdbm/helper/EntryIO.java
+++ b/jdbm/src/main/java/jdbm/helper/EntryIO.java
@@ -1,9 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
import java.io.IOException;
+/**
+ *
+ * TODO EntryIO.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
public interface EntryIO<K, V>
{
- public V read( K key, Serializer serializer) throws IOException;
- public void write( K key, V value, Serializer serializer ) throws IOException;
+ public V read( K key, Serializer serializer) throws IOException;
+ public void write( K key, V value, Serializer serializer ) throws IOException;
}
\ No newline at end of file
diff --git a/jdbm/src/main/java/jdbm/helper/ExplicitList.java b/jdbm/src/main/java/jdbm/helper/ExplicitList.java
index a1921ac..bd60dc8 100644
--- a/jdbm/src/main/java/jdbm/helper/ExplicitList.java
+++ b/jdbm/src/main/java/jdbm/helper/ExplicitList.java
@@ -1,137 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
+
/**
- * A imple doubly linked list implementation that can be used when fast remove operations are desired.
+ * A simple doubly linked list implementation that can be used when fast remove operations are desired.
* Objects are inserted into the list through an anchor (Link). When object is to be removed from the
* list, this anchor is provided by the client again and this class can do the remove operation in O(1)
* using the given anchor.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-
public class ExplicitList<T>
{
-
- Link<T> head = new Link<T>( null );
-
- public static class Link<V>
- {
- private V element;
- private Link<V> next;
- private Link<V> prev;
-
- public Link( V element )
- {
- this.element = element;
- this.reset();
- }
-
- public Link<V> getNext()
- {
- return next;
- }
-
- public void setNext( Link<V> next )
- {
- this.next = next;
- }
-
- public Link<V> getPrev()
- {
- return prev;
- }
-
- public void setPrev( Link<V> prev )
- {
- this.prev = prev;
- }
-
- public void remove()
- {
- assert( isLinked() );
- this.getPrev().setNext( this.getNext() );
- this.getNext().setPrev( this.getPrev() );
- this.reset();
- }
-
- public void addAfter( Link<V> after )
- {
- after.getNext().setPrev( this );
- this.setNext( after.getNext() );
- after.setNext( this );
- this.setPrev( after );
- }
-
- public void addBefore( Link<V> before )
- {
- before.getPrev().setNext(this );
- this.setPrev( before.getPrev() );
- before.setPrev( this );
- this.setNext( before );
- }
-
- public void splice( Link<V> listHead)
- {
- Link<V> prevLink = listHead.getPrev();
- listHead.setPrev( this );
- prevLink.setNext( this );
- this.setNext( listHead );
- this.setPrev( prevLink );
- }
-
- public boolean isUnLinked()
- {
- return ( prev == this && next == this );
- }
-
- public boolean isLinked()
- {
- return ( !this.isUnLinked() );
- }
-
- public void reset()
- {
- next = this;
- prev = this;
- }
-
- public void uninit()
- {
- assert ( this.isUnLinked() );
- element = null;
- }
-
- public V getElement()
- {
- return this.element;
- }
- }
-
-
- public void remove( Link<T> link )
- {
- link.remove();
- }
-
- public void addFirst( Link<T> link )
- {
- link.addAfter( head );
- }
-
- public void addLast( Link<T> link )
- {
- link.addBefore( head );
- }
-
- public Link<T> begin()
- {
- return ( head.getNext() );
- }
-
- public Link<T> end()
- {
- return head;
- }
-
-
+
+ Link<T> head = new Link<T>( null );
+
+ public static class Link<V>
+ {
+ private V element;
+ private Link<V> next;
+ private Link<V> prev;
+
+
+ public Link( V element )
+ {
+ this.element = element;
+ this.reset();
+ }
+
+
+ public Link<V> getNext()
+ {
+ return next;
+ }
+
+
+ public void setNext( Link<V> next )
+ {
+ this.next = next;
+ }
+
+
+ public Link<V> getPrev()
+ {
+ return prev;
+ }
+
+
+ public void setPrev( Link<V> prev )
+ {
+ this.prev = prev;
+ }
+
+
+ public void remove()
+ {
+ assert ( isLinked() );
+ this.getPrev().setNext( this.getNext() );
+ this.getNext().setPrev( this.getPrev() );
+ this.reset();
+ }
+
+
+ public void addAfter( Link<V> after )
+ {
+ after.getNext().setPrev( this );
+ this.setNext( after.getNext() );
+ after.setNext( this );
+ this.setPrev( after );
+ }
+
+
+ public void addBefore( Link<V> before )
+ {
+ before.getPrev().setNext( this );
+ this.setPrev( before.getPrev() );
+ before.setPrev( this );
+ this.setNext( before );
+ }
+
+
+ public void splice( Link<V> listHead )
+ {
+ Link<V> prevLink = listHead.getPrev();
+ listHead.setPrev( this );
+ prevLink.setNext( this );
+ this.setNext( listHead );
+ this.setPrev( prevLink );
+ }
+
+
+ public boolean isUnLinked()
+ {
+ return ( prev == this && next == this );
+ }
+
+
+ public boolean isLinked()
+ {
+ return ( !this.isUnLinked() );
+ }
+
+
+ public void reset()
+ {
+ next = this;
+ prev = this;
+ }
+
+
+ public void uninit()
+ {
+ assert ( this.isUnLinked() );
+ element = null;
+ }
+
+
+ public V getElement()
+ {
+ return this.element;
+ }
+ }
+
+
+ public void remove( Link<T> link )
+ {
+ link.remove();
+ }
+
+
+ public void addFirst( Link<T> link )
+ {
+ link.addAfter( head );
+ }
+
+
+ public void addLast( Link<T> link )
+ {
+ link.addBefore( head );
+ }
+
+
+ public Link<T> begin()
+ {
+ return ( head.getNext() );
+ }
+
+
+ public Link<T> end()
+ {
+ return head;
+ }
+
}
\ No newline at end of file
diff --git a/jdbm/src/main/java/jdbm/helper/LRUCache.java b/jdbm/src/main/java/jdbm/helper/LRUCache.java
index 7364d83..522637c 100644
--- a/jdbm/src/main/java/jdbm/helper/LRUCache.java
+++ b/jdbm/src/main/java/jdbm/helper/LRUCache.java
@@ -1,31 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
+import java.io.IOException;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
-import java.util.Iterator;
-import java.util.PriorityQueue;
-
-
-import java.util.Comparator;
-
import java.util.Random;
-
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.Condition;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.sun.tools.javac.util.Log;
-
-
-
/**
* This class implements a versioned lru cache. Entries in the cache are identified with a key.
@@ -96,42 +103,54 @@
this.entryIO =entryIO;
if ( cacheSize < MIN_ENTRIES )
+ {
cacheSize = MIN_ENTRIES;
+ }
maxEntries = cacheSize;
int numHashBuckets = MIN_ENTRIES;
+
while ( numHashBuckets < maxEntries )
+ {
numHashBuckets = numHashBuckets << 1;
+ }
if ( numHashBuckets > maxEntries)
+ {
numBuckets = numHashBuckets >> 1;
+ }
else
+ {
numBuckets = numHashBuckets;
+ }
buckets = ( List<CacheEntry>[] )new LinkedList[numBuckets];
+
for ( idx = 0; idx < numBuckets; idx++ )
{
buckets[idx] = new LinkedList<CacheEntry>();
}
int numLatches = numBuckets >> LOG_BUCKET_PER_LATCH;
- latches = new Lock[numLatches];
- for ( idx = 0; idx < numLatches; idx++ )
+ latches = new Lock[numLatches];
+
+ for ( idx = 0; idx < numLatches; idx++ )
{
latches[idx] = new ReentrantLock();
}
lrus = ( LRUCache.LRU[] ) new LRUCache.LRU[NUM_LRUS];
- for ( idx = 0; idx < NUM_LRUS; idx++ )
+
+ for ( idx = 0; idx < NUM_LRUS; idx++ )
{
lrus[idx] = new LRU();
}
numEntries = new AtomicInteger( 0 );
-
}
+
/**
* Called as the minimum version that readers will use advances. This lets
* cache get rid of the older versions of entries.
@@ -143,10 +162,10 @@
minReadVersion = minVersion;
}
+
/**
* Updates the entry identified with the key with the new value.
*
- *
* @param key identifier of the entry
* @param value new value of the entry
* @param newVersion version of the new value
@@ -189,6 +208,7 @@
while (it.hasNext() )
{
entry = it.next();
+
if ( entry.getKey().equals( key ) )
{
entryExists = true;
@@ -202,7 +222,6 @@
{
switch ( entry.getState() )
{
-
case ENTRY_READY: // should be the common case
if ( !entry.isCurrentVersion() )
@@ -221,13 +240,14 @@
this.doRead( entry, latches[latchIndex], serializer );
}
-
this.putNewVersion( entry, key, value, newVersion, hashIndex,
latches[latchIndex], serializer, neverReplace );
break;
+
case ENTRY_READING:
// Somebody is reading our entry, wait until the read is done and then retry
this.doWaitForStateChange( entry, latches[latchIndex] );
+
if ( entry.getState() == EntryState.ENTRY_READY )
{
this.putNewVersion( entry, key, value, newVersion, hashIndex, latches[latchIndex],
@@ -237,19 +257,20 @@
LOG.warn( "Entry with key {} is at intial state after waiting for IO", entry.getKey() );
// FALLTHROUGH
- case ENTRY_INITIAL:
+ case ENTRY_INITIAL:
LOG.warn( "Entry with key {} is at intial while trying to read from it", entry.getKey() );
this.doRead( entry, latches[latchIndex], serializer );
this.putNewVersion( entry, key, value, newVersion, hashIndex, latches[latchIndex],
serializer, neverReplace );
break;
+
case ENTRY_WRITING:
// FALLTHROUGH
+
default:
assert ( false );
}
-
}
else
{
@@ -265,7 +286,9 @@
sleepForFreeEntry = totalSleepTime < this.MAX_WRITE_SLEEP_TIME;
if ( sleepForFreeEntry == false )
+ {
throw e;
+ }
}
finally
{
@@ -287,7 +310,9 @@
totalSleepTime += sleepInterval;
}
else
+ {
break;
+ }
}
}
@@ -309,8 +334,6 @@
int latchIndex = ( hashIndex >> LOG_BUCKET_PER_LATCH );
V value = null;
-
-
/*
* 1) If entry exists
* 1.1) if the version chain contains the desired version, then return it, otherwise read
@@ -323,7 +346,6 @@
*
* While reading or waiting, latch is released.
*/
-
latches[latchIndex].lock();
boolean chainExists = false;
@@ -333,6 +355,7 @@
while ( it.hasNext() )
{
entry = it.next();
+
if ( entry.getKey().equals( key ) )
{
chainExists = true;
@@ -372,9 +395,11 @@
case ENTRY_WRITING: // being written entry is always at current version
value = this.searchChainForVersion( entry, version );
break;
+
case ENTRY_READING:
// Somebody is reading our entry, wait until the read is done and then retry
this.doWaitForStateChange( entry, latches[latchIndex] );
+
if ( entry.getState() == EntryState.ENTRY_READY )
{
value = this.searchChainForVersion( entry, version );
@@ -382,16 +407,17 @@
}
LOG.warn( "Entry with key {} is at intial state after waiting for IO", entry.getKey() );
// FALLTHROUGH
+
case ENTRY_INITIAL:
LOG.warn( "Entry with key {} is at intial while trying to read from it", entry.getKey() );
this.doRead( entry, latches[latchIndex], serializer );
value = this.searchChainForVersion( entry, version );
- break;
+ break;
+
default:
assert ( false );
}
-
}
else
{
@@ -409,7 +435,6 @@
* blocked
*/
return entryIO.read( key, serializer );
-
}
finally
{
@@ -417,8 +442,8 @@
}
return value;
-
}
+
/**
* Creates a new version of the given entry with the given new version.
@@ -464,15 +489,16 @@
}
if ( neverReplace )
+ {
entry.setNeverReplace();
-
+ }
entry.setState( EntryState.ENTRY_WRITING );
latch.unlock();
try
{
- entryIO.write( key, value, serializer );
+ entryIO.write( key, value, serializer );
}
catch( IOException e )
{
@@ -481,8 +507,11 @@
* inconsistent state.
*/
entry.setState( EntryState.ENTRY_INITIAL );
+
if ( entry.anyWaiters() )
+ {
entry.getStateCondition( latch ).notifyAll();
+ }
else
{
LRU lru = entry.getLru();
@@ -494,14 +523,13 @@
latch.unlock();
throw e;
-
}
latch.lock();
entry.setState( EntryState.ENTRY_READY );
-
}
+
/**
* Searches the given version for the entry that can satisfy the read with the
* given version and returns the value of that entry. Cache is responsible is for
@@ -521,11 +549,14 @@
V value = null;
if ( head.getState() != EntryState.ENTRY_READY || !head.isCurrentVersion() )
+ {
mustFind = false;
+ }
do
{
curEntry = curLink.getElement();
+
if ( curEntry.getState() != EntryState.ENTRY_READY )
{
assert( curEntry == head );
@@ -534,11 +565,12 @@
}
if ( curStartVersion != 0 && ( curEntry.getEndVersion() > curStartVersion ) )
+ {
assert( false );
+ }
curStartVersion = curEntry.getStartVersion();
-
if ( !curEntry.canReadFrom( version ) )
{
curLink = curLink.getNext();
@@ -546,7 +578,6 @@
}
// found it
-
if ( curEntry.isCurrentVersion() )
{
// Warm the entry in the lru
@@ -558,14 +589,18 @@
value = curEntry.getValue();
break;
- }while( curLink != head.getVersionsLink() );
+
+ } while ( curLink != head.getVersionsLink() );
- if ( value == null && mustFind == true )
+ if ( value == null && mustFind == true )
+ {
assert( false );
+ }
return value;
}
+
/**
* Wait for the state change to happen. Usually used to wait for another
* thread to complete the IO.Latch covering the entry is held at the entry.
@@ -578,6 +613,7 @@
EntryState curState = entry.getState();
Condition cond = entry.getStateCondition( latch );
entry.bumpWaiters();
+
do
{
cond.awaitUninterruptibly();
@@ -587,6 +623,7 @@
entry.decrementWaiters();
}
+
/**
* Does read the value for the given entry. At entry, latch is held. It is
* dropped during the read and regotten after a successful read.
@@ -611,8 +648,11 @@
// do cleanup and rethrow
latch.lock();
entry.setState( EntryState.ENTRY_INITIAL );
+
if ( entry.anyWaiters() )
+ {
entry.getStateCondition( latch ).notifyAll();
+ }
else
{
LRU lru = entry.getLru();
@@ -631,14 +671,22 @@
// set the version range
ExplicitList.Link<CacheEntry> nextLink = entry.getVersionsLink().getNext();
long startVersion;
+
if ( entry.getVersionsLink().isUnLinked() )
+ {
startVersion = 0;
+ }
else
+ {
startVersion = nextLink.getElement().getEndVersion();
+ }
entry.setAsCurrentVersion( value, startVersion );
+
if ( entry.anyWaiters() )
+ {
entry.getStateCondition( latch ).signalAll();
+ }
}
/**
@@ -657,7 +705,6 @@
int id, curIndex;
boolean lruLocked = false;
-
// if under max entries, allocate a new one and add it to the lru with the index.. numEntries check is dirty
if ( numEntries.get() < maxEntries )
{
@@ -668,6 +715,7 @@
lru.addToLRU( newEntry );
lru.getLock().unlock();
newEntry.initialize( key );
+
return newEntry;
}
@@ -679,6 +727,7 @@
CacheEntry victimEntry = null;
lru = null;
curIndex = 0;
+
for ( id = 0; id < NUM_LRUS; id++ )
{
curIndex = ( index + id ) % NUM_LRUS;
@@ -699,6 +748,7 @@
}
int startingIndex = curIndex;
+
do
{
victimEntry = lru.findVictim( latchIndex );
@@ -715,10 +765,13 @@
lru = lrus[curIndex];
lru.getLock().lock();
- }while ( true );
+ }
+ while ( true );
if ( victimEntry != null )
+ {
victimEntry.initialize( key );
+ }
else
{
LOG.warn( "Cache eviction failure: " + this.minReadVersion );
@@ -736,6 +789,7 @@
h ^= ( h >>> 14 );
h += ( h << 4 );
h ^= ( h >>> 10 );
+
return h;
}
@@ -820,6 +874,7 @@
neverReplace = true;
}
+
public K getKey()
{
return key;
@@ -831,6 +886,7 @@
return value;
}
+
public int getHashIndex()
{
return hashIndex;
@@ -842,10 +898,13 @@
return lrus[lruid];
}
+
public Condition getStateCondition( Lock lock )
{
if ( stateCondition == null )
+ {
stateCondition = lock.newCondition();
+ }
return stateCondition;
}
@@ -868,6 +927,7 @@
{
return numWaiters > 0;
}
+
public long getEndVersion()
{
@@ -880,6 +940,7 @@
return startVersion;
}
+
/**
* Check if entry is the most recent version for its key
*
@@ -914,6 +975,7 @@
{
this.state = newState;
}
+
public ExplicitList.Link<CacheEntry> getVersionsLink()
{
@@ -926,6 +988,7 @@
return lruLink;
}
+
public void setAsCurrentVersion( V newValue, long startVersion )
{
this.startVersion = startVersion;
@@ -934,6 +997,7 @@
this.state = EntryState.ENTRY_READY;
}
+
public void setAsSnapshotVersion( long newEndVersion )
{
this.endVersion = newEndVersion;
@@ -944,12 +1008,12 @@
lru.getLock().unlock();
}
+
public boolean isEntryFreeable()
{
return ( this.state != EntryState.ENTRY_READING && this.numWaiters == 0 &&
this.state != EntryState.ENTRY_WRITING && !neverReplace);
}
-
}
@@ -969,6 +1033,7 @@
return lock;
}
+
/**
* add the new entry to the head of the lru
*
@@ -979,6 +1044,7 @@
mostRecentVersions.addFirst( entry.getLruLink() );
}
+
/**
* Removes the entry from the lru list and Adds the entry to the list of snapshot entries.
* Entry should a most recent entry.
@@ -991,6 +1057,7 @@
snapshotVersions.addLast( entry );
}
+
/**
* Moves the entry to the cold end of the lru. Entry should be a most
* recent entry
@@ -1003,6 +1070,7 @@
mostRecentVersions.addFirst( entry.getLruLink() );
}
+
/**
* Increases the hotness of the given entry
*
@@ -1035,12 +1103,15 @@
*/
Iterator<CacheEntry> it = snapshotVersions.listIterator();
+
while ( it.hasNext() )
{
victimEntry = it.next();
if ( victimEntry.getEndVersion() > minReadVersion )
+ {
break;
+ }
assert ( victimEntry.isEntryFreeable() == true );
@@ -1048,13 +1119,17 @@
victimBucketIndex = victimEntry.getHashIndex();
victimLatchIndex = (victimBucketIndex >> LOG_BUCKET_PER_LATCH );
- if ( latchIndex != victimLatchIndex && latches[victimLatchIndex].tryLock() == false )
+ if ( ( latchIndex != victimLatchIndex ) && ( latches[victimLatchIndex].tryLock() == false ) )
+ {
continue;
+ }
- int hashChainIndex = buckets[victimEntry.getHashIndex()].indexOf( victimEntry );
+ int hashChainIndex = buckets[victimEntry.getHashIndex()].indexOf( victimEntry );
+
if ( hashChainIndex != -1 )
{
buckets[victimEntry.getHashIndex()].remove( hashChainIndex );
+
if ( victimEntry.getVersionsLink().isLinked() )
{
ExplicitList.Link<CacheEntry> nextLink = victimEntry.getVersionsLink().getNext();
@@ -1069,17 +1144,19 @@
victimEntry.getVersionsLink().remove();
}
-
if ( latchIndex != victimLatchIndex )
+ {
latches[victimLatchIndex].unlock();
+ }
it.remove();
this.mostRecentVersions.addLast( victimEntry.lruLink );
- return victimEntry;
+ return victimEntry;
}
ExplicitList.Link<CacheEntry> curLink = mostRecentVersions.begin();
+
while ( curLink != mostRecentVersions.end() )
{
victimEntry = curLink.getElement();
@@ -1104,14 +1181,16 @@
if ( victimEntry.isEntryFreeable() == false )
{
if ( latchIndex != victimLatchIndex )
+ {
latches[victimLatchIndex].unlock();
+ }
curLink = curLink.getNext();
continue;
}
-
buckets[victimEntry.getHashIndex()].remove( victimEntry );
+
if ( victimEntry.getVersionsLink().isLinked() )
{
ExplicitList.Link<CacheEntry> nextLink = victimEntry.getVersionsLink().getNext();
@@ -1122,18 +1201,15 @@
}
if ( latchIndex != victimLatchIndex )
+ {
latches[victimLatchIndex].unlock();
+ }
this.touch( victimEntry );
return victimEntry;
-
}
return null;
-
}
-
}
-
-
}
\ No newline at end of file
diff --git a/jdbm/src/main/java/jdbm/helper/TupleBrowser.java b/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
index 665cac6..3210109 100644
--- a/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
+++ b/jdbm/src/main/java/jdbm/helper/TupleBrowser.java
@@ -74,10 +74,10 @@
*/
public abstract boolean getPrevious( Tuple<K, V> tuple ) throws IOException;
+
/**
* Closes the browser and deallocates any resources it might have allocated.
* Repeated calls of close are OK.
*/
public void close() {}
-
}
diff --git a/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java b/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
index 2d158b5..2290c04 100644
--- a/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
+++ b/jdbm/src/main/java/jdbm/recman/BaseRecordManager.java
@@ -49,19 +49,18 @@
package jdbm.recman;
import java.io.IOException;
-
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.locks.Condition;
-
-import org.apache.directory.server.i18n.I18n;
import jdbm.RecordManager;
-import jdbm.helper.Serializer;
import jdbm.helper.DefaultSerializer;
+import jdbm.helper.Serializer;
+
+import org.apache.directory.server.i18n.I18n;
/**
* This class manages records, which are uninterpreted blobs of data. The
@@ -85,8 +84,7 @@
* @author <a href="mailto:boisvert@intalio.com">Alex Boisvert</a>
* @author <a href="cg@cdegroot.com">Cees de Groot</a>
*/
-public final class BaseRecordManager
- implements RecordManager
+public final class BaseRecordManager implements RecordManager
{
/** Underlying record recordFile. */
private RecordFile recordFile;
@@ -200,9 +198,9 @@
{
return cv;
}
-
}
+
/**
* Map used to synchronize reads and writes on the same logical
* recid.
@@ -319,7 +317,7 @@
*/
public void delete( long recid ) throws IOException
{
- LockElement element;
+ LockElement element;
checkIfClosed();
if ( recid <= 0 )
@@ -337,14 +335,14 @@
try
{
- Location logRowId = new Location( recid );
- Location physRowId = logMgr.fetch( logRowId );
- physMgr.delete( physRowId );
- logMgr.delete( logRowId );
+ Location logRowId = new Location( recid );
+ Location physRowId = logMgr.fetch( logRowId );
+ physMgr.delete( physRowId );
+ logMgr.delete( logRowId );
}
finally
{
- this.endIO(recid, element, IOType.WRITE_IO);
+ this.endIO(recid, element, IOType.WRITE_IO);
}
}
@@ -360,6 +358,7 @@
{
update( recid, obj, DefaultSerializer.INSTANCE );
}
+
/**
* Updates a record using a custom serializer.
@@ -371,9 +370,9 @@
*/
public void update( long recid, Object obj, Serializer serializer ) throws IOException
{
- LockElement element;
-
- checkIfClosed();
+ LockElement element;
+
+ checkIfClosed();
if ( recid <= 0 )
{
@@ -381,10 +380,10 @@
}
element = this.beginIO(recid, IOType.WRITE_IO);
-
+
try
- {
- Location logRecid = new Location( recid );
+ {
+ Location logRecid = new Location( recid );
Location physRecid = logMgr.fetch( logRecid );
byte[] data = serializer.serialize( obj );
@@ -400,12 +399,11 @@
{
logMgr.update( logRecid, newRecid );
}
-
- }
- finally
- {
- this.endIO(recid, element, IOType.WRITE_IO);
- }
+ }
+ finally
+ {
+ this.endIO(recid, element, IOType.WRITE_IO);
+ }
}
@@ -432,21 +430,21 @@
*/
public Object fetch( long recid, Serializer serializer ) throws IOException
{
- Object result;
- LockElement element;
-
- checkIfClosed();
+ Object result;
+ LockElement element;
+
+ checkIfClosed();
if ( recid <= 0 )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_536, recid ) );
}
-
- element = this.beginIO(recid, IOType.READ_IO);
-
- try
- {
- byte[] data;
+
+ element = this.beginIO(recid, IOType.READ_IO);
+
+ try
+ {
+ byte[] data;
data = physMgr.fetch( logMgr.fetch( new Location( recid ) ) );
@@ -454,17 +452,16 @@
{
System.out.println( "BaseRecordManager.fetch() recid " + recid + " length " + data.length ) ;
}
+
result = serializer.deserialize( data );
- }
- finally
- {
- this.endIO(recid, element, IOType.READ_IO);
- }
-
- return result;
-
+ }
+ finally
+ {
+ this.endIO(recid, element, IOType.READ_IO);
+ }
+
+ return result;
}
-
/**
@@ -541,6 +538,7 @@
{
getNameDirectory().put( name, recid );
}
+
saveNameDirectory( );
}
@@ -548,8 +546,7 @@
/**
* Commit (make persistent) all changes since beginning of transaction.
*/
- public void commit()
- throws IOException
+ public void commit() throws IOException
{
checkIfClosed();
@@ -634,6 +631,7 @@
// loop until we successfully verify that there is no concurrent writer
/*
element = lockElements.get( recid );
+
do
{
if ( element == null )
@@ -641,26 +639,36 @@
element = new LockElement();
if ( io == IOType.READ_IO )
+ {
element.bumpReaders();
+ }
else
+ {
element.setWritten();
+ }
LockElement existingElement = lockElements.putIfAbsent( recid, element );
if ( existingElement == null )
+ {
lockVerified = true;
+ }
else
+ {
element = existingElement;
+ }
}
else
{
Lock lock = element.getLock();
lock.lock();
+
if ( element.anyUser() )
{
if ( this.conflictingIOPredicate( io, element ) )
{
element.bumpWaiters();
+
do
{
element.getNoConflictingIOCondition()
@@ -673,25 +681,39 @@
// no conflicting IO anymore..done
if ( io == IOType.READ_IO )
+ {
element.bumpReaders();
+ }
else
+ {
element.setWritten();
+ }
+
lockVerified = true;
}
else
{
if ( io == IOType.READ_IO )
+ {
element.bumpReaders();
+ }
else
+ {
element.setWritten();
+ }
LockElement existingElement = lockElements.get( recid );
if ( element != existingElement )
+ {
element = existingElement;
+ }
else
+ {
lockVerified = true; // done
+ }
}
+
lock.unlock();
}
}
@@ -710,30 +732,43 @@
*/
private void endIO( Long recid, LockElement element, IOType io )
{
- /* Lock lock = element.getLock();
+ /*
+ Lock lock = element.getLock();
lock.lock();
if ( io == IOType.READ_IO )
+ {
element.decrementReaders();
+ }
else
+ {
element.unsetWritten();
+ }
if ( element.anyWaiters() )
+ {
element.getNoConflictingIOCondition().notifyAll();
+ }
if ( !element.anyUser() )
+ {
lockElements.remove( recid );
+ }
- lock.unlock();*/
+ lock.unlock();
+ */
}
private boolean conflictingIOPredicate( IOType io, LockElement element )
{
if ( io == IOType.READ_IO )
+ {
return element.beingWritten();
+ }
else
+ {
return ( element.anyReaders() || element.beingWritten() );
+ }
}
-
}
diff --git a/jdbm/src/main/java/jdbm/recman/SnapshotRecordManager.java b/jdbm/src/main/java/jdbm/recman/SnapshotRecordManager.java
index 36e58f1..8c76644 100644
--- a/jdbm/src/main/java/jdbm/recman/SnapshotRecordManager.java
+++ b/jdbm/src/main/java/jdbm/recman/SnapshotRecordManager.java
@@ -1,27 +1,47 @@
-
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.recman;
import java.io.IOException;
-import java.util.Enumeration;
-
-import jdbm.RecordManager;
-import jdbm.ActionRecordManager;
-import jdbm.helper.DefaultSerializer;
-import jdbm.helper.Serializer;
-import jdbm.helper.CacheEvictionException;
-import jdbm.helper.EntryIO;
-
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
-import jdbm.helper.ActionVersioning;
-import jdbm.helper.LRUCache;
+import jdbm.ActionRecordManager;
+import jdbm.RecordManager;
import jdbm.helper.ActionContext;
+import jdbm.helper.ActionVersioning;
+import jdbm.helper.CacheEvictionException;
+import jdbm.helper.DefaultSerializer;
+import jdbm.helper.EntryIO;
+import jdbm.helper.LRUCache;
+import jdbm.helper.Serializer;
import org.apache.directory.server.i18n.I18n;
-import jdbm.helper.CacheEvictionException;
+/**
+ *
+ * TODO SnapshotRecordManager.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
public class SnapshotRecordManager implements ActionRecordManager
{
/** Wrapped RecordManager */
@@ -67,7 +87,6 @@
versionedCache = new LRUCache<Long ,Object>(recordIO, size);
}
-
/**
* {@inheritDoc}
@@ -89,6 +108,7 @@
actionContext.beginAction( readOnly, version, whoStarted );
this.setCurrentActionContext( actionContext );
+
return actionContext;
}
@@ -102,6 +122,7 @@
actionContextVar.set( context );
}
+
/**
* {@inheritDoc}
*/
@@ -112,12 +133,14 @@
actionContextVar.set( null );
}
+
/**
* {@inheritDoc}
*/
public void endAction( ActionContext actionContext )
{
ActionVersioning.Version minVersion = null;
+
if ( actionContext.isReadOnlyAction() )
{
ActionVersioning.Version version = actionContext.getVersion();
@@ -138,15 +161,19 @@
this.unsetCurrentActionContext( actionContext );
if ( minVersion != null )
+ {
versionedCache.advanceMinReadVersion( minVersion.getVersion() );
+ }
}
+
/**
* {@inheritDoc}
*/
public void abortAction( ActionContext actionContext )
{
ActionVersioning.Version minVersion = null;
+
if ( actionContext.isReadOnlyAction() )
{
ActionVersioning.Version version = actionContext.getVersion();
@@ -175,8 +202,9 @@
this.unsetCurrentActionContext( actionContext );
if ( minVersion != null )
+ {
versionedCache.advanceMinReadVersion( minVersion.getVersion() );
-
+ }
}
@@ -219,6 +247,7 @@
ActionContext actionContext = actionContextVar.get();
boolean startedAction = false;
boolean abortedAction = false;
+
if ( actionContext == null )
{
actionContext = this.beginAction( false, "insert missing action" );
@@ -226,6 +255,7 @@
}
long recid = 0;
+
try
{
recid = recordManager.insert( obj, serializer );
@@ -240,6 +270,7 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw e;
}
catch ( CacheEvictionException except )
@@ -249,12 +280,15 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw new IOException( except.getLocalizedMessage() );
}
finally
{
if ( startedAction && !abortedAction )
+ {
this.endAction ( actionContext );
+ }
}
return recid;
@@ -274,11 +308,12 @@
ActionContext actionContext = actionContextVar.get();
boolean startedAction = false;
boolean abortedAction = false;
+
if ( actionContext == null )
{
actionContext = this.beginAction( false, "delete missing action" );
startedAction = true;
- }
+ }
// Update the cache
try
@@ -293,6 +328,7 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw e;
}
catch ( CacheEvictionException except )
@@ -302,14 +338,16 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw new IOException( except.getLocalizedMessage() );
}
finally
{
if ( startedAction && !abortedAction )
+ {
this.endAction ( actionContext );
+ }
}
-
}
@@ -340,6 +378,7 @@
ActionContext actionContext = actionContextVar.get();
boolean startedAction = false;
boolean abortedAction = false;
+
if ( actionContext == null )
{
actionContext = this.beginAction( false, "update missing action" );
@@ -358,6 +397,7 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw e;
}
catch ( CacheEvictionException except )
@@ -367,12 +407,15 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw new IOException( except.getLocalizedMessage() );
}
finally
{
if ( startedAction && !abortedAction )
+ {
this.endAction ( actionContext );
+ }
}
}
@@ -406,6 +449,7 @@
boolean startedAction = false;
boolean abortedAction = false;
+
if ( actionContext == null )
{
actionContext = this.beginAction( false, "fetch missing action" );
@@ -415,7 +459,7 @@
try
{
obj = versionedCache.get( new Long( recid ), actionContext.getVersion().getVersion(),
- serializer );
+ serializer );
}
catch ( IOException e )
{
@@ -424,12 +468,15 @@
this.abortAction( actionContext );
abortedAction = true;
}
+
throw e;
}
finally
{
if ( startedAction && !abortedAction )
+ {
this.endAction ( actionContext );
+ }
}
return obj;
@@ -475,6 +522,7 @@
public long getRoot( int id ) throws IOException
{
bigLock.lock();
+
try
{
checkIfClosed();
@@ -495,6 +543,7 @@
public void setRoot( int id, long rowid ) throws IOException
{
bigLock.lock();
+
try
{
checkIfClosed();
@@ -514,6 +563,7 @@
public void commit() throws IOException
{
bigLock.lock();
+
try
{
checkIfClosed();
@@ -532,7 +582,7 @@
*/
public void rollback() throws IOException
{
- // TODO handle this by quiecesing all actions and throwing away the cache contents
+ // TODO handle this by quiecesing all actions and throwing away the cache contents
}
@@ -543,6 +593,7 @@
public long getNamedObject( String name ) throws IOException
{
bigLock.lock();
+
try
{
checkIfClosed();
@@ -562,6 +613,7 @@
public void setNamedObject( String name, long recid ) throws IOException
{
bigLock.lock();
+
try
{
checkIfClosed();
@@ -587,15 +639,15 @@
}
-
-
private class RecordIO implements EntryIO<Long, Object>
{
public Object read( Long key, Serializer serializer) throws IOException
{
// Meta objects are kept in memory only
if ( key < 0 )
+ {
return null;
+ }
return recordManager.fetch( key.longValue(), serializer );
}
@@ -603,7 +655,9 @@
public void write( Long key, Object value, Serializer serializer ) throws IOException
{
if ( key < 0 )
+ {
return;
+ }
if ( value != null )
{
@@ -615,5 +669,4 @@
}
}
}
-
}
diff --git a/jdbm/src/test/java/jdbm/btree/SnapshotBTree.java b/jdbm/src/test/java/jdbm/btree/SnapshotBTree.java
index d3f1951..a939223 100644
--- a/jdbm/src/test/java/jdbm/btree/SnapshotBTree.java
+++ b/jdbm/src/test/java/jdbm/btree/SnapshotBTree.java
@@ -1,39 +1,51 @@
- package jdbm.btree;
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.btree;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.ObjectOutputStream;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.io.Serializable;
+import java.util.concurrent.Semaphore;
import jdbm.RecordManager;
import jdbm.RecordManagerFactory;
-import jdbm.helper.CacheEvictionException;
import jdbm.helper.IntegerComparator;
-import jdbm.helper.LRUCache;
import jdbm.helper.Tuple;
import jdbm.helper.TupleBrowser;
-
import jdbm.recman.SnapshotRecordManager;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
+
import com.mycila.junit.concurrent.Concurrency;
import com.mycila.junit.concurrent.ConcurrentJunitRunner;
-import org.junit.rules.TemporaryFolder;
-
-import org.junit.Test;
-
-import java.util.concurrent.Semaphore;
-
+/**
+ *
+ * TODO SnapshotBTree.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
@RunWith(ConcurrentJunitRunner.class)
@Concurrency()
public class SnapshotBTree
diff --git a/jdbm/src/test/java/jdbm/helper/TestActionVersioning.java b/jdbm/src/test/java/jdbm/helper/TestActionVersioning.java
index e094a9f..3febf90 100644
--- a/jdbm/src/test/java/jdbm/helper/TestActionVersioning.java
+++ b/jdbm/src/test/java/jdbm/helper/TestActionVersioning.java
@@ -1,13 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
-import org.junit.runner.RunWith;
-import com.mycila.junit.concurrent.Concurrency;
-import com.mycila.junit.concurrent.ConcurrentJunitRunner;
-
-import org.junit.Test;
-
import static org.junit.Assert.assertEquals;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import com.mycila.junit.concurrent.Concurrency;
+import com.mycila.junit.concurrent.ConcurrentJunitRunner;
+
+/**
+ *
+ * TODO TestActionVersioning.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
@RunWith(ConcurrentJunitRunner.class)
@Concurrency()
public class TestActionVersioning
diff --git a/jdbm/src/test/java/jdbm/helper/TestVersionedCache.java b/jdbm/src/test/java/jdbm/helper/TestVersionedCache.java
index c739967..093eacd 100644
--- a/jdbm/src/test/java/jdbm/helper/TestVersionedCache.java
+++ b/jdbm/src/test/java/jdbm/helper/TestVersionedCache.java
@@ -1,16 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 jdbm.helper;
+import static org.junit.Assert.assertEquals;
+
import java.io.IOException;
+import org.junit.Test;
import org.junit.runner.RunWith;
+
import com.mycila.junit.concurrent.Concurrency;
import com.mycila.junit.concurrent.ConcurrentJunitRunner;
-import org.junit.Test;
-
-import static org.junit.Assert.assertEquals;
-
+/**
+ *
+ * TODO TestVersionedCache.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
@RunWith(ConcurrentJunitRunner.class)
@Concurrency()
public class TestVersionedCache