Author: vgritsenko Date: Sun Nov 9 13:52:26 2008 New Revision: 712565 URL: http://svn.apache.org/viewvc?rev=712565&view=rev Log: Optimized transmission of collection's symbol table between server and the client for reduced traffic and better performance.
Modified: xml/xindice/trunk/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java xml/xindice/trunk/java/src/org/apache/xindice/server/rpc/messages/GetResource.java xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolDeserializer.java xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolSerializer.java xml/xindice/trunk/status.xml Modified: xml/xindice/trunk/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java?rev=712565&r1=712564&r2=712565&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/client/xmldb/xmlrpc/CollectionImpl.java Sun Nov 9 13:52:26 2008 @@ -31,6 +31,7 @@ import org.apache.xindice.server.rpc.RPCMessageInterface; import org.apache.xindice.util.SymbolDeserializer; import org.apache.xindice.xml.TextWriter; +import org.apache.xindice.xml.SymbolTable; import org.apache.xindice.xml.dom.DOMParser; import org.apache.xindice.xml.dom.DocumentImpl; import org.apache.xmlrpc.XmlRpcException; @@ -73,6 +74,11 @@ private XmlRpcClient client; /** + * Cached symbol table + */ + private SymbolDeserializer symsDeserializer; + + /** * Creates new <code>CollectionImpl</code> instance representing connection * to server collection. * @@ -96,6 +102,8 @@ FaultCodes.COL_COLLECTION_NOT_FOUND, "Collection not found: " + collPath); } + + symsDeserializer = new SymbolDeserializer(); } /** @@ -162,6 +170,7 @@ params.put(RPCDefaultMessage.COLLECTION, collPath); params.put(RPCDefaultMessage.NAME, id); params.put(RPCDefaultMessage.COMPRESSED, "true"); + params.put(RPCDefaultMessage.TIMESTAMP, Long.toString(symsDeserializer.getLastModified())); Object result = runRemoteCommand("GetResource", params); @@ -172,15 +181,15 @@ } else if (result instanceof Map) { // Result is compressed XML. Map compressed = (Map) result; - SymbolDeserializer symbolDeserial = new SymbolDeserializer(); - return new XMLResourceImpl(id, id, this, symbolDeserial.getSymbols(compressed), (byte[]) compressed.get("document")); + SymbolTable syms = symsDeserializer.getSymbols(compressed); + return new XMLResourceImpl(id, id, this, syms, (byte[]) compressed.get("document")); } else if (result instanceof byte[]) { // Result is binary. return new BinaryResourceImpl(id, this, (byte[]) result); } else { - // Result is XML. + // Result is XML string. return new XMLResourceImpl(id, this, (String) result); } Modified: xml/xindice/trunk/java/src/org/apache/xindice/server/rpc/messages/GetResource.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/server/rpc/messages/GetResource.java?rev=712565&r1=712564&r2=712565&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/server/rpc/messages/GetResource.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/server/rpc/messages/GetResource.java Sun Nov 9 13:52:26 2008 @@ -39,10 +39,7 @@ */ public class GetResource extends RPCDefaultMessage { - private static final Log log = LogFactory.getLog(GetResource.class); - public Map execute(Map message) throws Exception { - if (!message.containsKey(COLLECTION)) { throw new Exception(MISSING_COLLECTION_PARAM); } @@ -64,28 +61,25 @@ } else if (message.containsKey(COMPRESSED)) { // Compressed XML resource - SymbolSerializer symbolSerializer = new SymbolSerializer(col.getSymbols()); - long timestamp = 1; - /* TODO: Timestamp optimization. - Longs are causing problems with XML-RPC - so we'll try to get everything working without them. - if (!message.containsKey(TIMESTAMP)) { - throw new Exception(MISSING_TIMESTAMP_PARAM); - } - int timestamp = ((Integer) message.get("timestamp")).intValue(); - */ + // Document might be compressed (with bytes) or not. In a latter case, send a string. + CompressedDocument doc = (CompressedDocument) obj.getValue(); + if (doc.getDataBytes() != null) { + SymbolSerializer symbolSerializer = new SymbolSerializer(col.getSymbols()); + + // Get client's symbol table timestamp + long timestamp = 0; + if (message.containsKey(TIMESTAMP)) { + timestamp = Long.parseLong((String) message.get("timestamp")); + } - // Document might be compressed (with bytes) or not. In a latter case, convert to string. - Document doc = (Document) obj.getValue(); - if (/*( timestamp != -1) &&*/ ((CompressedDocument) doc).getDataBytes() != null) { - result.put(RESULT, symbolSerializer.convertFromDocument(doc, timestamp)); + result.put(RESULT, symbolSerializer.serialize(doc, timestamp)); } else { result.put(RESULT, TextWriter.toString(doc)); } } else { - // XML resource + // Uncompressed XML resource Document doc = (Document) obj.getValue(); result.put(RESULT, TextWriter.toString(doc)); } Modified: xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolDeserializer.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolDeserializer.java?rev=712565&r1=712564&r2=712565&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolDeserializer.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolDeserializer.java Sun Nov 9 13:52:26 2008 @@ -19,13 +19,14 @@ package org.apache.xindice.util; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.xindice.xml.SymbolTable; import org.apache.xindice.xml.SymbolTableSymbols; import org.apache.xindice.xml.dom.DocumentImpl; import org.w3c.dom.Document; -import java.util.Hashtable; import java.util.Map; /** @@ -35,66 +36,71 @@ * @version $Revision$, $Date$ */ public final class SymbolDeserializer { - private static final SymbolTableSymbols hcSyms = SymbolTableSymbols.getInstance(); + + private static final Log log = LogFactory.getLog(SymbolSerializer.class); /** * The collection's SymbolTable */ - private SymbolTable syms; + private final SymbolTable syms; /** * Last time we caught a SymbolTable modification */ private long lastMod; + + public SymbolDeserializer() { + this.syms = new SymbolTable(); + } + /** - * convertToDocument converts the compressed Hashtable to - * a DOM Document. + * getSymbols returns the Symbol Table being managed by this + * deserializer. * - * @param buffer The Hashtable - * @return The Document + * @return The Symbol Table */ - public Document convertToDocument(Hashtable buffer) { - SymbolTable s = getSymbols(buffer); - return new DocumentImpl((byte[]) buffer.get("document"), s, null); + public SymbolTable getSymbols() { + return syms; } /** + * getLastModified returns the last modified time stamp of the + * client's image of the managed symbol table. + * + * @return The last modified stamp + */ + public long getLastModified() { + return lastMod; + } + + /** * getSymbols returns the current SymbolTable image for the * server-side Collection that is being managed. The Symbol - * table is shipped as part of an Hashtable when the server + * table is shipped as part of an Map when the server * has determined that its image of the SymbolTable is out of * date. This method either returns the current image or - * extracts the new image from the Hashtable. + * extracts the new image from the Map. * - * @param buffer The Hashtable + * @param buffer The Map * @return The Symbol Table */ public SymbolTable getSymbols(Map buffer) { - //if ( ((Long) buffer.get("timestamp")).longValue() != lastMod ) { - // lastMod = ((Long) buffer.get("timestamp")).longValue(); - - Document doc = new DocumentImpl((byte[]) buffer.get("symbols"), hcSyms, null); - - if (syms == null) { - syms = new SymbolTable(); + byte[] symBytes = (byte[]) buffer.get("symbols"); + if (symBytes != null) { + String ts = (String) buffer.get("timestamp"); + if (log.isDebugEnabled()) { + log.info("Receiving symbols. Client ts=" + lastMod + ", Server ts=" + ts); + } + + Document doc = new DocumentImpl(symBytes, SymbolTableSymbols.getInstance(), null); + synchronized (syms) { + syms.streamFromXML(doc.getDocumentElement()); + // Server v1.1 won't be sending timestamp. Will use 0. + lastMod = ts == null ? 0 : Long.parseLong(ts); + } } - synchronized (syms) { - syms.streamFromXML(doc.getDocumentElement()); - } - // } return syms; } - - /** - * getLastModified returns the last modified time stamp of the - * client's image of the managed Symbol Table. - * - * @return The last modified stamp - */ - public long getLastModified() { - return lastMod; - } } - Modified: xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolSerializer.java URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolSerializer.java?rev=712565&r1=712564&r2=712565&view=diff ============================================================================== --- xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolSerializer.java (original) +++ xml/xindice/trunk/java/src/org/apache/xindice/util/SymbolSerializer.java Sun Nov 9 13:52:26 2008 @@ -30,7 +30,8 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.Hashtable; +import java.util.HashMap; +import java.util.Map; /** * SymbolSerializer is a utility class for managing SymbolTables in @@ -42,8 +43,6 @@ private static final Log log = LogFactory.getLog(SymbolSerializer.class); - private static final SymbolTableSymbols hcSyms = SymbolTableSymbols.getInstance(); - /** * The collection's SymbolTable */ @@ -65,75 +64,75 @@ } /** - * getSymBuffer returns a new Hashtable that includes a + * getSymbols returns the Symbol Table being managed by this + * Serializer. + * + * @return The Symbol Table + */ + public SymbolTable getSymbols() { + return syms; + } + + /** + * getLastModified returns a time stamp of the last server-side + * modified of the Symbol Table. This is used to determine + * whether or not to regenerate the byte stream, and whether + * the client will need a new copy of the Symbol Table. + * + * @return Last modified stamp + */ + public long getLastModified() { + return syms.getLastModified(); + } + + /** + * getSymBuffer returns a new Map that optionally includes a * reference to the SymbolTable's byte array image for wire - * transmission. Depending on whether the client is up to - * date, convertFromDocument will remove this reference. + * transmission. * - * @return A new Hashtable + * @return A new Map */ - public Hashtable getSymBuffer() { + private Map getSymBuffer(long remoteLastMod) { long lm = syms.getLastModified(); - if (lm > lastMod) { + if (lm != lastMod) { DocumentImpl doc = new DocumentImpl(); - doc.setSymbols(hcSyms); + doc.setSymbols(SymbolTableSymbols.getInstance()); synchronized (syms) { - Element elem = syms.streamToXML(doc); - doc.appendChild(elem); + Element element = syms.streamToXML(doc); + doc.appendChild(element); - symBytes = DOMCompressor.compress(doc, hcSyms); + symBytes = DOMCompressor.compress(doc, SymbolTableSymbols.getInstance()); lastMod = lm; } } - Hashtable result = new Hashtable(); - //result.put("timestamp", new Long(lm)); - result.put("symbols", symBytes); + Map result = new HashMap(5); + if (remoteLastMod != lastMod) { + if (log.isDebugEnabled()) { + log.info("Sending symbols. Client ts=" + remoteLastMod + ", Server ts=" + lastMod); + } + result.put("timestamp", Long.toString(lastMod)); + result.put("symbols", symBytes); + } + return result; } /** - * convertFromDocument converts a DOM Document into an - * Hashtable that, depending on the time stamp, possibly - * includes a current image of the managed Collection's Symbol - * Table. + * Converts a DOM Document into a Map that, depending on the + * time stamp, possibly includes a current image of the managed + * Collection's Symbol Table. * * @param doc The Document to Convert - * @param stamp The client's last modified stamp - * @return The Hashtable + * @param remoteLastMod The client's last modified time stamp + * @return The Map */ - public Hashtable convertFromDocument(Document doc, long stamp) { - Hashtable result = getSymBuffer(); + public Map serialize(Document doc, long remoteLastMod) { + Map result = getSymBuffer(remoteLastMod); byte[] docBytes = ((CompressedDocument) doc).getDataBytes(); result.put("document", docBytes); - /*if ( ((Long) result.get("timestamp")).longValue() == stamp ) { - result.put("symbols", EmptyBytes); - }*/ - return result; } - - /** - * getSymbols returns the Symbol Table being managed by this - * Serializer. - * - * @return The Symbol Table - */ - public SymbolTable getSymbols() { - return syms; - } - - /** - * getLastModified returns a time stamp of the last server-side - * modified of the Symbol Table. This is used to determine - * whether or not to regenerate the byte stream, and whether - * the client will need a new copy of the Symbol Table. - * - * @return Last modified stamp - */ - public long getLastModified() { - return syms.getLastModified(); - } } Modified: xml/xindice/trunk/status.xml URL: http://svn.apache.org/viewvc/xml/xindice/trunk/status.xml?rev=712565&r1=712564&r2=712565&view=diff ============================================================================== --- xml/xindice/trunk/status.xml (original) +++ xml/xindice/trunk/status.xml Sun Nov 9 13:52:26 2008 @@ -70,19 +70,8 @@ XQuery implementation. </action> </actions> - <actions priority="High Priority"> - <action context="code" dev="open"> - <strong>Caching</strong> Revisit implementation of documents cache in - the core Collection class. Clarify caching semantics, implement caching - for all use cases (compressed, uncompressed, binary objects). Ensure - dirty data can not be placed in the cache. - </action> - <action context="code" dev="open"> - <strong>XML-RPC</strong> Extend Xindice XML-RPC API to optimize transmission - of collection's symbol table between server and the client for reduced - traffic and improved performance. - </action> - </actions> + <!--<actions priority="High Priority">--> + <!--</actions>--> <actions priority="Medium Priority"> <action context="code" dev="open"> <strong>Entity Catalogue</strong> Xindice should have internal XML entity @@ -115,6 +104,10 @@ <changes> <release version="1.2-dev" date="unreleased"> <action dev="VG" type="update"> + Optimized transmission of collection's symbol table between server and + the client for reduced traffic and better performance. + </action> + <action dev="VG" type="update"> Update jetty to version 6.1.11. </action> <action dev="NS" type="update">