### Eclipse Workspace Patch 1.0
#P lucene_trunk
Index: src/java/org/apache/lucene/index/SegmentReader.java
===================================================================
--- src/java/org/apache/lucene/index/SegmentReader.java	(revision 789387)
+++ src/java/org/apache/lucene/index/SegmentReader.java	(working copy)
@@ -116,6 +116,43 @@
     }
   }
   
+  // Static values used in Norm#See LUCENE - 1566 / SUN - 6478546
+  // size of the byte[] buffer used to read the segments norm values
+  private static final int SUN_6478546_BUFFER_SIZE;
+  // internal - loop condition
+  private static final int SUN_6478546_BUFFER_THRESHOLD;
+  // fast path threshold see #readBytes(byte[], int, int)
+  private static final int SUN_6478546_THRESHOLD;
+
+  private static final String SUN_6478546_BUFFER_SIZE_PROPERTY = "lucene_SUN_6478546-bufferSize";
+  private static final String SUN_6478546_THRESHOLD_PROPERTY = "lucene_SUN_6478546-threshold";
+
+  static {
+    // Read buffer-size and threshold from properties to enable users with large
+    // values to use the workaround
+    final int bufferSize = parseShiftProperty(SUN_6478546_BUFFER_SIZE_PROPERTY,
+        16);
+    SUN_6478546_BUFFER_SIZE = 1 << bufferSize;
+    SUN_6478546_BUFFER_THRESHOLD = Integer.MAX_VALUE
+        & (Integer.MAX_VALUE << bufferSize);
+    // defauts to 0 -- always use fast path
+    SUN_6478546_THRESHOLD = Integer.MAX_VALUE
+        & (Integer.MAX_VALUE << parseShiftProperty(
+            SUN_6478546_THRESHOLD_PROPERTY, 31));
+  }
+
+  private static int parseShiftProperty(final String property, int defaultValue) {
+    try {
+      final int value = Integer.parseInt(System.getProperty(property, Integer
+          .toString(defaultValue)));
+      if (value > 31 || value < defaultValue)
+        return defaultValue;
+      return value;
+    } catch (NumberFormatException e) {
+      return defaultValue;
+    }
+  }
+  
   /**
    * Byte[] referencing is used because a new norm object needs 
    * to be created for each clone, and the byte array is all 
@@ -208,10 +245,41 @@
           origNorm.bytes(bytesOut, offset, len);
         } else {
           // We are orig -- read ourselves from disk:
-          synchronized(in) {
-            in.seek(normSeek);
-            in.readBytes(bytesOut, offset, len, false);
+          readBytes(bytesOut, offset, len);
+        }
+      }
+    }
+    
+    private void readBytes(byte[] bytesOut, int offset, int length) throws IOException{
+      assert bytesOut.length >= (offset+length);
+      synchronized(in) {
+        in.seek(normSeek);
+        /*
+         * LUCENE-1566 / SUN-6478546 JVM bug present in 32 bit VM > 1.5
+         * Passing a very large array (e.g. > 200 MB) in combination with
+         * a large Xmx (e.g. 1400M) value to RandomAccess or InputStream #read 
+         * causes an incorrect OOM error.
+         * This is not a Lucene Bug but affects lots of users running 32bit JVMs.
+         */
+        if ((length & SUN_6478546_THRESHOLD) == 0) {
+          // fast path if the segments norm array is less than the threshold
+          in.readBytes(bytesOut, offset, length, false);
+        } else {
+          /*
+           * if the segments norm array length is > than the threshold 
+           * we read the bytes in a buffer first and copy it to the given bytes array.
+           */
+          int bytesLeft = length;
+          int bytesRead = offset;
+          final byte[] buffer = new byte[SUN_6478546_BUFFER_SIZE];
+          while ((bytesLeft & SUN_6478546_BUFFER_THRESHOLD) != 0) {
+            in.readBytes(buffer, 0, SUN_6478546_BUFFER_SIZE, false);
+            System.arraycopy(buffer, 0, bytesOut, bytesRead, SUN_6478546_BUFFER_SIZE);
+            bytesLeft -= SUN_6478546_BUFFER_SIZE;
+            bytesRead += SUN_6478546_BUFFER_SIZE;
           }
+          in.readBytes(buffer, 0, bytesLeft, false);
+          System.arraycopy(buffer, 0, bytesOut, bytesRead, bytesLeft);
         }
       }
     }
@@ -244,10 +312,7 @@
           assert in != null;
 
           // Read from disk.
-          synchronized(in) {
-            in.seek(normSeek);
-            in.readBytes(bytes, 0, count, false);
-          }
+          readBytes(bytes, 0, count);
 
           bytesRef = new Ref();
           closeInput();
