Search in sources :

Example 21 with DirectByteBuffer

use of com.biglybt.core.util.DirectByteBuffer in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method deliverToTransport.

/**
 * Deliver (write) message(s) data to the underlying transport.
 *
 * NOTE: Allows for manual listener notification at some later time,
 * using doListenerNotifications(), instead of notifying immediately
 * from within this method.  This is useful if you want to invoke
 * listeners outside of some greater synchronised block to avoid
 * deadlock.
 * @param max_bytes maximum number of bytes to deliver
 * @param manual_listener_notify true for manual notification, false for automatic
 * @return number of bytes delivered
 * @throws IOException on delivery error
 */
@Override
public int[] deliverToTransport(int max_bytes, boolean protocol_is_free, boolean manual_listener_notify) throws IOException {
    if (max_bytes < 1) {
        if (!protocol_is_free) {
            Debug.out("max_bytes < 1: " + max_bytes);
            return (new int[2]);
        }
        // in case it was negative
        max_bytes = 0;
    }
    if (transport == null) {
        throw (new IOException("not ready to deliver data"));
    }
    int data_written = 0;
    int protocol_written = 0;
    ArrayList<RawMessage> messages_sent = null;
    // System.out.println( "deliver: %=" + percent_complete + ", queue=" + queue.size());
    try {
        queue_mon.enter();
        if (!queue.isEmpty()) {
            int buffer_limit = 64;
            ByteBuffer[] raw_buffers = (ByteBuffer[]) rawBufferCache.get();
            if (raw_buffers == null) {
                raw_buffers = new ByteBuffer[buffer_limit];
                rawBufferCache = new WeakReference(raw_buffers);
            } else {
                Arrays.fill(raw_buffers, null);
            }
            int[] orig_positions = (int[]) origPositionsCache.get();
            if (orig_positions == null) {
                orig_positions = new int[buffer_limit];
                origPositionsCache = new WeakReference(orig_positions);
            } else {
                Arrays.fill(orig_positions, 0);
            }
            int buffer_count = 0;
            int total_sofar_excluding_free = 0;
            int total_to_write = 0;
            outer: for (Iterator<RawMessage> i = queue.iterator(); i.hasNext(); ) {
                RawMessage message = i.next();
                boolean msg_is_free = message.getType() == Message.TYPE_PROTOCOL_PAYLOAD && protocol_is_free;
                DirectByteBuffer[] payloads = message.getRawData();
                for (int x = 0; x < payloads.length; x++) {
                    ByteBuffer buff = payloads[x].getBuffer(DirectByteBuffer.SS_NET);
                    raw_buffers[buffer_count] = buff;
                    orig_positions[buffer_count] = buff.position();
                    buffer_count++;
                    int rem = buff.remaining();
                    total_to_write += rem;
                    if (!msg_is_free) {
                        total_sofar_excluding_free += rem;
                        if (total_sofar_excluding_free >= max_bytes) {
                            break outer;
                        }
                    }
                    if (buffer_count == buffer_limit) {
                        int new_buffer_limit = buffer_limit * 2;
                        ByteBuffer[] new_raw_buffers = new ByteBuffer[new_buffer_limit];
                        int[] new_orig_positions = new int[new_buffer_limit];
                        System.arraycopy(raw_buffers, 0, new_raw_buffers, 0, buffer_limit);
                        System.arraycopy(orig_positions, 0, new_orig_positions, 0, buffer_limit);
                        raw_buffers = new_raw_buffers;
                        orig_positions = new_orig_positions;
                        buffer_limit = new_buffer_limit;
                    }
                }
            }
            ByteBuffer last_buff = (ByteBuffer) raw_buffers[buffer_count - 1];
            int orig_last_limit = last_buff.limit();
            if (total_sofar_excluding_free > max_bytes) {
                int reduce_by = total_sofar_excluding_free - max_bytes;
                last_buff.limit(orig_last_limit - reduce_by);
                total_to_write -= reduce_by;
            }
            if (total_to_write <= 0) {
                last_buff.limit(orig_last_limit);
                return (new int[2]);
            }
            transport.write(raw_buffers, 0, buffer_count);
            last_buff.limit(orig_last_limit);
            int pos = 0;
            boolean stop = false;
            while (!queue.isEmpty() && !stop) {
                RawMessage msg = queue.get(0);
                DirectByteBuffer[] payloads = msg.getRawData();
                for (int x = 0; x < payloads.length; x++) {
                    ByteBuffer bb = payloads[x].getBuffer(DirectByteBuffer.SS_NET);
                    int bytes_written = (bb.limit() - bb.remaining()) - orig_positions[pos];
                    total_size -= bytes_written;
                    if (msg.getType() == Message.TYPE_DATA_PAYLOAD) {
                        total_data_size -= bytes_written;
                    }
                    if (x > 0 && msg.getType() == Message.TYPE_DATA_PAYLOAD) {
                        // assumes the first buffer is message header
                        data_written += bytes_written;
                    } else {
                        protocol_written += bytes_written;
                    }
                    if (bb.hasRemaining()) {
                        // still data left to send in this message
                        // so don't bother checking later messages for completion
                        stop = true;
                        // compute send percentage
                        int message_size = 0;
                        int written = 0;
                        for (int i = 0; i < payloads.length; i++) {
                            ByteBuffer buff = payloads[i].getBuffer(DirectByteBuffer.SS_NET);
                            message_size += buff.limit();
                            if (i < x) {
                                // if in front of non-empty buffer
                                written += buff.limit();
                            } else if (i == x) {
                                // is non-empty buffer
                                written += buff.position();
                            }
                        }
                        percent_complete = (written * 100) / message_size;
                        break;
                    } else if (x == payloads.length - 1) {
                        // last payload buffer of message is empty
                        if (msg == urgent_message)
                            urgent_message = null;
                        queue.remove(0);
                        if (TRACE_HISTORY) {
                            prev_sent.addLast(msg);
                            if (prev_sent.size() > MAX_HISTORY_TRACES)
                                prev_sent.removeFirst();
                        }
                        // reset send percentage
                        percent_complete = -1;
                        if (manual_listener_notify) {
                            NotificationItem item = new NotificationItem(NotificationItem.MESSAGE_SENT);
                            item.message = msg;
                            try {
                                delayed_notifications_mon.enter();
                                delayed_notifications.add(item);
                            } finally {
                                delayed_notifications_mon.exit();
                            }
                        } else {
                            if (messages_sent == null) {
                                messages_sent = new ArrayList<>();
                            }
                            messages_sent.add(msg);
                        }
                    }
                    pos++;
                    if (pos >= buffer_count) {
                        stop = true;
                        break;
                    }
                }
            }
        }
    } finally {
        queue_mon.exit();
    }
    if (data_written + protocol_written > 0 || messages_sent != null) {
        if (trace) {
            TimeFormatter.milliTrace("omq:deliver: " + (data_written + protocol_written) + ", q=" + queue.size() + "/" + total_size);
        }
        if (manual_listener_notify) {
            if (data_written > 0) {
                // data bytes notify
                NotificationItem item = new NotificationItem(NotificationItem.DATA_BYTES_SENT);
                item.byte_count = data_written;
                try {
                    delayed_notifications_mon.enter();
                    delayed_notifications.add(item);
                } finally {
                    delayed_notifications_mon.exit();
                }
            }
            if (protocol_written > 0) {
                // protocol bytes notify
                NotificationItem item = new NotificationItem(NotificationItem.PROTOCOL_BYTES_SENT);
                item.byte_count = protocol_written;
                try {
                    delayed_notifications_mon.enter();
                    delayed_notifications.add(item);
                } finally {
                    delayed_notifications_mon.exit();
                }
            }
        } else {
            // do listener notification now
            ArrayList listeners_ref = listeners;
            int num_listeners = listeners_ref.size();
            for (int i = 0; i < num_listeners; i++) {
                MessageQueueListener listener = (MessageQueueListener) listeners_ref.get(i);
                if (data_written > 0)
                    listener.dataBytesSent(data_written);
                if (protocol_written > 0)
                    listener.protocolBytesSent(protocol_written);
                if (messages_sent != null) {
                    for (int x = 0; x < messages_sent.size(); x++) {
                        RawMessage msg = messages_sent.get(x);
                        listener.messageSent(msg.getBaseMessage());
                        if (i == num_listeners - 1) {
                            // the last listener notification, so destroy
                            msg.destroy();
                        }
                    }
                }
            }
        }
    } else {
        if (trace) {
            TimeFormatter.milliTrace("omq:deliver: 0, q=" + queue.size() + "/" + total_size);
        }
    }
    return (new int[] { data_written, protocol_written });
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer) WeakReference(java.lang.ref.WeakReference) Iterator(java.util.Iterator) RawMessage(com.biglybt.core.networkmanager.RawMessage) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 22 with DirectByteBuffer

