Author: xedin
Date: Mon Oct 31 19:33:58 2011
New Revision: 1195630

URL: http://svn.apache.org/viewvc?rev=1195630&view=rev
Log:
Avoid large array allocation for compressed chunk offsets
patch by Sylvain Lebresne; reviewed by Pavel Yaskevich for CASSANDRA-3432

Added:
    
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/utils/BigLongArray.java
Modified:
    cassandra/branches/cassandra-1.0/CHANGES.txt
    
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/io/compress/CompressionMetadata.java

Modified: cassandra/branches/cassandra-1.0/CHANGES.txt
URL: 
http://svn.apache.org/viewvc/cassandra/branches/cassandra-1.0/CHANGES.txt?rev=1195630&r1=1195629&r2=1195630&view=diff
==============================================================================
--- cassandra/branches/cassandra-1.0/CHANGES.txt (original)
+++ cassandra/branches/cassandra-1.0/CHANGES.txt Mon Oct 31 19:33:58 2011
@@ -4,7 +4,7 @@
  * Add timing information to cassandra-cli GET/SET/LIST queries 
(CASSANDRA-3326)
  * Cache for CompressionMetadata objects (CASSANDRA-3427)
  * synchronize BiMap of bootstrapping tokens (CASSANDRA-3417)
-
+ * Avoid large array allocation for compressed chunk offsets (CASSANDRA-3432)
 
 1.0.1
  * acquire references during index build to prevent delete problems

Modified: 
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/io/compress/CompressionMetadata.java
URL: 
http://svn.apache.org/viewvc/cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/io/compress/CompressionMetadata.java?rev=1195630&r1=1195629&r2=1195630&view=diff
==============================================================================
--- 
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/io/compress/CompressionMetadata.java
 (original)
+++ 
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/io/compress/CompressionMetadata.java
 Mon Oct 31 19:33:58 2011
@@ -27,6 +27,7 @@ import org.apache.cassandra.config.Confi
 import org.apache.cassandra.io.sstable.Component;
 import org.apache.cassandra.io.sstable.Descriptor;
 import org.apache.cassandra.io.util.FileUtils;
+import org.apache.cassandra.utils.BigLongArray;
 
 /**
  * Holds metadata about compressed file
@@ -35,7 +36,7 @@ public class CompressionMetadata
 {
     public final long dataLength;
     public final long compressedFileLength;
-    public final long[] chunkOffsets;
+    private final BigLongArray chunkOffsets;
     public final String indexFilePath;
     public final CompressionParameters parameters;
 
@@ -136,16 +137,16 @@ public class CompressionMetadata
      *
      * @throws java.io.IOException on any I/O error (except EOF).
      */
-    private long[] readChunkOffsets(DataInput input) throws IOException
+    private BigLongArray readChunkOffsets(DataInput input) throws IOException
     {
         int chunkCount = input.readInt();
-        long[] offsets = new long[chunkCount];
+        BigLongArray offsets = new BigLongArray(chunkCount);
 
-        for (int i = 0; i < offsets.length; i++)
+        for (int i = 0; i < chunkCount; i++)
         {
             try
             {
-                offsets[i] = input.readLong();
+                offsets.set(i, input.readLong());
             }
             catch (EOFException e)
             {
@@ -171,13 +172,13 @@ public class CompressionMetadata
         // position of the chunk
         int idx = (int) (position / parameters.chunkLength());
 
-        if (idx >= chunkOffsets.length)
+        if (idx >= chunkOffsets.size)
             throw new EOFException();
 
-        long chunkOffset = chunkOffsets[idx];
-        long nextChunkOffset = (idx + 1 == chunkOffsets.length)
+        long chunkOffset = chunkOffsets.get(idx);
+        long nextChunkOffset = (idx + 1 == chunkOffsets.size)
                                 ? compressedFileLength
-                                : chunkOffsets[idx + 1];
+                                : chunkOffsets.get(idx + 1);
 
         return new Chunk(chunkOffset, (int) (nextChunkOffset - chunkOffset - 
4)); // "4" bytes reserved for checksum
     }

Added: 
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/utils/BigLongArray.java
URL: 
http://svn.apache.org/viewvc/cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/utils/BigLongArray.java?rev=1195630&view=auto
==============================================================================
--- 
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/utils/BigLongArray.java
 (added)
+++ 
cassandra/branches/cassandra-1.0/src/java/org/apache/cassandra/utils/BigLongArray.java
 Mon Oct 31 19:33:58 2011
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.utils;
+
+/**
+ * A GC friendly long[].
+ * Allocating large arrays (that are not short-lived) generate fragmentation
+ * in old-gen space. This breaks such large long array into fixed size pages
+ * to avoid that problem.
+ */
+public class BigLongArray
+{
+    private static final int DEFAULT_PAGE_SIZE = 4096;
+
+    private final long[][] pages;
+    public final int size;
+
+    private final int pageSize;
+    private final int pageCount;
+
+    public BigLongArray(int size)
+    {
+        this(size, DEFAULT_PAGE_SIZE);
+    }
+
+    public BigLongArray(int size, int pageSize)
+    {
+        this.size = size;
+        this.pageSize = pageSize;
+
+        int lastPageSize = size % pageSize;
+        int fullPageCount = size / pageSize;
+        pageCount = fullPageCount + (lastPageSize == 0 ? 0 : 1);
+        pages = new long[pageCount][];
+
+        for (int i = 0; i < fullPageCount; ++i)
+            pages[i] = new long[pageSize];
+
+        if (lastPageSize != 0)
+            pages[pages.length - 1] = new long[lastPageSize];
+    }
+
+    public void set(int idx, long value)
+    {
+        if (idx < 0 || idx > size)
+            throw new IndexOutOfBoundsException(String.format("%d is not 
whithin [0, %d)", idx, size));
+
+        int page = idx / pageSize;
+        int pageIdx = idx % pageSize;
+        pages[page][pageIdx] = value;
+    }
+
+    public long get(int idx)
+    {
+        if (idx < 0 || idx > size)
+            throw new IndexOutOfBoundsException(String.format("%d is not 
whithin [0, %d)", idx, size));
+
+        int page = idx / pageSize;
+        int pageIdx = idx % pageSize;
+        return pages[page][pageIdx];
+    }
+}


Reply via email to