package ar.com.javacuriosities.nio.server.message;
/*
* Creamos un shared buffer el cual puede contener multiples mensajes. Un mensaje obtiene una sección del buffer
* para usar y si este es mas grande es movido a una sección mayor.
*
*/
public class MessageBuffer {
private static int KB = 1024;
private static int MB = 1024 * KB;
private static final int CAPACITY_SMALL = 4 * KB;
private static final int CAPACITY_MEDIUM = 128 * KB;
private static final int CAPACITY_LARGE = 1024 * KB;
private byte[] smallMessageBuffer = new byte[1024 * 4 * KB]; // 1024 x 4KB mensajes = 4MB
private byte[] mediumMessageBuffer = new byte[128 * 128 * KB]; // 128 x 128KB mensajes = 16MB
private byte[] largeMessageBuffer = new byte[16 * 1 * MB]; // 16 * 1MB mensajes = 16MB
private QueueIntFlip smallMessageBufferFreeBlocks = new QueueIntFlip(1024); // 1024 secciones
private QueueIntFlip mediumMessageBufferFreeBlocks = new QueueIntFlip(128); // 128 secciones
private QueueIntFlip largeMessageBufferFreeBlocks = new QueueIntFlip(16); // 16 secciones
public MessageBuffer() {
// Inicializamos todas Queue de mensajes para las secciones
for (int i = 0; i < smallMessageBuffer.length; i += CAPACITY_SMALL) {
this.smallMessageBufferFreeBlocks.put(i);
}
for (int i = 0; i < mediumMessageBuffer.length; i += CAPACITY_MEDIUM) {
this.mediumMessageBufferFreeBlocks.put(i);
}
for (int i = 0; i < largeMessageBuffer.length; i += CAPACITY_LARGE) {
this.largeMessageBufferFreeBlocks.put(i);
}
}
public Message getMessage() {
int nextFreeSmallBlock = this.smallMessageBufferFreeBlocks.take();
if (nextFreeSmallBlock == -1)
return null;
Message message = new Message(this);
message.sharedBuffer = this.smallMessageBuffer;
message.capacity = CAPACITY_SMALL;
message.offset = nextFreeSmallBlock;
message.length = 0;
return message;
}
public boolean expandMessage(Message message) {
if (message.capacity == CAPACITY_SMALL) {
return moveMessage(message, this.smallMessageBufferFreeBlocks, this.mediumMessageBufferFreeBlocks, this.mediumMessageBuffer, CAPACITY_MEDIUM);
} else if (message.capacity == CAPACITY_MEDIUM) {
return moveMessage(message, this.mediumMessageBufferFreeBlocks, this.largeMessageBufferFreeBlocks, this.largeMessageBuffer, CAPACITY_LARGE);
} else {
return false;
}
}
private boolean moveMessage(Message message, QueueIntFlip sourceQueue, QueueIntFlip targetQueue, byte[] destination, int newCapacity) {
int nextFreeBlock = targetQueue.take();
if (nextFreeBlock == -1)
return false;
System.arraycopy(message.sharedBuffer, message.offset, destination, nextFreeBlock, message.length);
// Liberamos los bloques luego de la copia
sourceQueue.put(message.offset);
message.sharedBuffer = destination;
message.offset = nextFreeBlock;
message.capacity = newCapacity;
return true;
}
}