use of com.biglybt.core.util.DirectByteBuffer in project BiglyBT by BiglySoftware.

the class OutgoingMessageQueueImpl method removeMessage.

/**
 * Remove a particular message from the queue.
 * NOTE: Only the original message found in the queue will be destroyed upon removal,
 * which may not necessarily be the one passed as the method parameter,
 * as some messages override equals() (i.e. BTRequest messages) instead of using reference
 * equality, and could be a completely different object, and would need to be destroyed
 * manually.  If the message does not override equals, then any such method will likely
 * *not* be found and removed, as internal queued object was a new allocation on insertion.
 * NOTE: Allows for manual listener notification at some later time,
 * using doListenerNotifications(), instead of notifying immediately
 * from within this method.  This is useful if you want to invoke
 * listeners outside of some greater synchronised block to avoid
 * deadlock.
 * @param message to remove
 * @param manual_listener_notify true for manual notification, false for automatic
 * @return true if the message was removed, false otherwise
 */
@Override
public boolean removeMessage(Message message, boolean manual_listener_notify) {
    RawMessage msg_removed = null;
    try {
        queue_mon.enter();
        for (Iterator<RawMessage> it = queue.iterator(); it.hasNext(); ) {
            RawMessage raw = it.next();
            if (message.equals(raw.getBaseMessage())) {
                if (raw.getRawData()[0].position(DirectByteBuffer.SS_NET) == 0) {
                    // dont remove a half-sent message
                    if (raw == urgent_message)
                        urgent_message = null;
                    DirectByteBuffer[] payload = raw.getRawData();
                    int remaining = 0;
                    for (int x = 0; x < payload.length; x++) {
                        remaining += payload[x].remaining(DirectByteBuffer.SS_NET);
                    }
                    total_size -= remaining;
                    if (raw.getType() == Message.TYPE_DATA_PAYLOAD) {
                        total_data_size -= remaining;
                    }
                    queue.remove(raw);
                    msg_removed = raw;
                }
                break;
            }
        }
        if (queue.isEmpty()) {
            percent_complete = -1;
        }
    } finally {
        queue_mon.exit();
    }
    if (msg_removed != null) {
        if (manual_listener_notify) {
            // delayed manual notification
            NotificationItem item = new NotificationItem(NotificationItem.MESSAGE_REMOVED);
            item.message = msg_removed;
            try {
                delayed_notifications_mon.enter();
                delayed_notifications.add(item);
            } finally {
                delayed_notifications_mon.exit();
            }
        } else {
            // do listener notification now
            ArrayList listeners_ref = listeners;
            for (int i = 0; i < listeners_ref.size(); i++) {
                MessageQueueListener listener = (MessageQueueListener) listeners_ref.get(i);
                listener.messageRemoved(msg_removed.getBaseMessage());
            }
            msg_removed.destroy();
        }
        return true;
    }
    return false;
}
Also used : ArrayList(java.util.ArrayList) RawMessage(com.biglybt.core.networkmanager.RawMessage) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 23 with DirectByteBuffer

