You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2012/03/05 20:12:52 UTC

svn commit: r1297185 - in /qpid/trunk/qpid/cpp: include/qpid/framing/FieldTable.h src/qpid/framing/FieldTable.cpp

Author: astitcher
Date: Mon Mar  5 19:12:52 2012
New Revision: 1297185

URL: http://svn.apache.org/viewvc?rev=1297185&view=rev
Log:
QPID-3883: Using application headers in messages causes a very large slowdown
Lazily decode FieldTables, holding onto the actual raw bytes
until we really need to decode, if we encode the FieldTable before
decoding it we can just send the raw bytes we captured initially.

Modified:
    qpid/trunk/qpid/cpp/include/qpid/framing/FieldTable.h
    qpid/trunk/qpid/cpp/src/qpid/framing/FieldTable.cpp

Modified: qpid/trunk/qpid/cpp/include/qpid/framing/FieldTable.h
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/include/qpid/framing/FieldTable.h?rev=1297185&r1=1297184&r2=1297185&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/include/qpid/framing/FieldTable.h (original)
+++ qpid/trunk/qpid/cpp/include/qpid/framing/FieldTable.h Mon Mar  5 19:12:52 2012
@@ -21,6 +21,7 @@
 #include <iostream>
 #include <vector>
 #include <boost/shared_ptr.hpp>
+#include <boost/shared_array.hpp>
 #include <map>
 #include "qpid/framing/amqp_types.h"
 #include "qpid/CommonImportExport.h"
@@ -57,9 +58,7 @@ class FieldTable
     typedef ValueMap::value_type value_type;
 
     QPID_COMMON_EXTERN FieldTable();
-    QPID_COMMON_EXTERN FieldTable(const FieldTable& ft);
-    QPID_COMMON_EXTERN ~FieldTable();
-    QPID_COMMON_EXTERN FieldTable& operator=(const FieldTable& ft);
+    // Compiler default copy, assignment and destructor are fine
     QPID_COMMON_EXTERN uint32_t encodedSize() const;
     QPID_COMMON_EXTERN void encode(Buffer& buffer) const;
     QPID_COMMON_EXTERN void decode(Buffer& buffer);
@@ -99,24 +98,24 @@ class FieldTable
     QPID_COMMON_EXTERN bool operator==(const FieldTable& other) const;
 
     // Map-like interface.
-    ValueMap::const_iterator begin() const { return values.begin(); }
-    ValueMap::const_iterator end() const { return values.end(); }
-    ValueMap::const_iterator find(const std::string& s) const { return values.find(s); }
-
-    ValueMap::iterator begin() { return values.begin(); }
-    ValueMap::iterator end() { return values.end(); }
-    ValueMap::iterator find(const std::string& s) { return values.find(s); }
+    ValueMap::const_iterator begin() const;
+    ValueMap::const_iterator end() const;
+    ValueMap::const_iterator find(const std::string& s) const;
+
+    ValueMap::iterator begin();
+    ValueMap::iterator end();
+    ValueMap::iterator find(const std::string& s);
 
     QPID_COMMON_EXTERN std::pair <ValueMap::iterator, bool> insert(const ValueMap::value_type&);
     QPID_COMMON_EXTERN ValueMap::iterator insert(ValueMap::iterator, const ValueMap::value_type&);
     void clear();
 
-    // ### Hack Alert
-
-    ValueMap::iterator getValues() { return values.begin(); }
-
   private:
-    ValueMap values;
+    void realDecode() const;
+    void flushRawCache() const;
+
+    mutable ValueMap values;
+    mutable boost::shared_array<uint8_t> cachedBytes;
     mutable uint32_t cachedSize; // if = 0 then non cached size as 0 is not a legal size
 
     QPID_COMMON_EXTERN friend std::ostream& operator<<(std::ostream& out, const FieldTable& body);

