Example #1
0
LegacyReply::LegacyReply(const Message* message) {
    invariant(message->operation() == opReply);

    QueryResult::View qr = message->singleData().view2ptr();

    // should be checked by caller.
    invariant(qr.msgdata().getNetworkOp() == opReply);

    uassert(ErrorCodes::BadValue,
            str::stream() << "Got legacy command reply with a bad cursorId field,"
                          << " expected a value of 0 but got "
                          << qr.getCursorId(),
            qr.getCursorId() == 0);

    uassert(ErrorCodes::BadValue,
            str::stream() << "Got legacy command reply with a bad nReturned field,"
                          << " expected a value of 1 but got "
                          << qr.getNReturned(),
            qr.getNReturned() == 1);

    uassert(ErrorCodes::BadValue,
            str::stream() << "Got legacy command reply with a bad startingFrom field,"
                          << " expected a value of 0 but got "
                          << qr.getStartingFrom(),
            qr.getStartingFrom() == 0);

    auto status = Validator<BSONObj>::validateLoad(qr.data(), qr.dataLen());
    uassert(ErrorCodes::InvalidBSON,
            str::stream() << "Got legacy command reply with invalid BSON in the metadata field"
                          << causedBy(status),
            status.isOK());

    _commandReply = BSONObj(qr.data());
    _commandReply.shareOwnershipWith(message->sharedBuffer());

    if (_commandReply.firstElementFieldName() == "$err"_sd) {
        // Upconvert legacy errors.
        BSONObjBuilder bob;
        bob.appendAs(_commandReply.firstElement(), "errmsg");
        bob.append("ok", 0.0);
        if (auto code = _commandReply["code"]) {
            bob.append(code);
        }
        _commandReply = bob.obj();
    }

    return;
}
Example #2
0
void DBClientCursor::commandDataReceived() {
    int op = batch.m.operation();
    invariant(op == opReply || op == dbCommandReply);

    batch.nReturned = 1;
    batch.pos = 0;

    auto commandReply = rpc::makeReply(&batch.m);

    auto commandStatus = getStatusFromCommandResult(commandReply->getCommandReply());

    if (ErrorCodes::SendStaleConfig == commandStatus) {
        throw RecvStaleConfigException("stale config in DBClientCursor::dataReceived()",
                                       commandReply->getCommandReply());
    } else if (!commandStatus.isOK()) {
        wasError = true;
    }

    if (_client->getReplyMetadataReader()) {
        uassertStatusOK(_client->getReplyMetadataReader()(commandReply->getMetadata(),
                                                          _client->getServerAddress()));
    }

    // HACK: If we got an OP_COMMANDREPLY, take the reply object
    // and shove it in to an OP_REPLY message.
    if (op == dbCommandReply) {
        // Need to take ownership here as we destroy the underlying message.
        BSONObj reply = commandReply->getCommandReply().getOwned();
        batch.m.reset();
        replyToQuery(0, batch.m, reply);
    }

    QueryResult::View qr = batch.m.singleData().view2ptr();
    batch.data = qr.data();
}
Example #3
0
void DBClientCursor::dataReceived(bool& retry, string& host) {
    // If this is a reply to our initial command request.
    if (_isCommand && cursorId == 0) {
        commandDataReceived();
        return;
    }

    QueryResult::View qr = batch.m.singleData().view2ptr();
    resultFlags = qr.getResultFlags();

    if (qr.getResultFlags() & ResultFlag_ErrSet) {
        wasError = true;
    }

    if (qr.getResultFlags() & ResultFlag_CursorNotFound) {
        // cursor id no longer valid at the server.
        invariant(qr.getCursorId() == 0);

        if (!(opts & QueryOption_CursorTailable)) {
            uasserted(13127,
                      str::stream() << "cursor id " << cursorId << " didn't exist on server.");
        }

        // 0 indicates no longer valid (dead)
        cursorId = 0;
    }

    if (cursorId == 0 || !(opts & QueryOption_CursorTailable)) {
        // only set initially: we don't want to kill it on end of data
        // if it's a tailable cursor
        cursorId = qr.getCursorId();
    }

    batch.nReturned = qr.getNReturned();
    batch.pos = 0;
    batch.data = qr.data();
    batch.remainingBytes = qr.dataLen();

    _client->checkResponse(batch.data, batch.nReturned, &retry, &host);  // watches for "not master"

    if (qr.getResultFlags() & ResultFlag_ShardConfigStale) {
        BSONObj error;
        verify(peekError(&error));
        throw RecvStaleConfigException(
            (string) "stale config on lazy receive" + causedBy(getErrField(error)), error);
    }

    /* this assert would fire the way we currently work:
        verify( nReturned || cursorId == 0 );
    */
}
Example #4
0
LegacyReply::LegacyReply(const Message* message) : _message(std::move(message)) {
    invariant(message->operation() == opReply);

    QueryResult::View qr = _message->singleData().view2ptr();

    // should be checked by caller.
    invariant(qr.msgdata().getNetworkOp() == opReply);

    uassert(ErrorCodes::BadValue,
            str::stream() << "Got legacy command reply with a bad cursorId field,"
                          << " expected a value of 0 but got " << qr.getCursorId(),
            qr.getCursorId() == 0);

    uassert(ErrorCodes::BadValue,
            str::stream() << "Got legacy command reply with a bad nReturned field,"
                          << " expected a value of 1 but got " << qr.getNReturned(),
            qr.getNReturned() == 1);

    uassert(ErrorCodes::BadValue,
            str::stream() << "Got legacy command reply with a bad startingFrom field,"
                          << " expected a value of 0 but got " << qr.getStartingFrom(),
            qr.getStartingFrom() == 0);

    std::tie(_commandReply, _metadata) =
        uassertStatusOK(rpc::upconvertReplyMetadata(BSONObj(qr.data())));

    // Copy the bson array of documents from the message into
    // a contiguous area of memory owned by _docBuffer so
    // DocumentRange can be used to iterate over documents
    auto cursorElem = _commandReply[LegacyReplyBuilder::kCursorTag];
    if (cursorElem.eoo())
        return;

    BSONObj cursorObj = cursorElem.Obj();
    auto firstBatchElem = cursorObj[LegacyReplyBuilder::kFirstBatchTag];
    if (firstBatchElem.eoo())
        return;

    for (BSONObjIterator it(firstBatchElem.Obj()); it.more(); it.next()) {
        invariant((*it).isABSONObj());
        BSONObj doc = (*it).Obj();
        doc.appendSelfToBufBuilder(_docBuffer);
    }
    const char* dataBegin = _docBuffer.buf();
    const char* dataEnd = dataBegin + _docBuffer.len();
    _outputDocs = DocumentRange(dataBegin, dataEnd);

    return;
}
void NetworkInterfaceASIO::_completedWriteCallback(AsyncOp* op) {
    // If we were told to send an empty message, toRecv will be empty here.

    // TODO: handle metadata SERVER-19156
    BSONObj commandReply;
    if (op->toRecv()->empty()) {
        LOG(3) << "received an empty message";
    } else {
        QueryResult::View qr = op->toRecv()->singleData().view2ptr();
        // unavoidable copy
        commandReply = BSONObj(qr.data()).getOwned();
    }
    _completeOperation(
        op, RemoteCommandResponse(std::move(commandReply), BSONObj(), now() - op->start()));
}
Example #6
0
    void DBClientCursor::dataReceived( bool& retry, string& host ) {

        QueryResult::View qr = batch.m->singleData().view2ptr();
        resultFlags = qr.getResultFlags();

        if ( qr.getResultFlags() & ResultFlag_ErrSet ) {
            wasError = true;
        }

        if ( qr.getResultFlags() & ResultFlag_CursorNotFound ) {
            // cursor id no longer valid at the server.
            verify( qr.getCursorId() == 0 );
            cursorId = 0; // 0 indicates no longer valid (dead)
            if ( ! ( opts & QueryOption_CursorTailable ) )
                throw UserException( 13127 , "getMore: cursor didn't exist on server, possible restart or timeout?" );
        }

        if ( cursorId == 0 || ! ( opts & QueryOption_CursorTailable ) ) {
            // only set initially: we don't want to kill it on end of data
            // if it's a tailable cursor
            cursorId = qr.getCursorId();
        }

        batch.nReturned = qr.getNReturned();
        batch.pos = 0;
        batch.data = qr.data();

        _client->checkResponse( batch.data, batch.nReturned, &retry, &host ); // watches for "not master"

        if( qr.getResultFlags() & ResultFlag_ShardConfigStale ) {
            BSONObj error;
            verify( peekError( &error ) );
            throw RecvStaleConfigException( (string)"stale config on lazy receive" + causedBy( getErrField( error ) ), error );
        }

        /* this assert would fire the way we currently work:
            verify( nReturned || cursorId == 0 );
        */
    }