Status ServerSelectionMetadata::upconvert(const BSONObj& legacyCommand,
                                          const int legacyQueryFlags,
                                          BSONObjBuilder* commandBob,
                                          BSONObjBuilder* metadataBob) {
    // The secondaryOK option is equivalent to the slaveOk bit being set on legacy commands.
    BSONObjBuilder ssmBob;
    if (legacyQueryFlags & QueryOption_SlaveOk) {
        ssmBob.append(kSecondaryOkFieldName, 1);
    }

    // First we need to check if we have a wrapped command. That is, a command of the form
    // {'$query': { 'commandName': 1, ...}, '$someOption': 5, ....}. Curiously, the field name
    // of the wrapped query can be either '$query', or 'query'.
    auto swUnwrapped = unwrapCommand(legacyCommand);
    if (!swUnwrapped.isOK()) {
        return swUnwrapped.getStatus();
    }

    BSONObj maybeUnwrapped;
    bool wasWrapped;
    std::tie(wasWrapped, maybeUnwrapped) = swUnwrapped.getValue();

    if (wasWrapped) {
        // Check if legacyCommand has an invalid $maxTimeMS option.
        // TODO: Move this check elsewhere when we handle upconverting/downconverting maxTimeMS.
        if (legacyCommand.hasField("$maxTimeMS")) {
            return Status(ErrorCodes::InvalidOptions,
                          "cannot use $maxTimeMS query option with "
                          "commands; use maxTimeMS command option "
                          "instead");
        }

        // If the command was wrapped, we can write out the upconverted command now, as there
        // is nothing else we need to remove from it.
        commandBob->appendElements(maybeUnwrapped);

        auto status = extractWrappedReadPreference(legacyCommand, &ssmBob);
        if (!status.isOK()) {
            return status;
        }
    } else {
        // If the command was not wrapped, we need to check for a readPreference sent by mongos
        // on the $queryOptions field of the command. If it is set, we remove it from the
        // upconverted command, so we need to pass the command builder along.

        auto status = extractUnwrappedReadPreference(maybeUnwrapped, commandBob, &ssmBob);
        if (!status.isOK()) {
            return status;
        }
    }

    auto ssm = ssmBob.done();
    if (!ssm.isEmpty()) {
        metadataBob->append(fieldName(), ssm);
    }
    return Status::OK();
}
Beispiel #2
0
/*
This function adds the command and then recursively goes through any subcommands in the command, adding them to the list of commands (depth first search).  The resulting list only contains commands without subcommands.  This is typically used to break down commands for serialization with the ROS message type.
@param inputCommand: The top command to process
@param inputCommandList: The list to start appending to
*/
void unwrapCommand(const command &inputCommand, std::vector<command> &inputCommandList)
{
//Add top level command without subcommands
command commandBuffer = inputCommand;
commandBuffer.subCommands.clear();

inputCommandList.push_back(commandBuffer);

//Process subcommands
for(int i=0; i<inputCommand.subCommands.size(); i++)
{
unwrapCommand(inputCommand.subCommands[i], inputCommandList);
}
}
Beispiel #3
0
/*
This function decomposes the command into a ROS message for sending over the network.  ROS messages don't support containing submessages of the same type as the message, so this requires all subcommands to be decomposed into a list of simple (nonrecursive) commands.
*/
ardrone_command::serialized_ardrone_command command::serialize()
{
//Unwrap the commands so that they can be converted into ros messages
std::vector<command> commandList;
unwrapCommand(*this, commandList); //Unwrap this command into the command list

//Serialize
ardrone_command::serialized_ardrone_command buffer;
buffer.command = serializeCommandPart(commandList[0]);

for(int i=1; i<commandList.size(); i++)
{
buffer.subcommands.push_back(serializeCommandPart(commandList[i]));
}

return buffer;
}