diff options
| author | Andrew Stitcher <astitcher@apache.org> | 2012-03-05 19:12:52 +0000 |
|---|---|---|
| committer | Andrew Stitcher <astitcher@apache.org> | 2012-03-05 19:12:52 +0000 |
| commit | 2bd705facb5df85356918950d10a4125e2c177a0 (patch) | |
| tree | f86787b354ec7989100cad520290a080710fa1fe /qpid/cpp/src | |
| parent | 822e4b0752fbff6284129f8bd85e529fc92bb3fa (diff) | |
| download | qpid-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
Diffstat (limited to 'qpid/cpp/src')
| -rw-r--r-- | qpid/cpp/src/qpid/framing/FieldTable.cpp | 156 |
1 files changed, 118 insertions, 38 deletions
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); } - } } |
