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 });
}
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;
}
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);
}
}
}
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 };
}
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 };
}
}
Aggregations