You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@labs.apache.org by el...@apache.org on 2012/07/25 01:46:11 UTC
svn commit: r1365355 -
/labs/mavibot/trunk/mavibot/src/main/java/org/apache/mavibot/btree/Node.java
Author: elecharny
Date: Tue Jul 24 23:46:11 2012
New Revision: 1365355
URL: http://svn.apache.org/viewvc?rev=1365355&view=rev
Log:
Implemented the Node update when the deletion leads to borrow an element from the right Node.
Modified:
labs/mavibot/trunk/mavibot/src/main/java/org/apache/mavibot/btree/Node.java
Modified: labs/mavibot/trunk/mavibot/src/main/java/org/apache/mavibot/btree/Node.java
URL: http://svn.apache.org/viewvc/labs/mavibot/trunk/mavibot/src/main/java/org/apache/mavibot/btree/Node.java?rev=1365355&r1=1365354&r2=1365355&view=diff
==============================================================================
--- labs/mavibot/trunk/mavibot/src/main/java/org/apache/mavibot/btree/Node.java (original)
+++ labs/mavibot/trunk/mavibot/src/main/java/org/apache/mavibot/btree/Node.java Tue Jul 24 23:46:11 2012
@@ -19,9 +19,11 @@
*/
package org.apache.mavibot.btree;
+
import java.lang.reflect.Array;
import java.util.LinkedList;
+
/**
* A MVCC Node. It stores the keys and references to its children page. It does not
* contain any value.
@@ -31,12 +33,12 @@ import java.util.LinkedList;
*
* @author <a href="mailto:labs@laps.apache.org">Mavibot labs Project</a>
*/
-/* No qualifier */ class Node<K, V> extends AbstractPage<K, V>
+/* No qualifier */class Node<K, V> extends AbstractPage<K, V>
{
/** Children pages associated with keys. */
protected Page<K, V>[] children;
-
-
+
+
/**
* Create a new Node which will contain only one key, with references to
* a left and right page. This is a specific constructor used by the btree
@@ -47,15 +49,15 @@ import java.util.LinkedList;
* @param nbElems The number of elements in this Node
*/
@SuppressWarnings("unchecked")
- /* No qualifier */ Node( BTree<K, V> btree, long revision, int nbElems )
+ /* No qualifier */Node( BTree<K, V> btree, long revision, int nbElems )
{
super( btree, revision, nbElems );
-
+
// Create the children array
children = new Page[nbElems + 1];
}
-
-
+
+
/**
* Create a new Node which will contain only one key, with references to
* a left and right page. This is a specific constructor used by the btree
@@ -68,20 +70,20 @@ import java.util.LinkedList;
* @param rightPage The right page
*/
@SuppressWarnings("unchecked")
- /* No qualifier */ Node( BTree<K, V> btree, long revision, K key, Page<K, V> leftPage, Page<K, V> rightPage )
+ /* No qualifier */Node( BTree<K, V> btree, long revision, K key, Page<K, V> leftPage, Page<K, V> rightPage )
{
super( btree, revision, 1 );
-
+
// Create the children array, and store the left and right children
children = new Page[btree.getPageSize()];
children[0] = leftPage;
children[1] = rightPage;
-
+
// Create the keys array and store the pivot into it
// We get the type of array to create from the btree
// Yes, this is an hack...
Class<?> keyType = btree.getKeyType();
- keys = (K[])Array.newInstance( keyType, btree.getPageSize() );
+ keys = ( K[] ) Array.newInstance( keyType, btree.getPageSize() );
keys[0] = key;
}
@@ -99,12 +101,12 @@ import java.util.LinkedList;
{
// The key has been found in the page. As it's a Node, that means
// we must go down in the right child to insert the value
- pos = - ( pos++ );
+ pos = -( pos++ );
}
-
+
// Get the child page into which we will insert the <K, V> tuple
Page<K, V> child = children[pos];
-
+
// and insert the <K, V> into this child
InsertResult<K, V> result = child.insert( revision, key, value );
@@ -113,17 +115,17 @@ import java.util.LinkedList;
if ( result instanceof ModifyResult )
{
// The child has been modified.
- return replaceChild( revision, (ModifyResult<K, V>)result, pos );
+ return replaceChild( revision, ( ModifyResult<K, V> ) result, pos );
}
else
{
// The child has been split. We have to insert the new pivot in the
// current page, and to reference the two new pages
- SplitResult<K, V> splitResult = (SplitResult<K, V>)result;
+ SplitResult<K, V> splitResult = ( SplitResult<K, V> ) result;
K pivot = splitResult.getPivot();
Page<K, V> leftPage = splitResult.getLeftPage();
Page<K, V> rightPage = splitResult.getRightPage();
-
+
// We have to deal with the two cases :
// - the current page is full, we have to split it
// - the current page is not full, we insert the new pivot
@@ -137,12 +139,12 @@ import java.util.LinkedList;
// The page can contain the new pivot, let's insert it
result = insertChild( revision, pivot, leftPage, rightPage, pos );
}
-
+
return result;
}
}
-
-
+
+
/**
* Modify the current node after a remove has been done in one of its children.
* The node won't be merged with another node.
@@ -153,7 +155,7 @@ import java.util.LinkedList;
// we just have to copy the current page an modify the reference to link to
// the modified page.
Node<K, V> newPage = copy( revision );
-
+
if ( found )
{
newPage.children[index + 1] = removeResult.getModifiedPage();
@@ -162,21 +164,21 @@ import java.util.LinkedList;
{
newPage.children[index] = removeResult.getModifiedPage();
}
-
+
K newLeftMost = removeResult.getNewLeftMost();
-
+
if ( ( newLeftMost != null ) && ( pos < 0 ) )
{
newPage.keys[index] = newLeftMost;
}
-
+
// Modify the result and return
removeResult.setModifiedPage( newPage );
return removeResult;
}
-
-
+
+
/**
* Handle the removal of an element from the root page, when two of its children
* have been merged.
@@ -189,7 +191,7 @@ import java.util.LinkedList;
private RemoveResult<K, V> handleRootRemove( MergedWithSiblingResult<K, V> mergedResult, int pos, boolean found )
{
RemoveResult<K, V> removeResult = null;
-
+
// If the current node contains only one key, then the merged result will be
// the new root. Deal with this case
if ( nbElems == 1 )
@@ -208,6 +210,76 @@ import java.util.LinkedList;
/**
+ * Borrow an element from the right sibling, creating a new sibling with one
+ * less element and creating a new page where the element to remove has been
+ * deleted and the borrowed element added on the right.
+ *
+ * @param revision The new revision for all the pages
+ * @param sibling The right sibling
+ * @param pos The position of the element to remove
+ * @return The resulting pages
+ */
+ private DeleteResult<K, V> borrowFromRight( long revision, MergedWithSiblingResult<K, V> mergedResult,
+ Node<K, V> sibling, int pos )
+ {
+ // The sibling is on the right, borrow the leftmost element
+ Page<K, V> siblingChild = sibling.children[0];
+ K siblingKey = siblingChild.getKey( 0 );
+
+ // Create the new sibling, with one less element at the beginning
+ Node<K, V> newSibling = new Node<K, V>( btree, revision, sibling.getNbElems() - 1 );
+
+ // Copy the keys and children of the old sibling in the new sibling
+ System.arraycopy( sibling.keys, 1, newSibling.keys, 0, newSibling.getNbElems() );
+ System.arraycopy( sibling.children, 1, newSibling.children, 0, sibling.getNbElems() );
+
+ // Create the new page and add the new element at the end
+ // First copy the current node, with the same size
+ Node<K, V> newNode = new Node<K, V>( btree, revision, nbElems );
+
+ // Copy the keys and the values up to the insertion position
+ int index = Math.abs( pos );
+
+ if ( index < 2 )
+ {
+ System.arraycopy( keys, 1, newNode.keys, 0, nbElems - 1 );
+ newNode.keys[nbElems - 1] = siblingKey;
+
+ System.arraycopy( children, 2, newNode.children, 1, nbElems - 1 );
+ newNode.children[0] = mergedResult.getModifiedPage();
+ newNode.children[nbElems] = siblingChild;
+ }
+ else
+ {
+ System.arraycopy( keys, 0, newNode.keys, 0, index - 1 );
+
+ if ( index < nbElems )
+ {
+ System.arraycopy( keys, index + 1, newNode.keys, index, nbElems - 1 - index );
+ }
+
+ newNode.keys[newNode.nbElems - 1] = siblingKey;
+
+ System.arraycopy( children, 0, newNode.children, 0, index - 1 );
+ newNode.children[index - 1] = mergedResult.getModifiedPage();
+
+ if ( index < nbElems )
+ {
+ System.arraycopy( children, index + 1, newNode.children, index, nbElems - 1 - index );
+ }
+
+ newNode.children[index] = siblingChild;
+ }
+
+ // Create the result
+ DeleteResult<K, V> result = new BorrowedFromRightResult<K, V>( newNode, newSibling,
+ mergedResult.getRemovedElement(), siblingKey );
+
+ return result;
+ }
+
+
+ /**
* {@inheritDoc}
*/
public DeleteResult<K, V> delete( long revision, K key, Page<K, V> parent, int parentPos )
@@ -219,7 +291,7 @@ import java.util.LinkedList;
int index = pos;
Page<K, V> child = null;
DeleteResult<K, V> deleteResult = null;
-
+
if ( found )
{
index = -( pos + 1 );
@@ -231,19 +303,20 @@ import java.util.LinkedList;
child = children[pos];
deleteResult = child.delete( revision, key, this, pos );
}
-
+
// If the key is not present in the tree, we simply return
if ( deleteResult instanceof NotPresentResult )
{
// Nothing to do...
return deleteResult;
}
-
+
// If we just modified the child, return a modified page
if ( deleteResult instanceof RemoveResult )
{
- RemoveResult<K, V> removeResult = handleRemoveResult( (RemoveResult<K, V>)deleteResult, index, pos, found );
-
+ RemoveResult<K, V> removeResult = handleRemoveResult( ( RemoveResult<K, V> ) deleteResult, index, pos,
+ found );
+
return removeResult;
}
@@ -251,8 +324,9 @@ import java.util.LinkedList;
// the current page
if ( deleteResult instanceof BorrowedFromSiblingResult )
{
- RemoveResult<K, V> removeResult = handleBorrowedResult( (BorrowedFromSiblingResult<K, V>)deleteResult, pos );
-
+ RemoveResult<K, V> removeResult = handleBorrowedResult( ( BorrowedFromSiblingResult<K, V> ) deleteResult,
+ pos );
+
return removeResult;
}
@@ -260,18 +334,18 @@ import java.util.LinkedList;
// an element from the local page, and to deal with the result.
if ( deleteResult instanceof MergedWithSiblingResult )
{
- MergedWithSiblingResult<K, V> mergedResult = (MergedWithSiblingResult<K, V>)deleteResult;
+ MergedWithSiblingResult<K, V> mergedResult = ( MergedWithSiblingResult<K, V> ) deleteResult;
// If the parent is null, then this page is the root page.
if ( parent == null )
{
RemoveResult<K, V> result = handleRootRemove( mergedResult, pos, found );
-
+
return result;
}
// We have some parent. Check if the current page is not half full
- int halfSize = btree.pageSize/2;
+ int halfSize = btree.pageSize / 2;
if ( nbElems > halfSize )
{
@@ -280,7 +354,7 @@ import java.util.LinkedList;
// we return the new pivot (it will replace any instance of the removed
// key in its parents)
RemoveResult<K, V> result = removeKey( mergedResult, revision, pos );
-
+
return result;
}
else
@@ -288,9 +362,9 @@ import java.util.LinkedList;
// We will remove one element from a page that will have less than N/2 elements,
// which will lead to some reorganization : either we can borrow an element from
// a sibling, or we will have to merge two pages
- int siblingPos = selectSibling( (Node<K, V>)parent, parentPos );
+ int siblingPos = selectSibling( ( Node<K, V> ) parent, parentPos );
- Leaf<K, V> sibling = (Leaf<K, V>)((Node<K, V>)parent).children[siblingPos];
+ Node<K, V> sibling = ( Node<K, V> ) ( ( Node<K, V> ) parent ).children[siblingPos];
if ( sibling.getNbElems() > halfSize )
{
@@ -299,15 +373,15 @@ import java.util.LinkedList;
if ( siblingPos < parentPos )
{
//DeleteResult<K, V> result = borrowFromLeft( revision, sibling, pos );
-
- return null; //result;
+
+ return null;
}
else
{
// Borrow from the right
- //DeleteResult<K, V> result = borrowFromRight( revision, sibling, pos );
-
- return null; //result;
+ DeleteResult<K, V> result = borrowFromRight( revision, mergedResult, sibling, pos );
+
+ return result;
}
}
else
@@ -317,12 +391,12 @@ import java.util.LinkedList;
}
}
}
-
+
// We should never reach this point
return null;
}
-
-
+
+
/**
* The deletion in a children has moved an element from one of its sibling. The key
* is present in the current node.
@@ -339,14 +413,14 @@ import java.util.LinkedList;
if ( pos < 0 )
{
- pos = - ( pos + 1 );
+ pos = -( pos + 1 );
if ( borrowedResult.isFromRight() )
{
// Update the keys
newPage.keys[pos] = modifiedPage.getKey( 0 );
- newPage.keys[pos + 1] = modifiedSibling.getKey( 0 );
-
+ newPage.keys[pos + 1] = modifiedSibling.findLeftMost().getKey();
+
// Update the children
newPage.children[pos + 1] = modifiedPage;
newPage.children[pos + 2] = modifiedSibling;
@@ -355,7 +429,7 @@ import java.util.LinkedList;
{
// Update the keys
newPage.keys[pos] = modifiedPage.getKey( 0 );
-
+
// Update the children
newPage.children[pos] = modifiedSibling;
newPage.children[pos + 1] = modifiedPage;
@@ -366,8 +440,8 @@ import java.util.LinkedList;
if ( borrowedResult.isFromRight() )
{
// Update the keys
- newPage.keys[pos] = modifiedSibling.getKey( 0 );
-
+ newPage.keys[pos] = modifiedSibling.findLeftMost().getKey();
+
// Update the children
newPage.children[pos] = modifiedPage;
newPage.children[pos + 1] = modifiedSibling;
@@ -376,21 +450,21 @@ import java.util.LinkedList;
{
// Update the keys
newPage.keys[pos - 1] = modifiedPage.getKey( 0 );
-
+
// Update the children
newPage.children[pos - 1] = modifiedSibling;
newPage.children[pos] = modifiedPage;
}
}
-
+
// Modify the result and return
RemoveResult<K, V> removeResult = new RemoveResult<K, V>( newPage,
borrowedResult.getRemovedElement(), borrowedResult.getNewLeftMost() );
-
+
return removeResult;
}
-
-
+
+
/**
* Remove the key at a given position.
*
@@ -402,11 +476,11 @@ import java.util.LinkedList;
{
// First copy the current page, but remove one element in the copied page
Node<K, V> newNode = new Node<K, V>( btree, revision, nbElems - 1 );
-
+
K newLeftMost = null;
int index = Math.abs( pos ) - 2;
-
+
//
if ( index < 0 )
{
@@ -422,37 +496,31 @@ import java.util.LinkedList;
{
System.arraycopy( keys, 0, newNode.keys, 0, index );
}
-
+
newNode.keys[index] = mergedResult.getModifiedPage().getKey( 0 );
-
+
if ( index < nbElems - 2 )
{
System.arraycopy( keys, index + 2, newNode.keys, index + 1, nbElems - index - 2 );
}
-
+
// Copy the children
System.arraycopy( children, 0, newNode.children, 0, index + 1 );
-
+
newNode.children[index + 1] = mergedResult.getModifiedPage();
-
+
if ( index < nbElems - 2 )
{
System.arraycopy( children, index + 3, newNode.children, index + 2, nbElems - index - 2 );
}
}
-
- if ( newNode.keys[0] == mergedResult.getRemovedElement().getKey() )
- {
- newLeftMost = newNode.keys[0];
- }
- else
- {
- newLeftMost = mergedResult.getNewLeftMost();
- }
-
+
+ // Propagate the new leftmost
+ newLeftMost = mergedResult.getNewLeftMost();
+
// Create the result
RemoveResult<K, V> result = new RemoveResult<K, V>( newNode, mergedResult.getRemovedElement(), newLeftMost );
-
+
return result;
}
@@ -463,50 +531,50 @@ import java.util.LinkedList;
public V find( K key )
{
int pos = findPos( key );
-
+
if ( pos < 0 )
{
// Here, if we have found the key in the node, then we must go down into
// the right child, not the left one
- return children[- pos ].find( key );
+ return children[-pos].find( key );
}
else
{
return children[pos].find( key );
}
}
-
-
+
+
/**
* {@inheritDoc}
*/
public Cursor<K, V> browse( K key, Transaction<K, V> transaction, LinkedList<ParentPos<K, V>> stack )
{
int pos = findPos( key );
-
+
if ( pos < 0 )
{
pos = -pos;
}
-
+
// We first stack the current page
stack.push( new ParentPos<K, V>( this, pos ) );
-
+
return children[pos].browse( key, transaction, stack );
}
-
-
+
+
/**
* {@inheritDoc}
*/
public Cursor<K, V> browse( Transaction<K, V> transaction, LinkedList<ParentPos<K, V>> stack )
{
stack.push( new ParentPos<K, V>( this, 0 ) );
-
+
return children[0].browse( transaction, stack );
}
-
+
/**
* This method is used when we have to replace a child in a page when we have
* found the key in the tree (the value will be changed, so we have made
@@ -521,19 +589,19 @@ import java.util.LinkedList;
{
// Just copy the current page and update its revision
Page<K, V> newPage = copy( revision );
-
+
// Last, we update the children table of the newly created page
// to point on the modified child
- ((Node<K, V>)newPage).children[pos] = result.modifiedPage;
-
+ ( ( Node<K, V> ) newPage ).children[pos] = result.modifiedPage;
+
// We can return the result, where we update the modifiedPage,
// to avoid the creation of a new object
result.modifiedPage = newPage;
return result;
}
-
-
+
+
/**
* Add a new key into a copy of the current page at a given position. We return the
* modified page. The new page will have one more key than the current page.
@@ -549,7 +617,7 @@ import java.util.LinkedList;
{
// First copy the current page, but add one element in the copied page
Node<K, V> newNode = new Node<K, V>( btree, revision, nbElems + 1 );
-
+
// Deal with the special case of an empty page
if ( nbElems == 0 )
{
@@ -562,24 +630,24 @@ import java.util.LinkedList;
// Copy the keys and the children up to the insertion position
System.arraycopy( keys, 0, newNode.keys, 0, pos );
System.arraycopy( children, 0, newNode.children, 0, pos );
-
+
// Add the new key and children
newNode.keys[pos] = key;
newNode.children[pos] = leftPage;
newNode.children[pos + 1] = rightPage;
-
+
// And copy the remaining keys and children
System.arraycopy( keys, pos, newNode.keys, pos + 1, keys.length - pos );
System.arraycopy( children, pos + 1, newNode.children, pos + 2, children.length - pos - 1 );
}
-
+
// Create the result
InsertResult<K, V> result = new ModifyResult<K, V>( newNode, null );
-
+
return result;
}
-
-
+
+
/**
* Split a full page into two new pages, a left, a right and a pivot element. The new pages will
* each contains half of the original elements. <br/>
@@ -599,11 +667,11 @@ import java.util.LinkedList;
private InsertResult<K, V> addAndSplit( long revision, K pivot, Page<K, V> leftPage, Page<K, V> rightPage, int pos )
{
int middle = btree.pageSize >> 1;
-
+
// Create two new pages
Node<K, V> newLeftPage = new Node<K, V>( btree, revision, middle );
Node<K, V> newRightPage = new Node<K, V>( btree, revision, middle );
-
+
// Determinate where to store the new value
// If it's before the middle, insert the value on the left,
// the key in the middle will become the new pivot
@@ -612,12 +680,12 @@ import java.util.LinkedList;
// Copy the keys and the children up to the insertion position
System.arraycopy( keys, 0, newLeftPage.keys, 0, pos );
System.arraycopy( children, 0, newLeftPage.children, 0, pos );
-
+
// Add the new element
newLeftPage.keys[pos] = pivot;
newLeftPage.children[pos] = leftPage;
- newLeftPage.children[pos+1] = rightPage;
-
+ newLeftPage.children[pos + 1] = rightPage;
+
// And copy the remaining elements minus the new pivot
System.arraycopy( keys, pos, newLeftPage.keys, pos + 1, middle - pos - 1 );
System.arraycopy( children, pos + 1, newLeftPage.children, pos + 2, middle - pos - 1 );
@@ -625,10 +693,10 @@ import java.util.LinkedList;
// Copy the keys and the children in the right page
System.arraycopy( keys, middle, newRightPage.keys, 0, middle );
System.arraycopy( children, middle, newRightPage.children, 0, middle + 1 );
-
+
// Create the result
InsertResult<K, V> result = new SplitResult<K, V>( keys[middle - 1], newLeftPage, newRightPage );
-
+
return result;
}
else if ( pos == middle )
@@ -639,15 +707,15 @@ import java.util.LinkedList;
System.arraycopy( keys, 0, newLeftPage.keys, 0, middle );
System.arraycopy( children, 0, newLeftPage.children, 0, middle );
newLeftPage.children[middle] = leftPage;
-
+
// And process the right page now
System.arraycopy( keys, middle, newRightPage.keys, 0, middle );
System.arraycopy( children, middle + 1, newRightPage.children, 1, middle );
newRightPage.children[0] = rightPage;
-
+
// Create the result
InsertResult<K, V> result = new SplitResult<K, V>( pivot, newLeftPage, newRightPage );
-
+
return result;
}
else
@@ -655,28 +723,28 @@ import java.util.LinkedList;
// Copy the keys and the children up to the middle
System.arraycopy( keys, 0, newLeftPage.keys, 0, middle );
System.arraycopy( children, 0, newLeftPage.children, 0, middle + 1 );
-
+
// Copy the keys and the children in the right page up to the pos
System.arraycopy( keys, middle + 1, newRightPage.keys, 0, pos - middle - 1 );
System.arraycopy( children, middle + 1, newRightPage.children, 0, pos - middle - 1 );
-
+
// Add the new element
newRightPage.keys[pos - middle - 1] = pivot;
newRightPage.children[pos - middle - 1] = leftPage;
newRightPage.children[pos - middle] = rightPage;
-
+
// And copy the remaining elements minus the new pivot
System.arraycopy( keys, pos, newRightPage.keys, pos - middle, nbElems - pos );
System.arraycopy( children, pos + 1, newRightPage.children, pos + 1 - middle, nbElems - pos );
// Create the result
InsertResult<K, V> result = new SplitResult<K, V>( keys[middle], newLeftPage, newRightPage );
-
+
return result;
}
}
-
-
+
+
/**
* Copy the current page and all its keys, with a new revision.
*
@@ -691,12 +759,12 @@ import java.util.LinkedList;
System.arraycopy( keys, 0, newPage.keys, 0, nbElems );
// Copy the children
- System.arraycopy( children, 0, newPage.children, 0, nbElems + 1);
+ System.arraycopy( children, 0, newPage.children, 0, nbElems + 1 );
return newPage;
}
-
-
+
+
/**
* {@inheritDoc}
*/
@@ -704,8 +772,8 @@ import java.util.LinkedList;
{
return children[0].findLeftMost();
}
-
-
+
+
/**
* {@inheritDoc}
*/
@@ -721,11 +789,11 @@ import java.util.LinkedList;
public String toString()
{
StringBuilder sb = new StringBuilder();
-
+
sb.append( "Node[" );
sb.append( super.toString() );
- sb.append ( "] -> {" );
-
+ sb.append( "] -> {" );
+
if ( nbElems > 0 )
{
// Start with the first child
@@ -737,11 +805,11 @@ import java.util.LinkedList;
{
sb.append( children[0].getId() ).append( "-r" ).append( children[0].getRevision() );
}
-
+
for ( int i = 0; i < nbElems; i++ )
{
sb.append( "|<" ).append( keys[i] ).append( ">|" );
-
+
if ( children[i + 1] == null )
{
sb.append( "null" );
@@ -752,34 +820,34 @@ import java.util.LinkedList;
}
}
}
-
+
sb.append( "}" );
-
+
return sb.toString();
}
-
-
+
+
/**
* {@inheritDoc}
*/
public String dumpPage( String tabs )
{
StringBuilder sb = new StringBuilder();
-
+
if ( nbElems > 0 )
{
// Start with the first child
sb.append( children[0].dumpPage( tabs + " " ) );
-
+
for ( int i = 0; i < nbElems; i++ )
{
sb.append( tabs );
- sb.append ( "<" );
+ sb.append( "<" );
sb.append( keys[i] ).append( ">\n" );
sb.append( children[i + 1].dumpPage( tabs + " " ) );
}
}
-
+
return sb.toString();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@labs.apache.org
For additional commands, e-mail: commits-help@labs.apache.org