use of com.biglybt.core.util.DirectByteBuffer in project BiglyBT by BiglySoftware.

the class DiskAccessRequestImpl method runAggregated.

protected static void runAggregated(DiskAccessRequestImpl base_request, DiskAccessRequestImpl[] requests) {
    // assumption - they are all for the same file, sequential offsets and aggregatable, not cancelled
    int op = base_request.getOperation();
    CacheFile file = base_request.getFile();
    long offset = base_request.getOffset();
    short cache_policy = base_request.getCachePolicy();
    DirectByteBuffer[] buffers = new DirectByteBuffer[requests.length];
    long current_offset = offset;
    long total_size = 0;
    for (int i = 0; i < buffers.length; i++) {
        DiskAccessRequestImpl request = requests[i];
        if (current_offset != request.getOffset()) {
            Debug.out("assert failed: requests not contiguous");
        }
        int size = request.getSize();
        current_offset += size;
        total_size += size;
        buffers[i] = request.getBuffer();
    }
    try {
        if (op == OP_READ) {
            file.read(buffers, offset, cache_policy);
        } else if (op == OP_WRITE) {
            file.write(buffers, offset);
        } else {
            file.writeAndHandoverBuffers(buffers, offset);
        }
        base_request.getListener().requestExecuted(total_size);
        for (int i = 0; i < requests.length; i++) {
            DiskAccessRequestImpl request = requests[i];
            request.getListener().requestComplete(request);
            if (request != base_request) {
                request.getListener().requestExecuted(0);
            }
        }
    } catch (CacheFileManagerException e) {
        int fail_index = e.getFailIndex();
        for (int i = 0; i < fail_index; i++) {
            DiskAccessRequestImpl request = requests[i];
            request.getListener().requestComplete(request);
        }
        for (int i = fail_index; i < requests.length; i++) {
            DiskAccessRequestImpl request = requests[i];
            request.getListener().requestFailed(request, e);
        }
    } catch (Throwable e) {
        for (int i = 0; i < requests.length; i++) {
            DiskAccessRequestImpl request = requests[i];
            request.getListener().requestFailed(request, e);
        }
    }
}
Also used : CacheFile(com.biglybt.core.diskmanager.cache.CacheFile) CacheFileManagerException(com.biglybt.core.diskmanager.cache.CacheFileManagerException) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 24 with DirectByteBuffer

