Return-Path: Delivered-To: apmail-directory-commits-archive@www.apache.org Received: (qmail 44150 invoked from network); 18 Jul 2006 21:18:39 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 18 Jul 2006 21:18:39 -0000 Received: (qmail 39015 invoked by uid 500); 18 Jul 2006 21:18:39 -0000 Delivered-To: apmail-directory-commits-archive@directory.apache.org Received: (qmail 38968 invoked by uid 500); 18 Jul 2006 21:18:39 -0000 Mailing-List: contact commits-help@directory.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@directory.apache.org Delivered-To: mailing list commits@directory.apache.org Received: (qmail 38957 invoked by uid 99); 18 Jul 2006 21:18:39 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Jul 2006 14:18:39 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 18 Jul 2006 14:18:37 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id AD9701A981A; Tue, 18 Jul 2006 14:18:17 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r423256 - in /directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message: LockableAttributeImpl.java LockableAttributesImpl.java Date: Tue, 18 Jul 2006 21:18:17 -0000 To: commits@directory.apache.org From: elecharny@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060718211817.AD9701A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: elecharny Date: Tue Jul 18 14:18:16 2006 New Revision: 423256 URL: http://svn.apache.org/viewvc?rev=423256&view=rev Log: Total rewrite of those two classes. The goal was to add serialization methods to them, but the speed improvment obtained in this process woth the commit, even if the serialization is not included. Modified: directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributeImpl.java directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributesImpl.java Modified: directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributeImpl.java URL: http://svn.apache.org/viewvc/directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributeImpl.java?rev=423256&r1=423255&r2=423256&view=diff ============================================================================== --- directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributeImpl.java (original) +++ directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributeImpl.java Tue Jul 18 14:18:16 2006 @@ -18,6 +18,8 @@ import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import javax.naming.NamingEnumeration; import javax.naming.NamingException; @@ -25,6 +27,7 @@ import javax.naming.directory.Attribute; import javax.naming.directory.DirContext; +import org.apache.directory.shared.ldap.util.StringTools; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,11 +44,17 @@ private static final long serialVersionUID = -5158233254341746514L; - /** the name of the attribute */ - private final String id; + /** the name of the attribute, case sensitive */ + private final String upId; + /** In case we have only one value, just use this container */ + private Object value; + /** the list of attribute values */ - private final ArrayList list; + private List list; + + /** The number of values stored */ + private int size = 0; // ------------------------------------------------------------------------ @@ -61,8 +70,10 @@ */ public LockableAttributeImpl(final String id) { - this.id = id; - list = new ArrayList(); + upId = id; + value = null; + list = null; //new ArrayList(); + size = 0; } @@ -76,9 +87,10 @@ */ public LockableAttributeImpl(final String id, final Object value) { - this.id = id; - list = new ArrayList(); - list.add( value ); + upId = id; + list = null; // new ArrayList(); + this.value = value; //list.add( value ); + size = 1; } @@ -92,9 +104,11 @@ */ public LockableAttributeImpl(final String id, final byte[] value) { - this.id = id; - list = new ArrayList(); - list.add( value ); + upId = id; + list = null; //new ArrayList(); + this.value = value; + //list.add( value ); + size = 1; } @@ -107,10 +121,12 @@ * @param list * the list of values to start with */ - private LockableAttributeImpl(final String id, final ArrayList list) + private LockableAttributeImpl(final String id, final List list) { - this.id = id; + upId = id; this.list = list; + value = null; + size = (list != null ? list.size() : 0); } @@ -125,7 +141,35 @@ */ public NamingEnumeration getAll() { - return new IteratorNamingEnumeration( list.iterator() ); + if ( size < 2 ) + { + return new IteratorNamingEnumeration( new Iterator() + { + private boolean done = (size != 0); + + public boolean hasNext() + { + return done; + } + + public Object next() + { + done = false; + return value; + } + + public void remove() + { + value = null; + done = false; + size = 0; + } + }); + } + else + { + return new IteratorNamingEnumeration( list.iterator() ); + } } @@ -136,12 +180,18 @@ */ public Object get() { - if ( list.isEmpty() ) + if ( list == null ) + { + return value; + } + else if ( list.isEmpty() ) { return null; } - - return list.get( 0 ); + else + { + return list.get( 0 ); + } } @@ -152,7 +202,7 @@ */ public int size() { - return list.size(); + return size; } @@ -163,7 +213,7 @@ */ public String getID() { - return id; + return upId; } @@ -176,7 +226,17 @@ */ public boolean contains( Object attrVal ) { - return list.contains( attrVal ); + switch (size) + { + case 0 : + return false; + + case 1 : + return value == null ? attrVal == null : value.equals( attrVal ); + + default : + return list.contains( attrVal ); + } } @@ -191,7 +251,32 @@ */ public boolean add( Object attrVal ) { - return list.add( attrVal ); + boolean exists = false; + + switch ( size ) + { + case 0 : + value = attrVal; + size++; + return true; + + case 1 : + exists = value.equals( attrVal ); + + list = new ArrayList(); + list.add( value ); + list.add( attrVal ); + size++; + value = null; + return exists; + + default : + exists = list.contains( attrVal ); + + list.add( attrVal ); + size++; + return exists; + } } @@ -205,7 +290,28 @@ */ public boolean remove( Object attrVal ) { - return list.remove( attrVal ); + switch ( size ) + { + case 0 : + return false; + + case 1 : + value = null; + size--; + return true; + + case 2 : + list.remove( attrVal ); + value = list.get(0); + size = 1; + list = null; + return true; + + default : + list.remove( attrVal ); + size--; + return true; + } } @@ -214,7 +320,21 @@ */ public void clear() { - list.clear(); + switch ( size ) + { + case 0 : + return; + + case 1 : + value = null; + size = 0; + return; + + default : + list = null; + size = 0; + return; + } } @@ -248,8 +368,17 @@ */ public Object clone() { - ArrayList l_list = ( ArrayList ) list.clone(); - return new LockableAttributeImpl( id, l_list ); + switch ( size ) + { + case 0 : + return new LockableAttributeImpl( upId ); + + case 1 : + return new LockableAttributeImpl( upId, value ); + + default : + return new LockableAttributeImpl( upId, (List)((ArrayList)list).clone() ); + } } @@ -274,7 +403,17 @@ */ public Object get( int index ) { - return list.get( index ); + switch ( size ) + { + case 0 : + return null; + + case 1 : + return value; + + default : + return list.get( index ); + } } @@ -288,7 +427,21 @@ */ public Object remove( int index ) { - return list.remove( index ); + switch ( size ) + { + case 0 : + return null; + + case 1 : + Object result = value; + value = null; + size = 0; + return result; + + default : + size--; + return list.remove( index ); + } } @@ -303,7 +456,36 @@ */ public void add( int index, Object attrVal ) { - list.add( index, attrVal ); + switch ( size ) + { + case 0 : + size++; + value = attrVal; + return; + + case 1 : + list = new ArrayList(); + + if ( index == 0 ) + { + list.add( attrVal ); + list.add( value ); + } + else + { + list.add( value ); + list.add( attrVal ); + } + + size++; + value = null; + return; + + default : + list.add( index, attrVal ); + size++; + return; + } } @@ -318,7 +500,35 @@ */ public Object set( int index, Object attrVal ) { - return list.set( index, attrVal ); + switch ( size ) + { + case 0 : + size++; + value = attrVal; + return null; + + case 1 : + if ( index == 0 ) + { + Object result = value; + value = attrVal; + return result; + } + else + { + list = new ArrayList(); + list.add( value ); + list.add( attrVal ); + size = 2; + value = null; + return null; + } + + default : + Object oldValue = list.get( index ); + list.set( index, attrVal ); + return oldValue; + } } @@ -349,54 +559,112 @@ } Attribute attr = ( Attribute ) obj; - if ( !id.equals( attr.getID() ) ) + + if ( !upId.equals( attr.getID() ) ) { return false; } - if ( attr.size() != list.size() ) + if ( attr.size() != size ) { return false; } - // if ( attr.isOrdered() ) - // { - // for ( int ii = 0; ii < attr.size(); ii++ ) - // { - // try - // { - // if ( ! list.get( ii).equals( attr.get( ii ) ) ) - // { - // return false; - // } - // } - // catch ( NamingException e ) - // { - // log.warn( "Failed to get an attribute from the specifid attribute: " - // + attr, e ); - // return false; - // } - // } - // } - // else - // { - for ( int ii = 0; ii < attr.size(); ii++ ) + switch ( size ) { - try - { - if ( !list.contains( attr.get( ii ) ) ) + case 0 : + return true; + + case 1 : + try + { + return value.equals( attr.get( 0 ) ); + } + catch ( NamingException e ) { + log.warn( "Failed to get an attribute from the specifid attribute: " + attr, e ); return false; } - } - catch ( NamingException e ) - { - log.warn( "Failed to get an attribute from the specifid attribute: " + attr, e ); - return false; - } + + default : + for ( int i = 0; i < size; i++ ) + { + try + { + if ( !list.contains( attr.get( i ) ) ) + { + return false; + } + } + catch ( NamingException e ) + { + log.warn( "Failed to get an attribute from the specifid attribute: " + attr, e ); + return false; + } + } + + return true; } - // } - - return true; + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + + sb.append( "Attribute id : '" ).append( upId ).append( "', " ); + sb.append( " Values : ["); + + switch (size) + { + case 0 : + sb.append( "]\n" ); + break; + + case 1 : + if ( value instanceof String ) + { + sb.append( '\'' ).append( value ).append( '\'' ); + } + else + { + sb.append( StringTools.dumpBytes( (byte[])value ) ); + } + + sb.append( "]\n" ); + break; + + default : + boolean isFirst = true; + + Iterator values = list.iterator(); + + while ( values.hasNext() ) + { + Object v = values.next(); + + if ( isFirst == false ) + { + sb.append( ", " ); + } + else + { + isFirst = false; + } + + if ( v instanceof String ) + { + sb.append( '\'' ).append( v ).append( '\'' ); + } + else + { + sb.append( StringTools.dumpBytes( (byte[])v ) ); + } + } + + sb.append( "]\n" ); + break; + } + + return sb.toString(); } } Modified: directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributesImpl.java URL: http://svn.apache.org/viewvc/directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributesImpl.java?rev=423256&r1=423255&r2=423256&view=diff ============================================================================== --- directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributesImpl.java (original) +++ directory/branches/shared/optimization/ldap/src/main/java/org/apache/directory/shared/ldap/message/LockableAttributesImpl.java Tue Jul 18 14:18:16 2006 @@ -17,16 +17,16 @@ package org.apache.directory.shared.ldap.message; +import java.io.Serializable; import java.util.Map; import java.util.HashMap; import java.util.Iterator; -import javax.naming.NamingException; import javax.naming.NamingEnumeration; +import javax.naming.NamingException; import javax.naming.directory.Attribute; import javax.naming.directory.Attributes; - -import org.apache.directory.shared.ldap.util.ExceptionUtils; +import javax.naming.directory.BasicAttribute; /** @@ -35,13 +35,108 @@ * @author Apache Directory Project * @version $Rev$ */ -public class LockableAttributesImpl implements Attributes +public class LockableAttributesImpl implements Attributes, Serializable { - static final long serialVersionUID = -69864533495992471L; - - /** Map of user provided String ids to Attributes */ - private final Map map = new HashMap(); + static transient final long serialVersionUID = -69864533495992471L; + /** + * An holder to store couples + * + */ + private class Holder implements Serializable, Cloneable + { + static transient final long serialVersionUID = 1L; + + private String upId; + private Attribute attribute; + + private Holder( String upId, Attribute attribute ) + { + this.upId = upId; + this.attribute = attribute; + } + + public Object clone() throws CloneNotSupportedException + { + Holder clone = (Holder)super.clone(); + + clone.upId = upId; + clone.attribute = (Attribute)attribute.clone(); + + return clone; + } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + + sb.append( upId ).append( ": " ); + + sb.append( attribute ).append( '\n' ); + + return sb.toString(); + } + } + + /** + * An iterator which returns Attributes. + */ + public class AttributeIterator implements Iterator + { + private Iterator iterator; + + private AttributeIterator( LockableAttributesImpl attributes ) + { + iterator = attributes.keyMap.values().iterator(); + } + + /** + * Returns true if the iteration has more elements. (In other + * words, returns true if next would return an element + * rather than throwing an exception.) + * + * @return true if the iterator has more elements. + */ + public boolean hasNext() + { + return iterator.hasNext(); + } + + /** + * Returns the next element in the iteration. Calling this method + * repeatedly until the {@link #hasNext()} method returns false will + * return each element in the underlying collection exactly once. + * + * @return the next element in the iteration. + * @exception NoSuchElementException iteration has no more elements. + */ + public Object next() + { + return ((Holder)iterator.next()).attribute; + } + + /** + * + * Removes from the underlying collection the last element returned by the + * iterator (optional operation). This method can be called only once per + * call to next. The behavior of an iterator is unspecified if + * the underlying collection is modified while the iteration is in + * progress in any way other than by calling this method. + * + * @exception UnsupportedOperationException if the remove + * operation is not supported by this Iterator. + + * @exception IllegalStateException if the next method has not + * yet been called, or the remove method has already + * been called after the last call to the next + * method. + */ + public void remove() + { + iterator.remove(); + } + } + /** Cache of lowercase id Strings to mixed cased user provided String ids */ private Map keyMap; @@ -58,32 +153,87 @@ keyMap = new HashMap(); } - - /** - * Used by clone to create a LockableAttributes. - * - * @param map - * the primary user provided id to Attribute Map - * @param keyMap - * the canonical key to user provided id Map - */ - private LockableAttributesImpl(Map map, Map keyMap) + // ------------------------------------------------------------------------ + // Serialization methods + // + // We will try to minimize the cost of reading and writing objects to the + // disk. + // + // We need to save all the attributes stored into the 'map' object, and + // their associated User Provided value. + // Attributes are stored following this pattern : + // ( attributeType = (attribute value )* )* + // + // The streamed value will looks like : + // [nbAttrs:int] + // ( + // [length attributeType(i):int] [attributeType(i):String] + // [length attributeTypeUP(i):int] [attributeTypeUP(i):String] + // [attributeValues(i)] + // )* + // + // The attribute value is streamed by the LockableAttributeImpl class. + // ------------------------------------------------------------------------ + /*public void readObject( ObjectInputStream oi ) throws IOException, ClassNotFoundException { - this.keyMap = new HashMap(); - - if ( keyMap != null ) - { - this.keyMap.putAll( keyMap ); - } - - Iterator list = map.values().iterator(); - while ( list.hasNext() ) - { - Attribute attr = ( Attribute ) list.next(); - this.map.put( attr.getID(), attr.clone() ); - } - } - + oi.defaultReadObject(); + + // Read the map size + int size = oi.readInt(); + + keyMap = new HashMap( size ); + + for ( int i = 0; i < size(); i++ ) + { + int keySize = oi.readInt(); + char[] keyChars = new char[keySize]; + + for ( int j = 0; j < keySize; j++) + { + keyChars[j] = oi.readChar(); + } + + String upId = new String( keyChars ); + String key = upId.toLowerCase(); + + Attribute attribute = (LockableAttributeImpl)oi.readObject(); + + Holder holder = new Holder( upId, attribute); + + keyMap.put( key, holder ); + } + }*/ + + /** + * Write the Attribute to a stream + */ + /*private void writeObject( ObjectOutputStream oo ) throws IOException + { + oo.defaultWriteObject(); + + // Write the map size + oo.write( keyMap.size() ); + + Iterator keys = keyMap.keySet().iterator(); + + while ( keys.hasNext() ) + { + String key = (String)keys.next(); + Holder holder = (Holder)keyMap.get( key ); + + // Write the userProvided key + // No need to write the key, it will be + // rebuilt by the read operation + oo.write( holder.upId.length() ); + oo.writeChars( holder.upId ); + + // Recursively call the writeExternal metho + // of the attribute object + oo.writeObject( holder.attribute ); + } + + // That's it ! + }*/ // ------------------------------------------------------------------------ // javax.naming.directory.Attributes Interface Method Implementations @@ -108,7 +258,7 @@ */ public int size() { - return map.size(); + return keyMap.size(); } @@ -126,14 +276,15 @@ */ public Attribute get( String attrId ) { - String key = getUserProvidedId( attrId ); - - if ( key == null ) - { - return null; - } - - return ( Attribute ) map.get( key ); + if ( attrId != null ) + { + Holder holder = (Holder)keyMap.get( attrId.toLowerCase() ); + return holder != null ? holder.attribute : null; + } + else + { + return null; + } } @@ -149,7 +300,7 @@ */ public NamingEnumeration getAll() { - return new IteratorNamingEnumeration( map.values().iterator() ); + return new IteratorNamingEnumeration( new AttributeIterator( this ) ); } @@ -165,7 +316,17 @@ */ public NamingEnumeration getIDs() { - return new ArrayNamingEnumeration( map.keySet().toArray() ); + String[] ids = new String[keyMap.size()]; + + Iterator values = keyMap.values().iterator(); + int i = 0; + + while ( values.hasNext() ) + { + ids[i++] = ((Holder)values.next()).upId; + } + + return new ArrayNamingEnumeration( ids ); } @@ -185,14 +346,11 @@ */ public Attribute put( String attrId, Object val ) { - if ( get( attrId ) == null ) - { - setUserProvidedId( attrId ); - } - Attribute attr = new LockableAttributeImpl( attrId ); attr.add( val ); - map.put( attrId, attr ); + + String key = attrId.toLowerCase(); + keyMap.put( key, new Holder( attrId, attr) ); return attr; } @@ -205,25 +363,45 @@ * the character case of its attribute ids, the case of attr's * identifier is ignored. * @return The Attribute with the same ID as attr that was previous in this - * attribute set; null if no such attribute existed. + * attribute set; The new attr if no such attribute existed. * @see #remove */ public Attribute put( Attribute attr ) { - Attribute old = get( attr.getID() ); - - if ( old != null ) - { - map.remove( old.getID() ); - - if ( keyMap != null ) - { - keyMap.remove( old.getID().toLowerCase() ); - } + String key = attr.getID().toLowerCase(); + Attribute old = null; + Attribute newAttr = attr; + + if ( keyMap.containsKey( key ) ) + { + old = (Attribute)((Holder)keyMap.remove( key )).attribute; + } + else + { + old = attr; + } + + if ( attr instanceof BasicAttribute ) + { + newAttr = new LockableAttributeImpl( attr.getID() ); + + try + { + NamingEnumeration values = attr.getAll(); + + while ( values.hasMore() ) + { + Object value = values.next(); + newAttr.add( value ); + } + } + catch ( NamingException ne ) + { + // do nothing + } } - - map.put( attr.getID(), attr ); - setUserProvidedId( attr.getID() ); + + keyMap.put( key, new Holder( attr.getID(), newAttr ) ); return old; } @@ -241,16 +419,17 @@ */ public Attribute remove( String attrId ) { - Attribute old = get( attrId ); - - if ( old != null ) - { - map.remove( old.getID() ); - - if ( keyMap != null ) - { - keyMap.remove( old.getID().toLowerCase() ); - } + String key = attrId.toLowerCase(); + Attribute old = null; + + if ( keyMap.containsKey( key ) ) + { + Holder holder = (Holder)keyMap.remove( key ); + + if ( holder != null ) + { + old = holder.attribute; + } } return old; @@ -265,7 +444,27 @@ */ public Object clone() { - return new LockableAttributesImpl( map, keyMap ); + try + { + LockableAttributesImpl clone = (LockableAttributesImpl)super.clone(); + + clone.keyMap = (Map)((HashMap)keyMap).clone(); + + Iterator keys = keyMap.keySet().iterator(); + + while ( keys.hasNext() ) + { + String key = (String)keys.next(); + Holder holder = (Holder)keyMap.get( key ); + clone.keyMap.put( key, holder.clone() ); + } + + return clone; + } + catch ( CloneNotSupportedException cnse ) + { + return null; + } } @@ -278,27 +477,16 @@ { StringBuffer buf = new StringBuffer(); - Iterator attrs = map.values().iterator(); + Iterator attrs = keyMap.values().iterator(); + while ( attrs.hasNext() ) { - Attribute l_attr = ( Attribute ) attrs.next(); + Holder holder = (Holder)attrs.next(); + Attribute attr = holder.attribute; - try - { - NamingEnumeration l_values = l_attr.getAll(); - while ( l_values.hasMore() ) - { - Object l_value = l_values.next(); - buf.append( l_attr.getID() ); - buf.append( ": " ); - buf.append( l_value ); - buf.append( '\n' ); - } - } - catch ( NamingException e ) - { - buf.append( ExceptionUtils.getFullStackTrace( e ) ); - } + buf.append( holder.upId ); + buf.append( ": " ); + buf.append( attr ); } return buf.toString(); @@ -340,6 +528,7 @@ } NamingEnumeration list = attrs.getAll(); + while ( list.hasMoreElements() ) { Attribute attr = ( Attribute ) list.nextElement(); @@ -357,60 +546,5 @@ } return true; - } - - - // ------------------------------------------------------------------------ - // Utility Methods - // ------------------------------------------------------------------------ - - /** - * Sets the user provided key by normalizing it and adding a record into the - * keymap for future lookups. - * - * @param userProvidedId - * the id of the Attribute gotten from the attribute instance via - * getID(). - */ - private void setUserProvidedId( String userProvidedId ) - { - if ( keyMap == null ) - { - keyMap = new HashMap(); - keyMap.put( userProvidedId.toLowerCase(), userProvidedId ); - return; - } - - if ( keyMap.get( userProvidedId ) == null ) - { - keyMap.put( userProvidedId.toLowerCase(), userProvidedId ); - } - } - - - /** - * Gets the user provided key by looking it up using the normalized key in - * the key map. - * - * @param attrId - * the id of the Attribute in any case. - * @return the attribute id as it would be returned on a call to the - * Attribute's getID() method. - */ - private String getUserProvidedId( String attrId ) - { - // First check if it is correct form to save string creation below. - if ( map.containsKey( attrId ) ) - { - return attrId; - } - - if ( keyMap == null ) - { - keyMap = new HashMap(); - return null; - } - - return ( String ) keyMap.get( attrId.toLowerCase() ); } }