private void freeSliceBuffer(DirectByteBuffer ddb) { if (ddb instanceof sliceDBB) { int slice_index = getSliceIndex(ddb.getBufferInternal().capacity()); List my_slice_entries = slice_entries[slice_index]; synchronized (my_slice_entries) { my_slice_entries.add(0, ((sliceDBB) ddb).getSliceBuffer()); } } }
/** Return the given buffer to the appropriate pool. */ protected void returnBufferSupport(DirectByteBuffer ddb) { ByteBuffer buff = ddb.getBufferInternal(); if (buff == null) { Debug.out("Returned dbb has null delegate"); throw (new RuntimeException("Returned dbb has null delegate")); } int capacity = buff.capacity(); bytesIn += capacity; if (DEBUG_TRACK_HANDEDOUT) { synchronized (handed_out) { if (handed_out.remove(buff) == null) { Debug.out("buffer not handed out"); throw (new RuntimeException("Buffer not handed out")); } // System.out.println( "[" + handed_out.size() + "] <- " + buffer + ", bytesIn = " + bytesIn // + ", bytesOut = " + bytesOut ); } } // remInUse( buffer.capacity() ); if (capacity <= SLICE_END_SIZE) { freeSliceBuffer(ddb); } else { Integer buffSize = new Integer(capacity); ArrayList bufferPool = (ArrayList) buffersMap.get(buffSize); if (bufferPool != null) { // no need to sync around 'poolsLock', as adding during compaction is ok synchronized (bufferPool) { bufferPool.add(buff); } } else { Debug.out("Invalid buffer given; could not find proper buffer pool"); } } }
private int preReadProcess(int allowed) { if (allowed < 1) { Debug.out("allowed < 1"); } decode_array[0] = payload_buffer == null ? null : payload_buffer.getBuffer( SS); // ensure the decode array has the latest payload pointer int bytes_available = 0; boolean shrink_remaining_buffers = false; int start_buff = reading_length_mode ? 1 : 0; boolean marked = false; for (int i = start_buff; i < 2; i++) { // set buffer limits according to bytes allowed ByteBuffer bb = decode_array[i]; if (bb == null) { Debug.out("preReadProcess:: bb[" + i + "] == null, decoder destroyed=" + destroyed); throw (new RuntimeException("decoder destroyed")); } if (shrink_remaining_buffers) { bb.limit(0); // ensure no read into this next buffer is possible } else { int remaining = bb.remaining(); if (remaining < 1) continue; // skip full buffer if (!marked) { pre_read_start_buffer = i; pre_read_start_position = bb.position(); marked = true; } if (remaining > allowed) { // read only part of this buffer bb.limit(bb.position() + allowed); // limit current buffer bytes_available += bb.remaining(); shrink_remaining_buffers = true; // shrink any tail buffers } else { // full buffer is allowed to be read bytes_available += remaining; allowed -= remaining; // count this buffer toward allowed and move on to the next } } } return bytes_available; }
public void readCompleted(DiskManagerReadRequest request, DirectByteBuffer data) { try { lock_mon.enter(); if (!loading_messages.contains(request) || destroyed) { // was canceled data.returnToPool(); return; } loading_messages.remove(request); BTPiece msg = new BTPiece(request.getPieceNumber(), request.getOffset(), data, piece_version); queued_messages.put(msg, request); outgoing_message_queue.addMessage(msg, true); } finally { lock_mon.exit(); } outgoing_message_queue.doListenerNotifications(); }
public class BTMessageDecoder implements MessageStreamDecoder { private static final int MIN_MESSAGE_LENGTH = 1; // for type id // private static final int MAX_MESSAGE_LENGTH = 16*1024+128; //should never be > 16KB+9B, as we // never request chunks > 16KB - update, some LT extensions can be bigger private static final int MAX_MESSAGE_LENGTH = 128 * 1024; // 17/5/2013: parg: got a huge torrent with so many pieces the bitfield exceeds // the above limit... private static final int HANDSHAKE_FAKE_LENGTH = 323119476; // (byte)19 + "Bit" readInt() value of header private static final byte SS = DirectByteBuffer.SS_MSG; private DirectByteBuffer payload_buffer = null; private final DirectByteBuffer length_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG, 4); private final ByteBuffer[] decode_array = new ByteBuffer[] {null, length_buffer.getBuffer(SS)}; private boolean reading_length_mode = true; private boolean reading_handshake_message = false; private int message_length; private int pre_read_start_buffer; private int pre_read_start_position; private boolean last_received_was_keepalive = false; private volatile boolean destroyed = false; private volatile boolean is_paused = false; private ArrayList messages_last_read = new ArrayList(); private int protocol_bytes_last_read = 0; private int data_bytes_last_read = 0; private int percent_complete = -1; public BTMessageDecoder() { /* nothing */ } public int performStreamDecode(Transport transport, int max_bytes) throws IOException { try { protocol_bytes_last_read = 0; data_bytes_last_read = 0; int bytes_remaining = max_bytes; while (bytes_remaining > 0) { if (destroyed) { // destruction currently isn't thread safe so one thread can destroy the decoder (e.g. // when closing a connection) // while the read-controller is still actively processing the us // throw( new IOException( "BTMessageDecoder already destroyed" )); break; } if (is_paused) { break; } int bytes_possible = preReadProcess(bytes_remaining); if (bytes_possible < 1) { Debug.out("ERROR BT: bytes_possible < 1"); break; } if (reading_length_mode) { transport.read(decode_array, 1, 1); // only read into length buffer } else { transport.read( decode_array, 0, 2); // read into payload buffer, and possibly next message length } int bytes_read = postReadProcess(); bytes_remaining -= bytes_read; if (bytes_read < bytes_possible) { break; } if (reading_length_mode && last_received_was_keepalive) { // hack to stop a 0-byte-read after receiving a keep-alive message // otherwise we won't realize there's nothing left on the line until trying to read again last_received_was_keepalive = false; break; } } return max_bytes - bytes_remaining; } catch (NullPointerException e) { // due to lack of synchronization here the buffers can be nullified by a concurrent 'destroy' // turn this into something less scarey throw (new IOException("Decoder has most likely been destroyed")); } } public int getPercentDoneOfCurrentMessage() { return percent_complete; } public Message[] removeDecodedMessages() { if (messages_last_read.isEmpty()) return null; Message[] msgs = (Message[]) messages_last_read.toArray(new Message[messages_last_read.size()]); messages_last_read.clear(); return msgs; } public int getProtocolBytesDecoded() { return protocol_bytes_last_read; } public int getDataBytesDecoded() { return data_bytes_last_read; } public ByteBuffer destroy() { if (destroyed) { Debug.out("Trying to redestroy message decoder, stack trace follows: " + this); Debug.outStackTrace(); } is_paused = true; destroyed = true; // there's a concurrency issue with the decoder whereby it can be destroyed while will being // messed with. Don't // have the energy to look into it properly atm so just try to ensure that it doesn't bork too // badly (parg: 29/04/2012) // only occasional but does have potential to generate direct buffer mem leak ;( int lbuff_read = 0; int pbuff_read = 0; length_buffer.limit(SS, 4); DirectByteBuffer plb = payload_buffer; if (reading_length_mode) { lbuff_read = length_buffer.position(SS); } else { // reading payload length_buffer.position(SS, 4); lbuff_read = 4; pbuff_read = plb == null ? 0 : plb.position(SS); } ByteBuffer unused = ByteBuffer.allocate(lbuff_read + pbuff_read); // TODO convert to direct? length_buffer.flip(SS); unused.put(length_buffer.getBuffer(SS)); try { if (plb != null) { plb.flip(SS); unused.put( plb.getBuffer( SS)); // Got a buffer overflow exception here in the past - related to PEX? } } catch (RuntimeException e) { Debug.out("hit known threading issue"); } unused.flip(); length_buffer.returnToPool(); if (plb != null) { plb.returnToPool(); payload_buffer = null; } try { for (int i = 0; i < messages_last_read.size(); i++) { Message msg = (Message) messages_last_read.get(i); msg.destroy(); } } catch (RuntimeException e) { // happens if messages modified by alt thread... Debug.out("hit known threading issue"); } messages_last_read.clear(); return unused; } private int preReadProcess(int allowed) { if (allowed < 1) { Debug.out("allowed < 1"); } decode_array[0] = payload_buffer == null ? null : payload_buffer.getBuffer( SS); // ensure the decode array has the latest payload pointer int bytes_available = 0; boolean shrink_remaining_buffers = false; int start_buff = reading_length_mode ? 1 : 0; boolean marked = false; for (int i = start_buff; i < 2; i++) { // set buffer limits according to bytes allowed ByteBuffer bb = decode_array[i]; if (bb == null) { Debug.out("preReadProcess:: bb[" + i + "] == null, decoder destroyed=" + destroyed); throw (new RuntimeException("decoder destroyed")); } if (shrink_remaining_buffers) { bb.limit(0); // ensure no read into this next buffer is possible } else { int remaining = bb.remaining(); if (remaining < 1) continue; // skip full buffer if (!marked) { pre_read_start_buffer = i; pre_read_start_position = bb.position(); marked = true; } if (remaining > allowed) { // read only part of this buffer bb.limit(bb.position() + allowed); // limit current buffer bytes_available += bb.remaining(); shrink_remaining_buffers = true; // shrink any tail buffers } else { // full buffer is allowed to be read bytes_available += remaining; allowed -= remaining; // count this buffer toward allowed and move on to the next } } } return bytes_available; } private int postReadProcess() throws IOException { int prot_bytes_read = 0; int data_bytes_read = 0; if (!reading_length_mode && !destroyed) { // reading payload data mode // ensure-restore proper buffer limits payload_buffer.limit(SS, message_length); length_buffer.limit(SS, 4); int read = payload_buffer.position(SS) - pre_read_start_position; if (payload_buffer.position(SS) > 0) { // need to have read the message id first byte if (BTMessageFactory.getMessageType(payload_buffer) == Message.TYPE_DATA_PAYLOAD) { data_bytes_read += read; } else { prot_bytes_read += read; } } if (!payload_buffer.hasRemaining(SS) && !is_paused) { // full message received! payload_buffer.position(SS, 0); DirectByteBuffer ref_buff = payload_buffer; payload_buffer = null; if (reading_handshake_message) { // decode handshake reading_handshake_message = false; DirectByteBuffer handshake_data = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HAND, 68); handshake_data.putInt(SS, HANDSHAKE_FAKE_LENGTH); handshake_data.put(SS, ref_buff); handshake_data.flip(SS); ref_buff.returnToPool(); try { Message handshake = MessageManager.getSingleton() .createMessage(BTMessage.ID_BT_HANDSHAKE_BYTES, handshake_data, (byte) 1); messages_last_read.add(handshake); } catch (MessageException me) { handshake_data.returnToPool(); throw new IOException("BT message decode failed: " + me.getMessage()); } // we need to auto-pause decoding until we're told to start again externally, // as we don't want to accidentally read the next message on the stream if it's an // AZ-format handshake pauseDecoding(); } else { // decode normal message try { messages_last_read.add(createMessage(ref_buff)); } catch (Throwable e) { ref_buff.returnToPoolIfNotFree(); // maintain unexpected errors as such so they get logged later if (e instanceof RuntimeException) { throw ((RuntimeException) e); } throw new IOException("BT message decode failed: " + e.getMessage()); } } reading_length_mode = true; // see if we've already read the next message's length percent_complete = -1; // reset receive percentage } else { // only partial received so far percent_complete = (payload_buffer.position(SS) * 100) / message_length; // compute receive percentage } } if (reading_length_mode && !destroyed) { length_buffer.limit(SS, 4); // ensure proper buffer limit prot_bytes_read += (pre_read_start_buffer == 1) ? length_buffer.position(SS) - pre_read_start_position : length_buffer.position(SS); if (!length_buffer.hasRemaining(SS)) { // done reading the length reading_length_mode = false; length_buffer.position(SS, 0); message_length = length_buffer.getInt(SS); length_buffer.position(SS, 0); // reset it for next length read if (message_length == HANDSHAKE_FAKE_LENGTH) { // handshake message reading_handshake_message = true; message_length = 64; // restore 'real' length payload_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HAND, message_length); } else if (message_length == 0) { // keep-alive message reading_length_mode = true; last_received_was_keepalive = true; try { Message keep_alive = MessageManager.getSingleton() .createMessage(BTMessage.ID_BT_KEEP_ALIVE_BYTES, null, (byte) 1); messages_last_read.add(keep_alive); } catch (MessageException me) { throw new IOException("BT message decode failed: " + me.getMessage()); } } else if (message_length < MIN_MESSAGE_LENGTH || message_length > MAX_MESSAGE_LENGTH) { throw new IOException( "Invalid message length given for BT message decode: " + message_length); } else { // normal message payload_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_PAYLOAD, message_length); } } } protocol_bytes_last_read += prot_bytes_read; data_bytes_last_read += data_bytes_read; return prot_bytes_read + data_bytes_read; } public void pauseDecoding() { is_paused = true; } public void resumeDecoding() { is_paused = false; } // Overridden by LTMessageDecoder. protected Message createMessage(DirectByteBuffer ref_buff) throws MessageException { try { return BTMessageFactory.createBTMessage(ref_buff); } catch (MessageException me) { /*if (identifier != null && me.getMessage() != null && me.getMessage().startsWith("Unknown BT message id")) { System.out.println(identifier + " " + me.getMessage()); }*/ throw me; } } }
private int postReadProcess() throws IOException { int prot_bytes_read = 0; int data_bytes_read = 0; if (!reading_length_mode && !destroyed) { // reading payload data mode // ensure-restore proper buffer limits payload_buffer.limit(SS, message_length); length_buffer.limit(SS, 4); int read = payload_buffer.position(SS) - pre_read_start_position; if (payload_buffer.position(SS) > 0) { // need to have read the message id first byte if (BTMessageFactory.getMessageType(payload_buffer) == Message.TYPE_DATA_PAYLOAD) { data_bytes_read += read; } else { prot_bytes_read += read; } } if (!payload_buffer.hasRemaining(SS) && !is_paused) { // full message received! payload_buffer.position(SS, 0); DirectByteBuffer ref_buff = payload_buffer; payload_buffer = null; if (reading_handshake_message) { // decode handshake reading_handshake_message = false; DirectByteBuffer handshake_data = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HAND, 68); handshake_data.putInt(SS, HANDSHAKE_FAKE_LENGTH); handshake_data.put(SS, ref_buff); handshake_data.flip(SS); ref_buff.returnToPool(); try { Message handshake = MessageManager.getSingleton() .createMessage(BTMessage.ID_BT_HANDSHAKE_BYTES, handshake_data, (byte) 1); messages_last_read.add(handshake); } catch (MessageException me) { handshake_data.returnToPool(); throw new IOException("BT message decode failed: " + me.getMessage()); } // we need to auto-pause decoding until we're told to start again externally, // as we don't want to accidentally read the next message on the stream if it's an // AZ-format handshake pauseDecoding(); } else { // decode normal message try { messages_last_read.add(createMessage(ref_buff)); } catch (Throwable e) { ref_buff.returnToPoolIfNotFree(); // maintain unexpected errors as such so they get logged later if (e instanceof RuntimeException) { throw ((RuntimeException) e); } throw new IOException("BT message decode failed: " + e.getMessage()); } } reading_length_mode = true; // see if we've already read the next message's length percent_complete = -1; // reset receive percentage } else { // only partial received so far percent_complete = (payload_buffer.position(SS) * 100) / message_length; // compute receive percentage } } if (reading_length_mode && !destroyed) { length_buffer.limit(SS, 4); // ensure proper buffer limit prot_bytes_read += (pre_read_start_buffer == 1) ? length_buffer.position(SS) - pre_read_start_position : length_buffer.position(SS); if (!length_buffer.hasRemaining(SS)) { // done reading the length reading_length_mode = false; length_buffer.position(SS, 0); message_length = length_buffer.getInt(SS); length_buffer.position(SS, 0); // reset it for next length read if (message_length == HANDSHAKE_FAKE_LENGTH) { // handshake message reading_handshake_message = true; message_length = 64; // restore 'real' length payload_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HAND, message_length); } else if (message_length == 0) { // keep-alive message reading_length_mode = true; last_received_was_keepalive = true; try { Message keep_alive = MessageManager.getSingleton() .createMessage(BTMessage.ID_BT_KEEP_ALIVE_BYTES, null, (byte) 1); messages_last_read.add(keep_alive); } catch (MessageException me) { throw new IOException("BT message decode failed: " + me.getMessage()); } } else if (message_length < MIN_MESSAGE_LENGTH || message_length > MAX_MESSAGE_LENGTH) { throw new IOException( "Invalid message length given for BT message decode: " + message_length); } else { // normal message payload_buffer = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_PAYLOAD, message_length); } } } protocol_bytes_last_read += prot_bytes_read; data_bytes_last_read += data_bytes_read; return prot_bytes_read + data_bytes_read; }
public ByteBuffer destroy() { if (destroyed) { Debug.out("Trying to redestroy message decoder, stack trace follows: " + this); Debug.outStackTrace(); } is_paused = true; destroyed = true; // there's a concurrency issue with the decoder whereby it can be destroyed while will being // messed with. Don't // have the energy to look into it properly atm so just try to ensure that it doesn't bork too // badly (parg: 29/04/2012) // only occasional but does have potential to generate direct buffer mem leak ;( int lbuff_read = 0; int pbuff_read = 0; length_buffer.limit(SS, 4); DirectByteBuffer plb = payload_buffer; if (reading_length_mode) { lbuff_read = length_buffer.position(SS); } else { // reading payload length_buffer.position(SS, 4); lbuff_read = 4; pbuff_read = plb == null ? 0 : plb.position(SS); } ByteBuffer unused = ByteBuffer.allocate(lbuff_read + pbuff_read); // TODO convert to direct? length_buffer.flip(SS); unused.put(length_buffer.getBuffer(SS)); try { if (plb != null) { plb.flip(SS); unused.put( plb.getBuffer( SS)); // Got a buffer overflow exception here in the past - related to PEX? } } catch (RuntimeException e) { Debug.out("hit known threading issue"); } unused.flip(); length_buffer.returnToPool(); if (plb != null) { plb.returnToPool(); payload_buffer = null; } try { for (int i = 0; i < messages_last_read.size(); i++) { Message msg = (Message) messages_last_read.get(i); msg.destroy(); } } catch (RuntimeException e) { // happens if messages modified by alt thread... Debug.out("hit known threading issue"); } messages_last_read.clear(); return unused; }
private void printInUse(boolean verbose) { if (DEBUG_PRINT_MEM) { System.out.print( "DIRECT: given=" + bytesOut / 1024 / 1024 + "MB, returned=" + bytesIn / 1024 / 1024 + "MB, "); long in_use = bytesOut - bytesIn; if (in_use < 1024 * 1024) System.out.print("in use=" + in_use + "B, "); else System.out.print("in use=" + in_use / 1024 / 1024 + "MB, "); long free = bytesFree(); if (free < 1024 * 1024) System.out.print("free=" + free + "B"); else System.out.print("free=" + free / 1024 / 1024 + "MB"); System.out.println(); CacheFileManager cm = null; try { cm = CacheFileManagerFactory.getSingleton(); } catch (Throwable e) { Debug.printStackTrace(e); } synchronized (handed_out) { Iterator it = handed_out.values().iterator(); Map cap_map = new TreeMap(); Map alloc_map = new TreeMap(); while (it.hasNext()) { DirectByteBuffer db = (DirectByteBuffer) it.next(); if (verbose) { String trace = db.getTraceString(); if (trace != null) { System.out.println(trace); } } Integer cap = new Integer(db.getBufferInternal().capacity()); Byte alloc = new Byte(db.getAllocator()); myInteger c = (myInteger) cap_map.get(cap); if (c == null) { c = new myInteger(); cap_map.put(cap, c); } c.value++; myInteger a = (myInteger) alloc_map.get(alloc); if (a == null) { a = new myInteger(); alloc_map.put(alloc, a); } a.value++; } it = cap_map.keySet().iterator(); while (it.hasNext()) { Integer key = (Integer) it.next(); myInteger count = (myInteger) cap_map.get(key); if (key.intValue() < 1024) { System.out.print("[" + key.intValue() + " x " + count.value + "] "); } else { System.out.print("[" + key.intValue() / 1024 + "K x " + count.value + "] "); } } System.out.println(); it = alloc_map.keySet().iterator(); while (it.hasNext()) { Byte key = (Byte) it.next(); myInteger count = (myInteger) alloc_map.get(key); System.out.print( "[" + DirectByteBuffer.AL_DESCS[key.intValue()] + " x " + count.value + "] "); } if (cm != null) { CacheFileManagerStats stats = cm.getStats(); System.out.print(" - Cache: "); System.out.print("sz=" + stats.getSize()); System.out.print(",us=" + stats.getUsedSize()); System.out.print(",cw=" + stats.getBytesWrittenToCache()); System.out.print(",cr=" + stats.getBytesReadFromCache()); System.out.print(",fw=" + stats.getBytesWrittenToFile()); System.out.print(",fr=" + stats.getBytesReadFromFile()); } System.out.println(); if (DEBUG_HANDOUT_SIZES) { it = size_counts.entrySet().iterator(); String str = ""; while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); str += (str.length() == 0 ? "" : ",") + entry.getKey() + "=" + entry.getValue(); } System.out.println(str); } String str = ""; for (int i = 0; i < slice_entries.length; i++) { boolean[] allocs = slice_allocs[i]; int alloc_count = 0; for (int j = 0; j < allocs.length; j++) { if (allocs[j]) { alloc_count++; } } str += (i == 0 ? "" : ",") + "[" + SLICE_ENTRY_SIZES[i] + "]f=" + slice_entries[i].size() + ",a=" + (alloc_count * SLICE_ENTRY_ALLOC_SIZES[i]) + ",u=" + slice_use_count[i]; } System.out.println("slices: " + str); } if (DEBUG_FREE_SIZES) { System.out.print("free block sizes: "); synchronized (poolsLock) { Iterator it = buffersMap.keySet().iterator(); while (it.hasNext()) { Integer keyVal = (Integer) it.next(); ArrayList bufferPool = (ArrayList) buffersMap.get(keyVal); int blocksize = keyVal.intValue(); int blockfootprint = keyVal.intValue() * bufferPool.size(); if (blockfootprint == 0) continue; String blocksuffix = ""; if (blocksize > 1024) { blocksize /= 1024; blocksuffix = "k"; } if (blocksize > 1024) { blocksize /= 1024; blocksuffix = "M"; } String footsuffix = ""; if (blockfootprint > 1024) { blockfootprint /= 1024; footsuffix = "k"; } if (blockfootprint > 1024) { blockfootprint /= 1024; footsuffix = "M"; } System.out.print( "[" + blocksize + blocksuffix + ":" + blockfootprint + footsuffix + "] "); } } System.out.println(); } long free_mem = Runtime.getRuntime().freeMemory() / 1024 / 1024; long max_mem = Runtime.getRuntime().maxMemory() / 1024 / 1024; long total_mem = Runtime.getRuntime().totalMemory() / 1024 / 1024; System.out.println( "HEAP: max=" + max_mem + "MB, total=" + total_mem + "MB, free=" + free_mem + "MB"); System.out.println(); } }
/** * Retrieve an appropriate buffer from the free pool, or create a new one if the pool is empty. */ private DirectByteBuffer getBufferHelper(byte _allocator, int _length) { DirectByteBuffer res; if (_length <= SLICE_END_SIZE) { res = getSliceBuffer(_allocator, _length); } else { ByteBuffer buff = null; Integer reqVal = new Integer(_length); // loop through the buffer pools to find a buffer big enough Iterator it = buffersMap.keySet().iterator(); while (it.hasNext()) { Integer keyVal = (Integer) it.next(); // check if the buffers in this pool are big enough if (reqVal.compareTo(keyVal) <= 0) { ArrayList bufferPool = (ArrayList) buffersMap.get(keyVal); while (true) { synchronized (poolsLock) { // make sure we don't remove a buffer when running compaction // if there are no free buffers in the pool, create a new one. // otherwise use one from the pool if (bufferPool.isEmpty()) { buff = allocateNewBuffer(keyVal.intValue()); if (buff == null) { Debug.out("allocateNewBuffer for " + _length + " returned null"); } break; } else { synchronized (bufferPool) { buff = (ByteBuffer) bufferPool.remove(bufferPool.size() - 1); } if (buff == null) { Debug.out("buffer pool for " + _length + " contained null entry"); } else { break; } } } } break; } } if (buff == null) { String str = "Unable to find an appropriate buffer pool for " + _length; Debug.out(str); throw (new RuntimeException(str)); } res = new DirectByteBuffer(_allocator, buff, this); } // clear doesn't actually zero the data, it just sets pos to 0 etc. ByteBuffer buff = res.getBufferInternal(); buff.clear(); // scrub the buffer buff.limit(_length); bytesOut += buff.capacity(); if (DEBUG_PRINT_MEM || DEBUG_TRACK_HANDEDOUT) { synchronized (handed_out) { if (DEBUG_HANDOUT_SIZES) { int trim_size; if (_length < 32) { trim_size = 4; } else { trim_size = 16; } int trim = ((_length + trim_size - 1) / trim_size) * trim_size; Long count = (Long) size_counts.get(new Integer(trim)); if (count == null) { size_counts.put(new Integer(trim), new Long(1)); } else { size_counts.put(new Integer(trim), new Long(count.longValue() + 1)); } } if (handed_out.put(buff, res) != null) { Debug.out("buffer handed out twice!!!!"); throw (new RuntimeException("Buffer handed out twice")); } // System.out.println( "[" + handed_out.size() + "] -> " + buff + ", bytesIn = " + bytesIn + // ", bytesOut = " + bytesOut ); } } // addInUse( dbb.capacity() ); return (res); }