org.simpleframework.transport.SegmentBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simple Show documentation
Show all versions of simple Show documentation
Simple is a high performance asynchronous HTTP server for Java
/*
* SegmentBuilder.java February 2008
*
* Copyright (C) 2008, Niall Gallagher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.simpleframework.transport;
import java.io.IOException;
import java.util.PriorityQueue;
/**
* The SegmentBuilder
object is used to build segments
* such that they represent segments of data from the the packets that
* are provided to the builder. This enables packets to be compacted
* into each other so that packets can be freed when they are no
* longer needed. This enables the transport as a whole to perform
* better as it ensures the packet pool is not exhausted when there
* is sufficient space in other queued packets. Also this will copy
* shared packets in to allocated space if requested, ensuring that
* the writing thread does not need to block.
*
* @author Niall Gallagher
*
* @see org.simpleframework.transport.Writer
*/
class SegmentBuilder {
/**
* This is a compact queue which contains the compact packets.
*/
private final Queue compact;
/**
* This is the packet queue that is used to queue packets.
*/
private final Queue ready;
/**
* This is the maximum size a packet can be duplicated as.
*/
private final int limit;
/**
* Constructor for the SegmentBuilder
object. This
* is used to create a queue of packets such that each packet is
* of a minimum size. To ensure packets are of a minimum size
* this aggregates them by moving bytes between packets.
*/
public SegmentBuilder() {
this(20480);
}
/**
* Constructor for the SegmentBuilder
object. This
* is used to create a queue of packets such that each packet is
* of a minimum size. To ensure packets are of a minimum size
* this aggregates them by moving bytes between packets.
*
* @param limit this is the threshold for asynchronous buffers
*/
public SegmentBuilder(int limit) {
this.compact = new Queue();
this.ready = new Queue();
this.limit = limit;
}
/**
* This is used to determine if the builder contains any references.
* If the segment builder contains any reference packets it forces
* the Writer
to block. Blocking is required so
* that a race condition is avoided where the writing thread and
* the flushing thread to not confuse each other.
*
* @return true if there are any referenced buffers in the builder
*/
public boolean isReference() {
for(Packet packet : ready) {
if(packet.isReference()) {
return true;
}
}
return false;
}
/**
* This will aggregate the queued packets in to a packet that is
* at least the minimum required size. If there are none in the
* queue then this will return null. Also if the queued packets
* are of zero length this will return null.
*
* @return this returns a packet from the queue of packets
*/
public Segment build() throws IOException {
Packet packet = ready.peek();
if(packet == null) {
return null;
}
return create(packet);
}
/**
* This will aggregate the queued packets in to a packet that is
* at least the minimum required size. If there are none in the
* queue then this will return null. Also if the queued packets
* are of zero length this will return null.
*
* @param packet this is the packet to wrap within a closer packet
*
* @return this returns a packet from the queue of packets
*/
private Segment create(Packet packet) throws IOException {
int length = packet.length();
if(length <= 0) {
packet.close();
ready.poll();
return build();
}
return new Segment(packet, ready);
}
/**
* This will aggregate the queued packets in to a packet that is
* at least the minimum required size. If there are none in the
* queue then this will return null. Also if the queued packets
* are of zero length this will return null.
*
* @param packet this is a new packet to be added to the packet queue
*
* @return this returns a packet from the queue of packets
*/
public Segment build(Packet packet) throws IOException {
boolean update = ready.offer(packet);
long sequence = packet.sequence();
if(!update) {
throw new PacketException("Could not add packet " + sequence);
}
return build();
}
/**
* This method is used to compact the packets within the builder
* such that it duplicates any shared packets and closes them.
* Duplicating and closing shared packets is done so that the
* writing thread does not need to block. Duplication of shared
* packets only occurs if the remaining length is less that
* than the maximum duplication size specified.
*/
public void compact() throws IOException {
Packet packet = ready.peek();
while(packet != null) {
packet = ready.poll();
if(packet != null) {
compact.offer(packet);
}
}
extract();
}
/**
* This is used to take all packets queued in to the compact queue
* and determine whether they need to be extracted in to separate
* private packets. Extracting shared packets ensures that they
* do not suffer from race conditions when the writing thread is
* released. This increases the concurrency capability.
*/
private void extract() throws IOException {
int count = limit;
for(Packet packet : compact) {
int length = packet.length();
if(length <= count) {
packet = packet.extract();
count -= length;
}
if(packet != null) {
ready.offer(packet);
}
}
compact.clear();
}
/**
* This returns the total length of all packets within the queue.
* This can be used to determine if any packets can be created
* using the aggregate
method. If the length is zero
* there are no packets waiting to be aggregated.
*
* @return this returns the total length of all queued packets
*/
public int length() throws IOException{
int count = 0;
for(Packet packet : ready) {
count += packet.length();
}
return count;
}
/**
* This is used to close all packets within the builder. This
* is done when there is an error or the client has closed the
* connection from their size. This is important as it releases
* any resources occupied by the queued packets.
*/
public void close() throws IOException {
for(Packet packet : ready) {
packet.close();
}
ready.clear();
}
/**
* The Queue
object is used to create a queue of
* packets that represent the order the packets have been added
* to the builder. This order ensures that the packets can
* be reassembled on the client size as a complete resource.
*/
private class Queue extends PriorityQueue {
/**
* Constructor for the SegmentBuilder
object. This
* is used to create a queue to order the packets that are
* to be aggregated and delivered to a client.
*/
public Queue() {
super();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy