aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Feng Xiao <xfxyjwf@gmail.com>2016-11-10 16:38:04 -0800
committerGravatar Feng Xiao <xfxyjwf@gmail.com>2016-11-10 18:14:05 -0800
commitbd158fc23849663f1cdb430ddea2dbab9deb336f (patch)
tree3b34e3fa84a82efb1fa7b685cf826ce0b52bc93e
parentdf8390790aae6025e95687a37eea81a4757966d0 (diff)
Speed up JSON parsing.
It turns out calling StringOutputStream::Next()/BackUp() repeatedly is very costly in opensource protobuf because it keeps resize() the string back and forth. The current JSON conversion API suffers this problem and leads to ridiculously long parsing time: https://github.com/google/protobuf/issues/2305#issuecomment-257785492 This change fixes the problem but caching the buffer of Next() and avoid calling BackUp() as much as possible.
-rw-r--r--src/google/protobuf/util/json_util.cc29
-rw-r--r--src/google/protobuf/util/json_util.h5
2 files changed, 20 insertions, 14 deletions
diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc
index d7ac2dba..5974cc4a 100644
--- a/src/google/protobuf/util/json_util.cc
+++ b/src/google/protobuf/util/json_util.cc
@@ -49,22 +49,25 @@ namespace protobuf {
namespace util {
namespace internal {
+ZeroCopyStreamByteSink::~ZeroCopyStreamByteSink() {
+ stream_->BackUp(buffer_size_);
+}
+
void ZeroCopyStreamByteSink::Append(const char* bytes, size_t len) {
- while (len > 0) {
- void* buffer;
- int length;
- if (!stream_->Next(&buffer, &length)) {
- // There isn't a way for ByteSink to report errors.
+ while (true) {
+ if (len <= buffer_size_) {
+ memcpy(buffer_, bytes, len);
+ buffer_ = static_cast<char*>(buffer_) + len;
+ buffer_size_ -= len;
return;
}
- if (len < length) {
- memcpy(buffer, bytes, len);
- stream_->BackUp(length - len);
- break;
- } else {
- memcpy(buffer, bytes, length);
- bytes += length;
- len -= length;
+ memcpy(buffer_, bytes, buffer_size_);
+ bytes += buffer_size_;
+ len -= buffer_size_;
+ if (!stream_->Next(&buffer_, &buffer_size_)) {
+ // There isn't a way for ByteSink to report errors.
+ buffer_size_ = 0;
+ return;
}
}
}
diff --git a/src/google/protobuf/util/json_util.h b/src/google/protobuf/util/json_util.h
index 6d3cee52..0e45ef81 100644
--- a/src/google/protobuf/util/json_util.h
+++ b/src/google/protobuf/util/json_util.h
@@ -172,12 +172,15 @@ namespace internal {
class LIBPROTOBUF_EXPORT ZeroCopyStreamByteSink : public strings::ByteSink {
public:
explicit ZeroCopyStreamByteSink(io::ZeroCopyOutputStream* stream)
- : stream_(stream) {}
+ : stream_(stream), buffer_size_(0) {}
+ ~ZeroCopyStreamByteSink();
virtual void Append(const char* bytes, size_t len);
private:
io::ZeroCopyOutputStream* stream_;
+ void* buffer_;
+ int buffer_size_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyStreamByteSink);
};