/** * Compares the contents retrieved from an InputStream to the provided contents. * * @return true when the contents exactly match */ public static boolean contentEquals(InputStream in, byte[] contents) throws IOException { final int contentLen = contents.length; final byte[] buff = BufferManager.getBytes(); try { int readPos = 0; while(readPos<contentLen) { int bytesRemaining = contentLen - readPos; int bytesRead = in.read(buff, 0, bytesRemaining > BufferManager.BUFFER_SIZE ? BufferManager.BUFFER_SIZE : bytesRemaining); if(bytesRead==-1) return false; // End of file int i=0; while(i<bytesRead) { if(buff[i++]!=contents[readPos++]) return false; } } // Next read must be end of file - otherwise file content longer than contents. return in.read()==-1; } finally { BufferManager.release(buff, false); } }
/** * Copies all information from one stream to another. Internally reuses thread-local * buffers to avoid initial buffer zeroing cost and later garbage collection overhead. * * @return the number of bytes copied * * @see BufferManager#getChars() */ public static long copy(Reader in, StringBuilder out) throws IOException { char[] buff = BufferManager.getChars(); try { long totalChars = 0; int numChars; while((numChars = in.read(buff, 0, BufferManager.BUFFER_SIZE))!=-1) { out.append(buff, 0, numChars); totalChars += numChars; } return totalChars; } finally { BufferManager.release(buff, false); } }
/** * Releases a {@code byte[]} that was obtained by a call to * {@code getBytes}. A buffer must not be released more than once. * * @param buffer the {@code byte[]} to release * @param zeroFill if the data in the buffer may be sensitive, it is best to zero-fill the buffer on release. */ public static void release(byte[] buffer, boolean zeroFill) { Deque<SoftReference<byte[]>> myBytes = bytes.get(); if(buffer.length != BUFFER_SIZE) throw new IllegalArgumentException(); assert !inQueue(myBytes, buffer); // Error if already in the buffer list if(zeroFill) { bytesZeroFills.getAndIncrement(); Arrays.fill(buffer, 0, BUFFER_SIZE, (byte)0); } myBytes.add(new SoftReference<byte[]>(buffer)); } private static boolean inQueue(Iterable<SoftReference<byte[]>> myBytes, byte[] buffer) {
@Override public void close() throws IOException { synchronized(this) { out.close(); if(buff!=null) { BufferManager.release(buff, false); buff=null; } } }
/** * Grows as-needed to fit the provided new capacity. * * @returns the possibly new buffer. */ private char[] getBuffer(int additional) throws IOException { long newLen = (long)length + additional; if(newLen > MAX_LENGTH) throw new IOException("Maximum buffer length is " + MAX_LENGTH + ", " + newLen + " requested"); char[] buf = this.buffer; int bufLen = buf.length; if(newLen > bufLen) { // Find the next power of two that will hold all of the contents int newBufLen = bufLen==0 ? BufferManager.BUFFER_SIZE : (bufLen << 1); while(newBufLen < newLen) { newBufLen <<= 1; } char[] newBuf = (newBufLen == BufferManager.BUFFER_SIZE) ? BufferManager.getChars() : new char[newBufLen]; System.arraycopy(buf, 0, newBuf, 0, length); // Recycle buffer if(bufLen == BufferManager.BUFFER_SIZE) { //BufferManager.release(buf, false); } buf = newBuf; this.buffer = buf; } return buf; }
/** * @deprecated May obtain greater performance by avoiding zero fill on non-sensitive data. */ @Deprecated public static void release(byte[] buffer) { release(buffer, true); }
/** * Copies all information from one stream to another. Internally reuses thread-local * buffers to avoid initial buffer zeroing cost and later garbage collection overhead. * * @return the number of bytes copied * * @see BufferManager#getBytes() */ public static long copy(InputStream in, OutputStream out, boolean flush) throws IOException { byte[] buff = BufferManager.getBytes(); try { long totalBytes = 0; int numBytes; while((numBytes = in.read(buff, 0, BufferManager.BUFFER_SIZE))!=-1) { out.write(buff, 0, numBytes); if(flush) out.flush(); totalBytes += numBytes; } return totalBytes; } finally { BufferManager.release(buff, false); } }
/** * Copies all information from one stream to another. Internally reuses thread-local * buffers to avoid initial buffer zeroing cost and later garbage collection overhead. * * @return the number of bytes copied * * @see BufferManager#getChars() */ public static long copy(Reader in, Writer out) throws IOException { char[] buff = BufferManager.getChars(); try { long totalChars = 0; int numChars; while((numChars = in.read(buff, 0, BufferManager.BUFFER_SIZE))!=-1) { out.write(buff, 0, numChars); totalChars += numChars; } return totalChars; } finally { BufferManager.release(buff, false); } }
/** * @deprecated May obtain greater performance by avoiding zero fill on non-sensitive data. */ @Deprecated public static void release(char[] buffer) { release(buffer, true); }
/** * Releases a {@code char[]} that was obtained by a call to * {@code getChars}. A buffer must not be released more than once. * * @param buffer the {@code char[]} to release * @param zeroFill if the data in the buffer may be sensitive, it is best to zero-fill the buffer on release. */ public static void release(char[] buffer, boolean zeroFill) { Deque<SoftReference<char[]>> myChars = chars.get(); if(buffer.length != BUFFER_SIZE) throw new IllegalArgumentException(); assert !inQueue(myChars, buffer); // Error if already in the buffer list if(zeroFill) { charsZeroFills.getAndIncrement(); Arrays.fill(buffer, 0, BUFFER_SIZE, (char)0); } myChars.add(new SoftReference<char[]>(buffer)); } private static boolean inQueue(Iterable<SoftReference<char[]>> myChars, char[] buffer) {
@Override public void serialize(char[] chars, OutputStream out) throws IOException { byte[] bytes = BufferManager.getBytes(); try { int len = chars.length; IoUtils.intToBuffer(len, bytes); out.write(bytes, 0, 4); int pos = 0; while(len>0) { int count = BufferManager.BUFFER_SIZE/2; if(len<count) count = len; for(int charsIndex=0, bytesIndex = 0; charsIndex<count; charsIndex++, bytesIndex+=2) { IoUtils.charToBuffer(chars[pos+charsIndex], bytes, bytesIndex); } out.write(bytes, 0, count*2); pos += count; len -= count; } } finally { BufferManager.release(bytes, false); } }
/** * Reads the contents of a File and returns as a String in the provided character set. * * @see #readFileAsString(java.io.File) */ public static String readFileAsString(File file, Charset charset) throws IOException { long len = file.length(); StringBuilder SB = len>0 && len<=Integer.MAX_VALUE ? new StringBuilder((int)len) : new StringBuilder(); Reader in = new InputStreamReader(new FileInputStream(file), charset); try { char[] buff = BufferManager.getChars(); try { int numChars; while((numChars = in.read(buff, 0, BufferManager.BUFFER_SIZE)) != -1) { SB.append(buff, 0, numChars); } } finally { BufferManager.release(buff, false); } } finally { in.close(); } return SB.toString(); } }
@Override protected void finalize() throws Throwable { if(buffer!=null) { BufferManager.release(buffer, false); buffer=null; } super.finalize(); } }
public static void main(String[] args) { try { if(args.length>0) { final byte[] buff = BufferManager.getBytes(); try { for (String filename : args) { long startTime = System.currentTimeMillis(); RandomAccessFile raf=new RandomAccessFile(filename, "r"); long length=raf.length(); try { for(long pos=1;pos<length;pos+=(1024*4096+4096)) { raf.seek(pos); raf.readFully(buff, 0, BufferManager.BUFFER_SIZE); } } finally { raf.close(); } System.out.println(filename+" scanned in "+BigDecimal.valueOf(System.currentTimeMillis()-startTime, 3)+" seconds"); } } finally { BufferManager.release(buff, false); } } else { System.err.println("Usage: BenchmarkCounterBlockDevice filename [filename] [...]"); } } catch(IOException err) { ErrorPrinter.printStackTraces(err); } } }
@Override public void close() throws IOException { isClosed = true; int len = this.length; if(len > 0) { if(len <= COPY_THEN_RECYCLE_LIMIT) { char[] oldBuf = buffer; this.buffer = Arrays.copyOf(oldBuf, len); if(oldBuf.length == BufferManager.BUFFER_SIZE) { BufferManager.release(oldBuf, false); } } } }
/** * Copies all information from one stream to an appendable. * * @return the number of bytes copied * * @see BufferManager#getChars() */ public static long copy(Reader in, Appendable out) throws IOException { if(in == null) throw new NullArgumentException("in"); if(out == null) throw new NullArgumentException("out"); char[] buff = BufferManager.getChars(); try { long totalChars = 0; int numChars; while((numChars = in.read(buff, 0, BufferManager.BUFFER_SIZE))!=-1) { out.append(new String(buff, 0, numChars)); totalChars += numChars; } return totalChars; } finally { BufferManager.release(buff, false); } }
@Override synchronized public void close() throws IOException { if(!isDone) { // Read the rest of the underlying stream int code; while((code=in.read())==AOServProtocol.NEXT) { int len=in.readShort(); while(len>0) { int skipped=(int)in.skip(len); len-=skipped; } } isDone=true; bufferFilled=bufferRead=0; if(buffer!=null) { BufferManager.release(buffer, false); buffer=null; } try { AOServProtocol.checkResult(code, in); } catch(SQLException err) { throw new IOException(err.toString()); } } }