Coverage Report - org.galagosearch.core.index.BackedCompressedByteBuffer
 
Classes in this File Line Coverage Branch Coverage Complexity
BackedCompressedByteBuffer
80%
37/46
50%
6/12
0
BackedCompressedByteBuffer$BufferInputStream
89%
47/53
69%
22/32
0
 
 1  
 // BSD License (http://www.galagosearch.org/license)
 2  
 
 3  
 package org.galagosearch.core.index;
 4  
 
 5  
 import java.io.ByteArrayInputStream;
 6  
 import java.io.File;
 7  
 import java.io.FileInputStream;
 8  
 import java.io.FileOutputStream;
 9  
 import java.io.IOException;
 10  
 import java.io.InputStream;
 11  
 import java.io.OutputStream;
 12  
 import java.util.ArrayList;
 13  
 import org.galagosearch.tupleflow.Utility;
 14  
 
 15  
 /**
 16  
  * A BackedCompressedByteBuffer is like a CompressedByteBuffer,
 17  
  * but it can overflow into disk storage if necessary.  Unlike a 
 18  
  * CompressedByteBuffer, there's no getBytes() method since that 
 19  
  * wouldn't makes sense if all the data is on disk.
 20  
  *
 21  
  * @author trevor
 22  
  */
 23  
 public class BackedCompressedByteBuffer {
 24  
     ArrayList<File> segments;
 25  
     CompressedByteBuffer buffer;
 26  
     long diskLength;
 27  
     long threshold;
 28  
 
 29  
     /** Creates a new instance of BackedCompressedByteBuffer */
 30  216
     public BackedCompressedByteBuffer(long threshold) {
 31  216
         buffer = new CompressedByteBuffer();
 32  216
         segments = new ArrayList<File>();
 33  216
         this.threshold = threshold;
 34  216
     }
 35  
 
 36  
     public BackedCompressedByteBuffer() {
 37  216
         this(1024 * 1024);
 38  216
     }
 39  
 
 40  
     public void add(long value) throws IOException {
 41  724
         buffer.add(value);
 42  
 
 43  724
         if (buffer.length() > threshold) {
 44  0
             flush();
 45  
         }
 46  724
     }
 47  
 
 48  
     public void add(CompressedByteBuffer other) throws IOException {
 49  0
         if (other.length() > threshold) {
 50  0
             flush();
 51  0
             flushBuffer(other);
 52  
         } else {
 53  0
             buffer.add(other);
 54  
         }
 55  0
     }
 56  
 
 57  
     public void addFloat(float f) throws IOException {
 58  64
         buffer.addFloat(f);
 59  
 
 60  64
         if (buffer.length() > threshold) {
 61  0
             flush();
 62  
         }
 63  64
     }
 64  
 
 65  
     public void addRaw(int b) throws IOException {
 66  64
         buffer.addRaw(b);
 67  
 
 68  64
         if (buffer.length() > threshold) {
 69  0
             flush();
 70  
         }
 71  64
     }
 72  
 
 73  
     public void write(OutputStream stream) throws IOException {
 74  188
         for (File f : segments) {
 75  12
             Utility.copyFileToStream(f, stream);
 76  
         }
 77  
 
 78  188
         buffer.write(stream);
 79  188
     }
 80  
 
 81  
     public void flush() throws IOException {
 82  24
         flushBuffer(buffer);
 83  24
         buffer.clear();
 84  24
     }
 85  
 
 86  
     void flushBuffer(CompressedByteBuffer other) throws IOException {
 87  24
         File file = Utility.createTemporary();
 88  24
         FileOutputStream stream = new FileOutputStream(file);
 89  24
         other.write(stream);
 90  24
         stream.close();
 91  24
         diskLength += buffer.length();
 92  24
         segments.add(file);
 93  24
     }
 94  
 
 95  
     public long length() {
 96  1224
         return diskLength + buffer.length();
 97  
     }
 98  
 
 99  
     public void clear() {
 100  168
         for (File f : segments) {
 101  0
             f.delete();
 102  
         }
 103  168
         segments.clear();
 104  168
         buffer.clear();
 105  168
         diskLength = 0;
 106  168
     }
 107  
 
 108  
     public BufferInputStream getInputStream() throws IOException {
 109  20
         return new BufferInputStream();
 110  
     }
 111  
 
 112  
     public class BufferInputStream extends InputStream {
 113  20
         InputStream current = null;
 114  20
         int fileSegment = -1;
 115  
 
 116  20
         BufferInputStream() throws IOException {
 117  20
             this.nextStream();
 118  20
         }
 119  
 
 120  
         private boolean nextStream() throws IOException {
 121  44
             if (fileSegment < segments.size() - 1) {
 122  12
                 if (current != null) {
 123  8
                     current.close();
 124  
                 }
 125  12
                 fileSegment++;
 126  12
                 current = new FileInputStream(segments.get(fileSegment));
 127  12
                 return true;
 128  32
             } else if (fileSegment == segments.size() - 1) {
 129  20
                 current = new ByteArrayInputStream(buffer.getBytes(), 0, buffer.length());
 130  20
                 fileSegment++;
 131  20
                 return true;
 132  
             } else {
 133  12
                 current = null;
 134  12
                 return false;
 135  
             }
 136  
         }
 137  
 
 138  
         @Override
 139  
         public int available() throws IOException {
 140  12
             if (current == null) {
 141  0
                 return 0;
 142  
             }
 143  12
             if (current instanceof ByteArrayInputStream) {
 144  8
                 return current.available();
 145  
             }
 146  4
             long total = 0;
 147  12
             for (int i = fileSegment + 1; i < segments.size(); i++) {
 148  8
                 File f = segments.get(i);
 149  8
                 total += f.length();
 150  
             }
 151  
 
 152  4
             total += buffer.length();
 153  4
             total += current.available();
 154  
 
 155  4
             if (total > Integer.MAX_VALUE) {
 156  0
                 return Integer.MAX_VALUE;
 157  
             }
 158  4
             return (int) total;
 159  
         }
 160  
 
 161  
         @Override
 162  
         public void close() throws IOException {
 163  4
             if (current != null) {
 164  4
                 current.close();
 165  
             }
 166  4
         }
 167  
 
 168  
         @Override
 169  
         public int read(byte[] arg) throws IOException {
 170  12
             return read(arg, 0, arg.length);
 171  
         }
 172  
 
 173  
         @Override
 174  
         public int read(byte[] arg, int offset, int length) throws IOException {
 175  12
             if (current == null) {
 176  0
                 return -1;
 177  
             }
 178  12
             int result = current.read(arg, offset, length);
 179  12
             int total = 0;
 180  
 
 181  24
             while (total < length) {
 182  24
                 if (result >= 0) {
 183  24
                     total += result;
 184  
                 }
 185  
 
 186  24
                 if (nextStream() == false) {
 187  12
                     if (total > 0) {
 188  12
                         return total;
 189  
                     } else {
 190  0
                         return result;
 191  
                     }
 192  
                 }
 193  
 
 194  12
                 result = current.read(arg, offset + total, length - total);
 195  
             }
 196  
 
 197  0
             return total;
 198  
         }
 199  
 
 200  
         public int read() throws IOException {
 201  32
             if (current == null) {
 202  4
                 return -1;
 203  
             }
 204  28
             int result = current.read();
 205  
 
 206  28
             while (result < 0 && nextStream()) {
 207  0
                 result = current.read();
 208  
             }
 209  28
             return result;
 210  
         }
 211  
     }
 212  
 }