You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by kr...@apache.org on 2008/08/01 17:24:35 UTC

svn commit: r681723 - /db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java

Author: kristwaa
Date: Fri Aug  1 08:24:34 2008
New Revision: 681723

URL: http://svn.apache.org/viewvc?rev=681723&view=rev
Log:
DERBY-3791: Excessive memory usage when fetching small Clobs.
Exploits length information (where available) to reduce memory overhead wrt buffering. This improvement will only affect small Clobs in the range 1 byte to 8 KB, the smaller the Clob the bigger the overhead reduction.
Patch file: derby-3791-2a-buffer-adjustments.diff

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java?rev=681723&r1=681722&r2=681723&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/UTF8Reader.java Fri Aug  1 08:24:34 2008
@@ -55,6 +55,8 @@
 public final class UTF8Reader extends Reader
 {
     private static final String READER_CLOSED = "Reader closed";
+    /** Maximum size in number of chars for the internal character buffer. */
+    private static final int MAXIMUM_BUFFER_SIZE = 8*1024; // 8 KB
 
     /** The underlying data stream. */
     private InputStream in;
@@ -82,7 +84,7 @@
     private final long maxFieldSize;    // characters
 
     /** Internal character buffer storing characters read from the stream. */
-    private final char[]   buffer = new char[8 * 1024];
+    private final char[]   buffer;
     /** The number of characters in the internal buffer. */
     private int            charactersInBuffer; // within buffer
     /** The position of the next character to read in the internal buffer. */
@@ -131,6 +133,7 @@
         parent.setupContextStack();
         try {
             synchronized (lock) { // Synchronize access to store.
+                this.in = in; // Note the possible reassignment below.
                 if (in instanceof PositionedStoreStream) {
                     this.positionedIn = (PositionedStoreStream)in;
                     // This stream is already buffered, and buffering it again
@@ -138,7 +141,6 @@
                     // implement a special buffered reader to buffer again.
                     // Note that buffering this UTF8Reader again, does not
                     // cause any trouble...
-                    this.in = in;
                     try {
                         this.positionedIn.resetStream();
                     } catch (StandardException se) {
@@ -146,8 +148,6 @@
                     }
                 } else {
                     this.positionedIn = null;
-                    // Buffer this for improved performance.
-                    this.in = new BufferedInputStream (in);
                 }
                 this.utfLen = readUnsignedShort();
                 // Even if we are reading the encoded length, the stream may
@@ -160,6 +160,16 @@
         } finally {
             parent.restoreContextStack();
         }
+        // Setup buffering.
+        int bufferSize = calculateBufferSize(utfLen, maxFieldSize);
+        this.buffer = new char[bufferSize];
+        if (this.positionedIn == null) {
+            // Buffer this for improved performance.
+            // Note that the stream buffers bytes, whereas the internal buffer
+            // buffers characters. In worst case, the stream buffer must be
+            // filled three times to fill the internal character buffer.
+            this.in = new BufferedInputStream(in, bufferSize);
+        }
     }
 
     /**
@@ -192,8 +202,13 @@
             // the stream and we can't pass that out as data to the user.
             SanityManager.ASSERT(!(in instanceof Resetable));
         }
+        int bufferSize = calculateBufferSize(streamSize, maxFieldSize);
+        this.buffer = new char[bufferSize];
         // Buffer this for improved performance.
-        this.in = new BufferedInputStream(in);
+        // Note that the stream buffers bytes, whereas the internal buffer
+        // buffers characters. In worst case, the stream buffer must be filled
+        // three times to fill the internal character buffer.
+        this.in = new BufferedInputStream(in, bufferSize);
     }
 
     /*
@@ -587,4 +602,25 @@
 
         return (ch1 << 8) + (ch2 << 0);
     }
+
+    /**
+     * Calculates an optimized buffer size.
+     * <p>
+     * The maximum size allowed is returned if the specified values don't give
+     * enough information to say a smaller buffer size is preferable.
+     *
+     * @param encodedSize data length in bytes
+     * @param maxFieldSize maximum data length in bytes
+     * @return An (sub)optimal buffer size.
+     */
+    private final int calculateBufferSize(long encodedSize, long maxFieldSize) {
+        int bufferSize = MAXIMUM_BUFFER_SIZE;
+        if (encodedSize > 0 && encodedSize < bufferSize) {
+            bufferSize = (int)encodedSize;
+        }
+        if (maxFieldSize > 0 && maxFieldSize < bufferSize) {
+            bufferSize = (int)maxFieldSize;
+        }
+        return bufferSize;
+    }
 }