From 51c3e1286d7923eb2ecbc97aade9d2cf5faa22b7 Mon Sep 17 00:00:00 2001
From: Michael Glavassevich <mrglavas@apache.org>
Date: Tue, 9 Aug 2011 14:51:31 +0000
Subject: [PATCH] JIRA Issue #1521:
 http://issues.apache.org/jira/browse/XERCESJ-1521. Compact the
 SoftReferenceSymbolTable if after cleaning out cleared SoftReferences the
 number of symbols drops below 25% of the table's load factor threshold.

git-svn-id: https://svn.apache.org/repos/asf/xerces/java/trunk@1155386 13f79535-47bb-0310-9956-ffa450edef68
---
 .../xerces/util/SoftReferenceSymbolTable.java | 40 ++++++++++++++-----
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/src/org/apache/xerces/util/SoftReferenceSymbolTable.java b/src/org/apache/xerces/util/SoftReferenceSymbolTable.java
index aebe2f449..542bfb7da 100644
--- a/src/org/apache/xerces/util/SoftReferenceSymbolTable.java
+++ b/src/org/apache/xerces/util/SoftReferenceSymbolTable.java
@@ -200,12 +200,26 @@ public String addSymbol(char[] buffer, int offset, int length) {
      * and load factor. 
      */
     protected void rehash() {
-
-        int oldCapacity = fBuckets.length;
-        SREntry[] oldTable = fBuckets;
-
-        int newCapacity = oldCapacity * 2 + 1;
-        SREntry[] newTable = new SREntry[newCapacity];
+        rehashCommon(fBuckets.length * 2 + 1);
+    }
+    
+    /**
+     * Reduces the capacity of and internally reorganizes this 
+     * SymbolTable, in order to accommodate and access its entries in
+     * a more memory efficient way. This method is called automatically when 
+     * the number of keys in the SymbolTable drops below 25% of this
+     * hashtable's load factor (as a result of SoftReferences which have
+     * been cleared).
+     */
+    protected void compact() {
+        rehashCommon(((int) (fCount / fLoadFactor)) * 2 + 1);
+    }
+    
+    private void rehashCommon(final int newCapacity) {
+        
+        final int oldCapacity = fBuckets.length;
+        final SREntry[] oldTable = fBuckets;
+        final SREntry[] newTable = new SREntry[newCapacity];
 
         fThreshold = (int)(newCapacity * fLoadFactor);
         fBuckets = newTable;
@@ -312,9 +312,17 @@ public class SoftReferenceSymbolTable ex
      */
     private void clean() {
         SREntry entry = (SREntry)fReferenceQueue.poll();
-        while (entry != null) {
-            removeEntry(entry);
-            entry = (SREntry)fReferenceQueue.poll();
+        if (entry != null) {
+            do {
+                removeEntry(entry);
+                entry = (SREntry)fReferenceQueue.poll();
+            }
+            while (entry != null);
+            // Reduce the number of buckets if the number of items
+            // in the table has dropped below 25% of the threshold.
+            if (fCount < (fThreshold >> 2)) {
+                compact();
+            }
         }
     }
         
