缓冲区读取问题

一次http请求(post),会报错:

HTTP request to `http://127.0.0.1:9200/my-index-000001?pretty` failed at try 1/1 with bytes read: 0/unknown. Error: DB::Exception: Unexpected state of istream at offset 0. (Current backoff wait is 100/1600 ms)

已确定服务端成功完成工作并返回response,因为可以通过下列代码获得Received response with content length:

std::streamsize HTTPMessage::getContentLength() const
{
	const std::string& contentLength = get(CONTENT_LENGTH, EMPTY);
	if (!contentLength.empty())
	{
		if (sizeof(std::streamsize) == sizeof(Poco::Int64))
			return static_cast<std::streamsize>(NumberParser::parse64(contentLength));
		else
			return static_cast<std::streamsize>(NumberParser::parse(contentLength));
	}
	else return UNKNOWN_CONTENT_LENGTH;
}
if (response.hasContentLength())
        LOG_DEBUG(log, "Received response with content length: {}", response.getContentLength());

会打印出个log:Received response with content length: 91
说明response长度已经可以被解析。

但是最终报错:

HTTP request to `http://127.0.0.1:9200/my-index-000001?pretty` failed at try 1/1 with bytes read: 0/unknown. Error: DB::Exception: Unexpected state of istream at offset 0. (Current backoff wait is 100/1600 ms)

经过定位failed at try 1/1 with bytes read: 0/unknown 发现异常抛出点。这里read_range是个unkown。大概率是buffer没读对。同时,offset_from_begin_pos是0。

catch (const Poco::Exception & e)
        {
            /// Too many open files - non-retryable.
            if (e.code() == POCO_EMFILE)
                throw;

            /** Retry request unconditionally if nothing has been read yet.
                    * Otherwise if it is GET method retry with range header.
                    */
            bool can_retry_request = !offset_from_begin_pos || method == Poco::Net::HTTPRequest::HTTP_GET;
            if (!can_retry_request)
                throw;

            LOG_ERROR(
                log,
                "HTTP request to `{}` failed at try {}/{} with bytes read: {}/{}. "
                "Error: {}. (Current backoff wait is {}/{} ms)",
                uri.toString(),
                i + 1,
                settings.http_max_tries,
                getOffset(),
                read_range.end ? toString(*read_range.end) : "unknown",
                e.displayText(),
                milliseconds_to_wait,
                settings.http_retry_max_backoff_ms);

            on_retriable_error();
            exception = std::current_exception();
        }

经过定位问题Unexpected state of istream at offset,发现现在,gcount() = 0,并且istr.fail() = false

bool ReadBufferFromIStream::nextImpl()
{
    istr.read(internal_buffer.begin(), internal_buffer.size());
    size_t gcount = istr.gcount();

    if (!gcount)
    {
        if (istr.eof())
            return false;

        if (istr.fail())
            throw Exception(ErrorCodes::CANNOT_READ_FROM_ISTREAM, "Cannot read from istream at offset {}", count());

        throw Exception(ErrorCodes::CANNOT_READ_FROM_ISTREAM, "Unexpected state of istream at offset {}", count());
    }
    else
        working_buffer.resize(gcount);

    return true;
}

大概率是buffer读取的问题。回到上层检查buffer读取。要么是http请求用的不对导致post返回的数据没有正确读取,要么是buffer本事的读取函数有问题。http请求调用与buffer读取代码如下。point576可以被打印,尝试虚修改读取函数。

if (!rq.body.empty())
    {
        std::cout << "point" << std::endl;
        auto write_body_callback = [rq](std::ostream & os) { os << rq.body+"\n"; };
        ReadWriteBufferFromHTTP buf_test(
            uri,
            rq.http_method,
            write_body_callback,
            connection_parameters.timeouts,
            creds,
            {},
            {},
            {},
            {{"Content-Type", "application/json"}});
        std::string character;
        std::cout<<"point:576"<<std::endl;
        readStringBinary(character, buf_test);
        std::cout << "response_body:" << character << std::endl;
]

定位到读取函数后,观察到用ReadWriteBufferFromHTTP时缓冲区不能正常读写,但是他的子类PooledReadWriteBufferFromHTTP缓冲区可以正常读写。因为ReadWriteBufferFromHTTP本身对于一部分请求可以正常发送读取,因此开始的时候误以为是使用方式出错。PooledReadWriteBufferFromHTTP可以发送读取无header的请求,不能满足条件,因此决定通过继承ReadWriteBufferFromHTTPBase实现类似于PooledReadWriteBufferFromHTTP的类。并且通过.Parent父类多态来将参数传入(这部分C++).

class TestReadWriteBufferFromHTTP : public detail::ReadWriteBufferFromHTTPBase<std::shared_ptr<UpdatableSession<PooledSessionFactory>>>
{
    using SessionType = UpdatableSession<PooledSessionFactory>;
    using Parent = detail::ReadWriteBufferFromHTTPBase<std::shared_ptr<SessionType>>;

public:
    explicit TestReadWriteBufferFromHTTP(
        Poco::URI uri_,
        const std::string & method_ = {},
        OutStreamCallback out_stream_callback_ = {},
        HTTPHeaderEntries http_header_entries_ = {},
        const ConnectionTimeouts & timeouts_ = {},
        const Poco::Net::HTTPBasicCredentials & credentials_ = {},
        size_t buffer_size_ = DBMS_DEFAULT_BUFFER_SIZE,
        const UInt64 max_redirects = 0,
        size_t max_connections_per_endpoint = DEFAULT_COUNT_OF_HTTP_CONNECTIONS_PER_ENDPOINT);
}

TestReadWriteBufferFromHTTP::TestReadWriteBufferFromHTTP(
    Poco::URI uri_,
    const std::string & method_,
    OutStreamCallback out_stream_callback_,
    HTTPHeaderEntries http_header_entries_,
    const ConnectionTimeouts & timeouts_,
    const Poco::Net::HTTPBasicCredentials & credentials_,
    size_t buffer_size_,
    const UInt64 max_redirects,
    size_t max_connections_per_endpoint)
    : Parent(
        std::make_shared<SessionType>(uri_, max_redirects, std::make_shared<PooledSessionFactory>(timeouts_, max_connections_per_endpoint)),
        uri_,
        credentials_,
        method_,
        out_stream_callback_,
        buffer_size_,
        {},
        http_header_entries_)
{
}

使用TestReadWriteBufferFromHTTP类既可以实现有header发送也可以实现无header发送,至此,一个卡点问题解决。

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值