use of com.biglybt.core.util.DirectByteBuffer in project BiglyBT by BiglySoftware.

the class AZHave method getData.

@Override
public DirectByteBuffer[] getData() {
    if (buffer == null) {
        Map map = new HashMap();
        List l = new ArrayList(piece_numbers.length);
        for (int i = 0; i < piece_numbers.length; i++) {
            l.add(new Long(piece_numbers[i]));
        }
        map.put("pieces", l);
        buffer = MessagingUtil.convertPayloadToBencodedByteStream(map, DirectByteBuffer.AL_MSG);
    }
    return new DirectByteBuffer[] { buffer };
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) List(java.util.List) ArrayList(java.util.ArrayList) Map(java.util.Map) HashMap(java.util.HashMap) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Example 25 with DirectByteBuffer

use of com.biglybt.core.util.DirectByteBuffer in project BiglyBT by BiglySoftware.

the class AZMetaData method getData.

@Override
public DirectByteBuffer[] getData() {
    if (buffer == null) {
        Map payload_map = new HashMap();
        payload_map.put("msg_type", new Long(msg_type));
        payload_map.put("piece", new Long(piece));
        if (total_size > 0) {
            payload_map.put("total_size", total_size);
        }
        buffer = MessagingUtil.convertPayloadToBencodedByteStream(payload_map, DirectByteBuffer.AL_MSG_AZ_METADATA);
    }
    if (msg_type == MSG_TYPE_DATA) {
        return new DirectByteBuffer[] { buffer, metadata };
    } else {
        return new DirectByteBuffer[] { buffer };
    }
}
Also used : HashMap(java.util.HashMap) Map(java.util.Map) HashMap(java.util.HashMap) DirectByteBuffer(com.biglybt.core.util.DirectByteBuffer)

Aggregations

DirectByteBuffer (com.biglybt.core.util.DirectByteBuffer)33 ByteBuffer (java.nio.ByteBuffer)8 ArrayList (java.util.ArrayList)8 HashMap (java.util.HashMap)7 Map (java.util.Map)7 RawMessage (com.biglybt.core.networkmanager.RawMessage)6 IOException (java.io.IOException)6 Message (com.biglybt.core.peermanager.messaging.Message)5 RawMessageImpl (com.biglybt.core.networkmanager.impl.RawMessageImpl)3 CacheFileManagerException (com.biglybt.core.diskmanager.cache.CacheFileManagerException)2 DiskManagerPiece (com.biglybt.core.disk.DiskManagerPiece)1 DiskManagerFileInfoImpl (com.biglybt.core.disk.impl.DiskManagerFileInfoImpl)1 DiskManagerRecheckInstance (com.biglybt.core.disk.impl.DiskManagerRecheckInstance)1 DMPieceList (com.biglybt.core.disk.impl.piecemapper.DMPieceList)1 DMPieceMapEntry (com.biglybt.core.disk.impl.piecemapper.DMPieceMapEntry)1 CacheFile (com.biglybt.core.diskmanager.cache.CacheFile)1 LogEvent (com.biglybt.core.logging.LogEvent)1 MessageException (com.biglybt.core.peermanager.messaging.MessageException)1 AESemaphore (com.biglybt.core.util.AESemaphore)1 ByteArrayHashMap (com.biglybt.core.util.ByteArrayHashMap)1