Merge "Issue #2968 improve efficiency by only compressing/serializing persisted objects once" into development

Former-commit-id: e7aed56884 [formerly e7aed56884 [formerly e2cd80cc4e2fbaaca7a8b34b6657a818d35cee4d]]
Former-commit-id: e44d1143c0
Former-commit-id: c1e383f8bf
This commit is contained in:
Nate Jensen 2014-04-08 13:16:45 -05:00 committed by Gerrit Code Review
commit cfe82eb2c5
4 changed files with 104 additions and 55 deletions

View file

@ -68,6 +68,7 @@ import com.raytheon.viz.ui.input.InputAdapter;
* Feb 19, 2014 2751 bclement added check for closed session
* Mar 05, 2014 2843 bsteffen Prevent exceptions on dispose.
* Mar 06, 2014 2848 bclement only send to venue if non empty
* Apr 08, 2014 2968 njensen Only serialize/compress persisted objects once
*
*
* </pre>
@ -213,24 +214,34 @@ public class CollaborationDispatcher extends Dispatcher {
// when they close the view.
return;
}
boolean immediateSend = true;
if (eventObject instanceof ICreationEvent == false) {
// Not a creation event, check event size. All creation events
// are sent immediately to avoid false negatives
try {
byte[] data = CompressionUtil.compress(SerializationUtil
.transformToThrift(eventObject));
if (data.length > IMMEDIATE_SEND_SIZE) {
immediateSend = false;
}
} catch (Exception e) {
Activator.statusHandler.handle(Priority.PROBLEM,
"Error determing size of eventObject: "
+ eventObject, e);
}
boolean immediateSend = false;
byte[] data = null;
try {
data = CompressionUtil.compress(SerializationUtil
.transformToThrift(eventObject));
} catch (Exception e) {
Activator.statusHandler.handle(Priority.PROBLEM,
"Error serializing eventObject: " + eventObject, e);
return;
}
if (eventObject instanceof ICreationEvent
|| data.length <= IMMEDIATE_SEND_SIZE) {
/*
* All creation events are sent immediately to avoid false
* negatives. All events under a set size are also sent
* immediately for optimal performance.
*/
immediateSend = true;
}
final byte[] compressedEvent = data;
final AbstractDispatchingObjectEvent toPersist = (AbstractDispatchingObjectEvent) eventObject;
final boolean[] sendPersisted = new boolean[] { !immediateSend };
/*
* we will always persist events to the data service for clients
* that join late
*/
persistPool.schedule(new Runnable() {
@Override
public void run() {
@ -238,8 +249,12 @@ public class CollaborationDispatcher extends Dispatcher {
synchronized (persistance) {
if (!disposed) {
IPersistedEvent event = persistance
.persistEvent(toPersist);
// If was no immediateSend, send now
.persistEvent(toPersist,
compressedEvent);
/*
* If it was not immediately sent, send
* notification now that it's persisted
*/
if (sendPersisted[0]) {
send(event);
}
@ -251,8 +266,14 @@ public class CollaborationDispatcher extends Dispatcher {
}
}
});
// Need to immediately send eventObject
if (immediateSend) {
/*
* Need to immediately send eventObject to get fast behavior on
* connected clients. It will go through serialization again and
* not be compressed, but since it's only small objects we don't
* care.
*/
try {
send(eventObject);
} catch (RuntimeException e) {

View file

@ -79,6 +79,7 @@ import com.raytheon.uf.viz.remote.graphics.events.ICreationEvent;
* Feb 25, 2014 2751 bclement fixed provider id path for webDAV
* Feb 28, 2014 2756 bclement added auth, moved response code checks to response object
* Mar 06, 2014 2826 njensen Fix spelling mistake
* Apr 08, 2014 2968 njensen PersistedObject serialization efficiency improvement
*
* </pre>
*
@ -178,8 +179,8 @@ public class CollaborationObjectEventStorage implements
* (com.raytheon.uf.viz.remote.graphics.AbstractRemoteGraphicsEvent)
*/
@Override
public IPersistedEvent persistEvent(AbstractDispatchingObjectEvent event)
throws CollaborationException {
public IPersistedEvent persistEvent(AbstractDispatchingObjectEvent event,
byte[] eventData) throws CollaborationException {
if (event instanceof ICreationEvent) {
// TODO this is for pre 14.3 compatibility
createFolder(String.valueOf(event.getObjectId()));
@ -202,12 +203,18 @@ public class CollaborationObjectEventStorage implements
+ event.getClass().getName() + ".obj";
String eventObjectURL = sessionDataURL + objectPath;
/*
* We will not set the event or compress the byte[] because the
* underlying event has already been serialized and compressed by
* the CollaborationDispatcher.
*/
CollaborationHttpPersistedObject persistObject = new CollaborationHttpPersistedObject();
persistObject.persistTime = System.currentTimeMillis();
persistObject.event = event;
byte[] toPersist = CompressionUtil.compress(SerializationUtil
.transformToThrift(persistObject));
persistObject.setPersistTime(System.currentTimeMillis());
persistObject.setEventAsCompressedBytes(eventData);
byte[] toPersist = SerializationUtil
.transformToThrift(persistObject);
stats.log(event.getClass().getSimpleName(), toPersist.length, 0);
HttpPut put = createPut(eventObjectURL, toPersist);
HttpClientResponse response = executeRequest(put);
if (response.isSuccess() == false) {
@ -284,10 +291,10 @@ public class CollaborationObjectEventStorage implements
if (object == null) {
// No object available
return null;
} else if (object.event != null) {
stats.log(object.event.getClass().getSimpleName(), 0,
} else if (object.getEvent() != null) {
stats.log(object.getEvent().getClass().getSimpleName(), 0,
object.dataSize);
return object.event;
return object.getEvent();
} else {
throw new CollaborationException(
"Unable to deserialize persisted event into event object");
@ -318,7 +325,7 @@ public class CollaborationObjectEventStorage implements
CollaborationHttpPersistedObject dataObject = SerializationUtil
.transformFromThrift(
CollaborationHttpPersistedObject.class,
CompressionUtil.uncompress(response.data));
response.data);
if (dataObject != null) {
dataObject.dataSize = response.data.length;
}
@ -388,7 +395,7 @@ public class CollaborationObjectEventStorage implements
.size()];
int i = 0;
for (CollaborationHttpPersistedObject object : objectEvents) {
events[i++] = object.event;
events[i++] = object.getEvent();
}
return events;
@ -570,7 +577,15 @@ public class CollaborationObjectEventStorage implements
@DynamicSerializeElement
private long persistTime;
/**
* This will be serialized instead of the event. Provides better
* efficiency than serializing the event itself since
* CollaborationDispatcher is already handling the serialization and
* compression.
*/
@DynamicSerializeElement
private byte[] eventAsCompressedBytes;
private AbstractDispatchingObjectEvent event;
private long dataSize;
@ -592,17 +607,32 @@ public class CollaborationObjectEventStorage implements
/**
* @return the event
* @throws CollaborationException
* @throws SerializationException
*/
public AbstractDispatchingObjectEvent getEvent() {
public AbstractDispatchingObjectEvent getEvent()
throws CollaborationException {
if (event == null && eventAsCompressedBytes != null) {
try {
event = SerializationUtil.transformFromThrift(
AbstractDispatchingObjectEvent.class,
CompressionUtil.uncompress(eventAsCompressedBytes));
eventAsCompressedBytes = null;
} catch (SerializationException e) {
throw new CollaborationException(
"Error deserializing event retrieved from collaboration data service",
e);
}
}
return event;
}
/**
* @param event
* the event to set
*/
public void setEvent(AbstractDispatchingObjectEvent event) {
this.event = event;
public byte[] getEventAsCompressedBytes() {
return eventAsCompressedBytes;
}
public void setEventAsCompressedBytes(byte[] eventAsCompressedBytes) {
this.eventAsCompressedBytes = eventAsCompressedBytes;
}
}

View file

@ -32,6 +32,7 @@ import com.raytheon.uf.viz.remote.graphics.events.AbstractDispatchingObjectEvent
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Apr 20, 2012 mschenke Initial creation
* Apr 08, 2014 2968 njensen Added byte[] data arg to persistEvent
*
* </pre>
*
@ -41,8 +42,18 @@ import com.raytheon.uf.viz.remote.graphics.events.AbstractDispatchingObjectEvent
public interface IObjectEventPersistance {
public IPersistedEvent persistEvent(AbstractDispatchingObjectEvent event)
throws CollaborationException;
/**
* Persists an event to the remote service
*
* @param event
* the event to persist
* @param data
* the event transformed to bytes
* @return an IPersistedEvent that references the remotely persisted event
* @throws CollaborationException
*/
public IPersistedEvent persistEvent(AbstractDispatchingObjectEvent event,
byte[] data) throws CollaborationException;
public void dispose() throws CollaborationException;
}

View file

@ -26,6 +26,8 @@ import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.raytheon.uf.common.util.BufferUtil;
/**
* Slices a subset of a Buffer object
*
@ -38,6 +40,7 @@ import java.nio.ShortBuffer;
* Nov 22, 2011 mschenke Initial creation
* Jun 20, 2013 2122 mschenke Made work with slicing from data with
* bounds not starting at 0,0
* Apr 08, 2014 2968 njensen Use BufferUtil for duplicate()
*
* </pre>
*
@ -67,7 +70,7 @@ public class BufferSlicer {
"Data bounds defines region outside of buffer's total bounds");
}
data = duplicate(data);
data = BufferUtil.duplicate(data);
int dataSize = dataBounds.width * dataBounds.height;
if (dataSize == totalBounds.width * totalBounds.height) {
return data;
@ -87,22 +90,6 @@ public class BufferSlicer {
}
}
private static Buffer duplicate(Buffer data) {
if (data instanceof ByteBuffer) {
return ((ByteBuffer) data).duplicate();
} else if (data instanceof ShortBuffer) {
return ((ShortBuffer) data).duplicate();
} else if (data instanceof IntBuffer) {
return ((IntBuffer) data).duplicate();
} else if (data instanceof FloatBuffer) {
return ((FloatBuffer) data).duplicate();
} else {
throw new RuntimeException(
"Unhandled buffer passed in: " + data != null ? data
.getClass().getSimpleName() : null);
}
}
private static ByteBuffer slice(ByteBuffer data, Rectangle dataBounds,
Rectangle totalBounds, int dataSize) {
ByteBuffer newData = null;