From aed5bc9d62d74ecfa08fbc18023e10782cf0a333 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 24 Apr 2009 20:34:14 +0000
Subject: [PATCH] Fix issue 3939: Wasteful memory allocation while sending search result entries.
---
opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java | 275 ++++++++++++++++++++++++++++++++++--------------------
1 files changed, 172 insertions(+), 103 deletions(-)
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
index 40f7a84..678f9f7 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/ldap/SearchResultEntryProtocolOp.java
@@ -45,6 +45,7 @@
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
import org.opends.server.types.ByteString;
import org.opends.server.types.DN;
import org.opends.server.types.Entry;
@@ -67,7 +68,13 @@
private LinkedList<LDAPAttribute> attributes;
// The DN for this search entry.
- private DN dn;
+ private final DN dn;
+
+ // The underlying search result entry.
+ private SearchResultEntry entry;
+
+ // The LDAP version (determines how attribute options are handled).
+ private final int ldapVersion;
@@ -79,8 +86,7 @@
*/
public SearchResultEntryProtocolOp(DN dn)
{
- this.dn = dn;
- this.attributes = new LinkedList<LDAPAttribute>();
+ this(dn, null, null, 3);
}
@@ -95,16 +101,7 @@
public SearchResultEntryProtocolOp(DN dn,
LinkedList<LDAPAttribute> attributes)
{
- this.dn = dn;
-
- if (attributes == null)
- {
- this.attributes = new LinkedList<LDAPAttribute>();
- }
- else
- {
- this.attributes = attributes;
- }
+ this(dn, attributes, null, 3);
}
@@ -118,7 +115,7 @@
*/
public SearchResultEntryProtocolOp(SearchResultEntry searchEntry)
{
- this(searchEntry,3);
+ this(searchEntry.getDN(), null, searchEntry, 3);
}
@@ -134,90 +131,20 @@
public SearchResultEntryProtocolOp(SearchResultEntry searchEntry,
int ldapVersion)
{
- this.dn = searchEntry.getDN();
+ this(searchEntry.getDN(), null, searchEntry, ldapVersion);
+ }
- attributes = new LinkedList<LDAPAttribute>();
- if (ldapVersion == 2)
- {
- // Merge attributes having the same type into a single
- // attribute.
- boolean needsMerge;
- Map<AttributeType, List<Attribute>> attrs = searchEntry
- .getUserAttributes();
- for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
- .entrySet())
- {
- needsMerge = true;
- if(attrList!=null && attrList.getValue().size()==1)
- {
- Attribute a = attrList.getValue().get(0);
- if(!a.hasOptions())
- {
- needsMerge = false;
- attributes.add(new LDAPAttribute(a));
- }
- }
-
- if(needsMerge)
- {
- AttributeBuilder builder = new AttributeBuilder(attrList.getKey());
- for (Attribute a : attrList.getValue())
- {
- builder.addAll(a);
- }
- attributes.add(new LDAPAttribute(builder.toAttribute()));
- }
- }
-
- attrs = searchEntry.getOperationalAttributes();
- for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
- .entrySet())
- {
- needsMerge = true;
-
- if(attrList!=null && attrList.getValue().size()==1)
- {
- Attribute a = attrList.getValue().get(0);
- if(!a.hasOptions())
- {
- needsMerge = false;
- attributes.add(new LDAPAttribute(a));
- }
- }
-
- if(needsMerge)
- {
- AttributeBuilder builder = new AttributeBuilder(attrList.getKey());
- for (Attribute a : attrList.getValue())
- {
- builder.addAll(a);
- }
- attributes.add(new LDAPAttribute(builder.toAttribute()));
- }
- }
- }
- else
- {
- // LDAPv3
- for (List<Attribute> attrList : searchEntry.getUserAttributes().values())
- {
- for (Attribute a : attrList)
- {
- attributes.add(new LDAPAttribute(a));
- }
- }
-
- for (List<Attribute> attrList : searchEntry.getOperationalAttributes()
- .values())
- {
- for (Attribute a : attrList)
- {
- attributes.add(new LDAPAttribute(a));
- }
- }
- }
+ // Generic constructor.
+ private SearchResultEntryProtocolOp(DN dn,
+ LinkedList<LDAPAttribute> attributes, SearchResultEntry searchEntry,
+ int ldapVersion)
+ {
+ this.dn = dn;
+ this.attributes = attributes;
+ this.entry = searchEntry;
+ this.ldapVersion = ldapVersion;
}
@@ -241,6 +168,102 @@
*/
public LinkedList<LDAPAttribute> getAttributes()
{
+ LinkedList<LDAPAttribute> tmp = attributes;
+ if (tmp == null)
+ {
+ tmp = new LinkedList<LDAPAttribute>();
+ if (entry != null)
+ {
+ if (ldapVersion == 2)
+ {
+ // Merge attributes having the same type into a single
+ // attribute.
+ boolean needsMerge;
+ Map<AttributeType, List<Attribute>> attrs =
+ entry.getUserAttributes();
+ for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
+ .entrySet())
+ {
+ needsMerge = true;
+
+ if (attrList != null && attrList.getValue().size() == 1)
+ {
+ Attribute a = attrList.getValue().get(0);
+ if (!a.hasOptions())
+ {
+ needsMerge = false;
+ tmp.add(new LDAPAttribute(a));
+ }
+ }
+
+ if (needsMerge)
+ {
+ AttributeBuilder builder =
+ new AttributeBuilder(attrList.getKey());
+ for (Attribute a : attrList.getValue())
+ {
+ builder.addAll(a);
+ }
+ tmp.add(new LDAPAttribute(builder.toAttribute()));
+ }
+ }
+
+ attrs = entry.getOperationalAttributes();
+ for (Map.Entry<AttributeType, List<Attribute>> attrList : attrs
+ .entrySet())
+ {
+ needsMerge = true;
+
+ if (attrList != null && attrList.getValue().size() == 1)
+ {
+ Attribute a = attrList.getValue().get(0);
+ if (!a.hasOptions())
+ {
+ needsMerge = false;
+ tmp.add(new LDAPAttribute(a));
+ }
+ }
+
+ if (needsMerge)
+ {
+ AttributeBuilder builder =
+ new AttributeBuilder(attrList.getKey());
+ for (Attribute a : attrList.getValue())
+ {
+ builder.addAll(a);
+ }
+ tmp.add(new LDAPAttribute(builder.toAttribute()));
+ }
+ }
+ }
+ else
+ {
+ // LDAPv3
+ for (List<Attribute> attrList : entry.getUserAttributes()
+ .values())
+ {
+ for (Attribute a : attrList)
+ {
+ tmp.add(new LDAPAttribute(a));
+ }
+ }
+
+ for (List<Attribute> attrList : entry
+ .getOperationalAttributes().values())
+ {
+ for (Attribute a : attrList)
+ {
+ tmp.add(new LDAPAttribute(a));
+ }
+ }
+ }
+ }
+
+ attributes = tmp;
+
+ // Since the attributes are mutable, null out the entry for consistency.
+ entry = null;
+ }
return attributes;
}
@@ -285,9 +308,33 @@
stream.writeOctetString(dn.toString());
stream.writeStartSequence();
- for(LDAPAttribute attr : attributes)
+ SearchResultEntry tmp = entry;
+ if (ldapVersion == 3 && tmp != null)
{
- attr.write(stream);
+ for (List<Attribute> attrList : tmp.getUserAttributes()
+ .values())
+ {
+ for (Attribute a : attrList)
+ {
+ writeAttribute(stream, a);
+ }
+ }
+
+ for (List<Attribute> attrList : tmp.getOperationalAttributes()
+ .values())
+ {
+ for (Attribute a : attrList)
+ {
+ writeAttribute(stream, a);
+ }
+ }
+ }
+ else
+ {
+ for (LDAPAttribute attr : getAttributes())
+ {
+ attr.write(stream);
+ }
}
stream.writeEndSequence();
@@ -309,9 +356,10 @@
dn.toString(buffer);
buffer.append(", attrs={");
- if (! attributes.isEmpty())
+ LinkedList<LDAPAttribute> tmp = getAttributes();
+ if (! tmp.isEmpty())
{
- Iterator<LDAPAttribute> iterator = attributes.iterator();
+ Iterator<LDAPAttribute> iterator = tmp.iterator();
iterator.next().toString(buffer);
while (iterator.hasNext())
@@ -355,7 +403,7 @@
buffer.append(" Attributes:");
buffer.append(EOL);
- for (LDAPAttribute attribute : attributes)
+ for (LDAPAttribute attribute : getAttributes())
{
attribute.toString(buffer, indent+4);
}
@@ -419,7 +467,7 @@
// Add the attributes to the buffer.
- for (LDAPAttribute a : attributes)
+ for (LDAPAttribute a : getAttributes())
{
String name = a.getAttributeType();
int nameLength = name.length();
@@ -495,6 +543,11 @@
public SearchResultEntry toSearchResultEntry()
throws LDAPException
{
+ if (entry != null)
+ {
+ return entry;
+ }
+
HashMap<ObjectClass,String> objectClasses =
new HashMap<ObjectClass,String>();
HashMap<AttributeType,List<Attribute>> userAttributes =
@@ -503,7 +556,7 @@
new HashMap<AttributeType,List<Attribute>>();
- for (LDAPAttribute a : attributes)
+ for (LDAPAttribute a : getAttributes())
{
Attribute attr = a.toAttribute();
AttributeType attrType = attr.getAttributeType();
@@ -570,10 +623,26 @@
}
}
-
Entry entry = new Entry(dn, objectClasses, userAttributes,
operationalAttributes);
return new SearchResultEntry(entry);
}
+
+
+
+ // Write an attribute without converting to an LDAPAttribute.
+ private void writeAttribute(ASN1Writer stream, Attribute a)
+ throws IOException
+ {
+ stream.writeStartSequence();
+ stream.writeOctetString(a.getNameWithOptions());
+ stream.writeStartSet();
+ for (AttributeValue value : a)
+ {
+ stream.writeOctetString(value.getValue());
+ }
+ stream.writeEndSequence();
+ stream.writeEndSequence();
+ }
}
--
Gitblit v1.10.0