Modified: qpid/trunk/qpid/cpp/src/qpid/framing/FieldTable.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/qpid/framing/FieldTable.cpp?rev=1297185&r1=1297184&r2=1297185&view=diff
==============================================================================
--- qpid/trunk/qpid/cpp/src/qpid/framing/FieldTable.cpp (original)
+++ qpid/trunk/qpid/cpp/src/qpid/framing/FieldTable.cpp Mon Mar  5 19:12:52 2012
@@ -31,25 +31,11 @@
 namespace qpid {
 namespace framing {
 
-FieldTable::FieldTable() : cachedSize(0)
+FieldTable::FieldTable() :
+    cachedSize(0)
 {
 }
 
-FieldTable::FieldTable(const FieldTable& ft)
-{
-  *this = ft;
-}
-
-FieldTable& FieldTable::operator=(const FieldTable& ft)
-{
-  clear();
-  values = ft.values;
-  cachedSize = ft.cachedSize;
-  return *this;
-}
-
-FieldTable::~FieldTable() {}
-
 uint32_t FieldTable::encodedSize() const {
     if (cachedSize != 0) {
         return cachedSize;
@@ -75,6 +61,7 @@ std::ostream& operator<<(std::ostream& o
 }
 
 std::ostream& operator<<(std::ostream& out, const FieldTable& t) {
+    t.realDecode();
     out << "{";
     FieldTable::ValueMap::const_iterator i = t.begin();
     if (i != t.end()) out << *i++;
@@ -86,58 +73,70 @@ std::ostream& operator<<(std::ostream& o
 }
 
 void FieldTable::set(const std::string& name, const ValuePtr& value){
+    realDecode();
     values[name] = value;
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setString(const std::string& name, const std::string& value){
+    realDecode();
     values[name] = ValuePtr(new Str16Value(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setInt(const std::string& name, const int value){
+    realDecode();
     values[name] = ValuePtr(new IntegerValue(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setInt64(const std::string& name, const int64_t value){
+    realDecode();
     values[name] = ValuePtr(new Integer64Value(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setTimestamp(const std::string& name, const uint64_t value){
+    realDecode();
     values[name] = ValuePtr(new TimeValue(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setUInt64(const std::string& name, const uint64_t value){
+    realDecode();
     values[name] = ValuePtr(new Unsigned64Value(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setTable(const std::string& name, const FieldTable& value)
 {
+    realDecode();
     values[name] = ValuePtr(new FieldTableValue(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 void FieldTable::setArray(const std::string& name, const Array& value)
 {
+    realDecode();
     values[name] = ValuePtr(new ArrayValue(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setFloat(const std::string& name, const float value){
+    realDecode();
     values[name] = ValuePtr(new FloatValue(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 void FieldTable::setDouble(const std::string& name, double value){
+    realDecode();
     values[name] = ValuePtr(new DoubleValue(value));
-    cachedSize = 0;
+    flushRawCache();
 }
 
 FieldTable::ValuePtr FieldTable::get(const std::string& name) const
 {
+    // Ensure we have any values we're trying to read
+    realDecode();
     ValuePtr value;
     ValueMap::const_iterator i = values.find(name);
     if ( i!=values.end() )
@@ -207,38 +206,76 @@ bool FieldTable::getDouble(const std::st
 //}
 
 void FieldTable::encode(Buffer& buffer) const {
-    buffer.putLong(encodedSize() - 4);
-    buffer.putLong(values.size());
-    for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
-        buffer.putShortString(i->first);
-    	i->second->encode(buffer);
+    // If we've still got the input field table
+    // we can just copy it directly to the output
+    if (cachedBytes) {
+        buffer.putRawData(&cachedBytes[0], cachedSize);
+    } else {
+        buffer.putLong(encodedSize() - 4);
+        buffer.putLong(values.size());
+        for (ValueMap::const_iterator i = values.begin(); i!=values.end(); ++i) {
+            buffer.putShortString(i->first);
+            i->second->encode(buffer);
+        }
     }
 }
 
+// Decode lazily - just record the raw bytes until we need them
 void FieldTable::decode(Buffer& buffer){
     clear();
     if (buffer.available() < 4)
         throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+    uint32_t p = buffer.getPosition();
     uint32_t len = buffer.getLong();
     if (len) {
         uint32_t available = buffer.available();
         if ((available < len) || (available < 4))
             throw IllegalArgumentException(QPID_MSG("Not enough data for field table."));
+    }
+    // Copy data into our buffer
+    cachedBytes = boost::shared_array<uint8_t>(new uint8_t[len + 4]);
+    cachedSize = len + 4;
+    buffer.setPosition(p);
+    buffer.getRawData(&cachedBytes[0], cachedSize);
+}
+
+void FieldTable::realDecode() const
+{
+    // If we've got no raw data stored up then nothing to do
+    if (!cachedBytes)
+        return;
+
+    Buffer buffer((char*)&cachedBytes[0], cachedSize);
+    uint32_t len = buffer.getLong();
+    if (len) {
+        uint32_t available = buffer.available();
         uint32_t count = buffer.getLong();
         uint32_t leftover = available - len;
         while(buffer.available() > leftover && count--){
             std::string name;
             ValuePtr value(new FieldValue);
-            
+
             buffer.getShortString(name);
             value->decode(buffer);
             values[name] = ValuePtr(value);
-        }    
+        }
     }
+    cachedSize = len + 4;
+    // We've done the delayed decoding throw away the raw data
+    // (later on we may find a way to keep this and avoid some
+    // other allocations)
+    cachedBytes.reset();
+}
+
+void FieldTable::flushRawCache() const
+{
+    cachedBytes.reset();
     cachedSize = 0;
 }
 
 bool FieldTable::operator==(const FieldTable& x) const {
+    realDecode();
+    x.realDecode();
     if (values.size() != x.values.size()) return false;
     for (ValueMap::const_iterator i =  values.begin(); i != values.end(); ++i) {
         ValueMap::const_iterator j = x.values.find(i->first);
@@ -250,29 +287,72 @@ bool FieldTable::operator==(const FieldT
 
 void FieldTable::erase(const std::string& name) 
 {
+    realDecode();
     if (values.find(name) != values.end()) {
         values.erase(name);
-        cachedSize = 0;
+        flushRawCache();
     }
 }
+
 void FieldTable::clear()
 {
     values.clear();
-    cachedSize = 0;
+    flushRawCache();
+}
+
+// Map-like interface.
+FieldTable::ValueMap::const_iterator FieldTable::begin() const
+{
+    realDecode();
+    return values.begin();
+}
+
+FieldTable::ValueMap::const_iterator FieldTable::end() const
+{
+    realDecode();
+    return values.end();
+}
+
+FieldTable::ValueMap::const_iterator FieldTable::find(const std::string& s) const
+{
+    realDecode();
+    return values.find(s);
+}
+
+FieldTable::ValueMap::iterator FieldTable::begin()
+{
+    realDecode();
+    flushRawCache();
+    return values.begin();
+}
+
+FieldTable::ValueMap::iterator FieldTable::end()
+{
+    realDecode();
+    flushRawCache();
+    return values.end();
+}
+
+FieldTable::ValueMap::iterator FieldTable::find(const std::string& s)
+{
+    realDecode();
+    flushRawCache();
+    return values.find(s);
 }
 
 std::pair<FieldTable::ValueMap::iterator, bool> FieldTable::insert(const ValueMap::value_type& value)
 {
-    cachedSize = 0;
+    realDecode();
+    flushRawCache();
     return values.insert(value);
 }
 
 FieldTable::ValueMap::iterator FieldTable::insert(ValueMap::iterator position, const ValueMap::value_type& value)
 {
-    cachedSize = 0;
+    realDecode();
+    flushRawCache();
     return values.insert(position, value);
 }
 
-
 }
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org