summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Stitcher <astitcher@apache.org>2012-03-05 19:12:52 +0000
committerAndrew Stitcher <astitcher@apache.org>2012-03-05 19:12:52 +0000
commit2bd705facb5df85356918950d10a4125e2c177a0 (patch)
treef86787b354ec7989100cad520290a080710fa1fe
parent822e4b0752fbff6284129f8bd85e529fc92bb3fa (diff)
downloadqpid-python-2bd705facb5df85356918950d10a4125e2c177a0.tar.gz
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. git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1297185 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--qpid/cpp/include/qpid/framing/FieldTable.h27
-rw-r--r--qpid/cpp/src/qpid/framing/FieldTable.cpp156
2 files changed, 131 insertions, 52 deletions
diff --git a/qpid/cpp/include/qpid/framing/FieldTable.h b/qpid/cpp/include/qpid/framing/FieldTable.h
index ce0374d829..b404a06c9a 100644
--- a/qpid/cpp/include/qpid/framing/FieldTable.h
+++ b/qpid/cpp/include/qpid/framing/FieldTable.h
@@ -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::const_iterator begin() const;
+ ValueMap::const_iterator end() const;
+ ValueMap::const_iterator find(const std::string& s) const;
- ValueMap::iterator begin() { return values.begin(); }
- ValueMap::iterator end() { return values.end(); }
- ValueMap::iterator find(const std::string& s) { return values.find(s); }
+ 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);
diff --git a/qpid/cpp/src/qpid/framing/FieldTable.cpp b/qpid/cpp/src/qpid/framing/FieldTable.cpp
index d5c42c3ade..9d33093df8 100644
--- a/qpid/cpp/src/qpid/framing/FieldTable.cpp
+++ b/qpid/cpp/src/qpid/framing/FieldTable.cpp
@@ -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& out, const FieldTable::ValueMap::value_ty
}
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& out, const FieldTable& t) {
}
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::string& name, double& value) const {
//}
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 FieldTable& x) const {
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);
}
-
}
}