Beispiel #1
0
   const CHAR* _omAgentNodeMgr::_getSvcNameFromArg( const CHAR * arg )
   {
      const CHAR *pSvcName = NULL ;

      try
      {
         BSONObj objArg1( arg ) ;
         BSONElement e = objArg1.getField( PMD_OPTION_SVCNAME ) ;
         if ( e.type() != String )
         {
            PD_LOG( PDERROR, "Param[%s] type[%s] error: %s",
                    PMD_OPTION_SVCNAME, e.type(), e.toString().c_str() ) ;
            goto error ;
         }
         pSvcName = e.valuestrsafe() ;
      }
      catch( std::exception &e )
      {
         PD_LOG( PDERROR, "Ocuur exception: %s", e.what() ) ;
         goto error ;
      }

   done:
      return pSvcName ;
   error:
      goto done ;
   }
Beispiel #2
0
    int64_t WiredTigerUtil::getIdentSize(WT_SESSION* s,
                                         const std::string& uri ) {
        BSONObjBuilder b;
        Status status = WiredTigerUtil::exportTableToBSON(s,
                                                          "statistics:" + uri,
                                                          "statistics=(fast)",
                                                          &b);
        if ( !status.isOK() ) {
            if ( status.code() == ErrorCodes::CursorNotFound ) {
                // ident gone, so its 0
                return 0;
            }
            uassertStatusOK( status );
        }

        BSONObj obj = b.obj();
        BSONObj sub = obj["block-manager"].Obj();
        BSONElement e = sub["file size in bytes"];
        invariant( e.type() );

        if ( e.isNumber() )
            return e.safeNumberLong();

        return strtoull( e.valuestrsafe(), NULL, 10 );
    }
void CollectionShardingState::onDeleteOp(OperationContext* txn,
                                         const CollectionShardingState::DeleteState& deleteState) {
    dassert(txn->lockState()->isCollectionLockedForMode(_nss.ns(), MODE_IX));

    if (txn->writesAreReplicated() && serverGlobalParams.clusterRole == ClusterRole::ShardServer &&
        _nss == NamespaceString::kConfigCollectionNamespace) {
        if (auto idElem = deleteState.idDoc["_id"]) {
            uassert(40070,
                    "cannot delete shardIdentity document while in --shardsvr mode",
                    idElem.str() != ShardIdentityType::IdName);
        }
    }

    // For backwards compatibility, cancel a pending asynchronous addShard task created on the
    // primary config as a result of a 3.2 mongos doing addShard for the shard with id
    // deletedDocId.
    if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer &&
        _nss == ShardType::ConfigNS) {
        BSONElement idElement = deleteState.idDoc["_id"];
        invariant(!idElement.eoo());
        auto shardIdStr = idElement.valuestrsafe();
        txn->recoveryUnit()->registerChange(
            new RemoveShardLogOpHandler(txn, ShardId(std::move(shardIdStr))));
    }

    checkShardVersionOrThrow(txn);

    if (_sourceMgr && deleteState.isMigrating) {
        _sourceMgr->getCloner()->onDeleteOp(txn, deleteState.idDoc);
    }
}
Beispiel #4
0
    void run() {
        OperationContextImpl txn;
        Client::WriteContext ctx(&txn, _ns);

        int numFinishedIndexesStart = _catalog->numIndexesReady(&txn);

        Helpers::ensureIndex(&txn, _coll, BSON("x" << 1), false, "_x_0");
        Helpers::ensureIndex(&txn, _coll, BSON("y" << 1), false, "_y_0");

        ASSERT_TRUE(_catalog->numIndexesReady(&txn) == numFinishedIndexesStart+2);

        IndexCatalog::IndexIterator ii = _catalog->getIndexIterator(&txn,false);
        int indexesIterated = 0;
        bool foundIndex = false;
        while (ii.more()) {
            IndexDescriptor* indexDesc = ii.next();
            indexesIterated++;
            BSONObjIterator boit(indexDesc->infoObj());
            while (boit.more() && !foundIndex) {
                BSONElement e = boit.next();
                if (str::equals(e.fieldName(), "name") &&
                        str::equals(e.valuestrsafe(), "_y_0")) {
                    foundIndex = true;
                    break;
                }
            }
        }

        ctx.commit();
        ASSERT_TRUE(indexesIterated == _catalog->numIndexesReady(&txn));
        ASSERT_TRUE(foundIndex);
    }
Beispiel #5
0
        virtual Status set( const BSONElement& newValueElement ) {
            if (!theReplSet) {
                return Status( ErrorCodes::BadValue, "replication is not enabled" );
            }

            std::string prefetch = newValueElement.valuestrsafe();
            return setFromString( prefetch );
        }
Beispiel #6
0
 string FTSSpec::getLanguageToUse( const BSONObj& userDoc ) const {
     BSONElement e = userDoc[_languageOverrideField];
     if ( e.type() == String ) {
         const char * x = e.valuestrsafe();
         if ( strlen( x ) > 0 )
             return x;
     }
     return _defaultLanguage;
 }
Beispiel #7
0
    virtual Status set(const BSONElement& newValueElement) {
        if (getGlobalReplicationCoordinator()->getReplicationMode() !=
            ReplicationCoordinator::modeReplSet) {
            return Status(ErrorCodes::BadValue, "replication is not enabled");
        }

        std::string prefetch = newValueElement.valuestrsafe();
        return setFromString(prefetch);
    }
const FTSLanguage& FTSSpec::_getLanguageToUseV1(const BSONObj& userDoc) const {
    BSONElement e = userDoc[_languageOverrideField];
    if (e.type() == String) {
        const char* x = e.valuestrsafe();
        if (strlen(x) > 0) {
            StatusWithFTSLanguage swl = FTSLanguage::make(x, TEXT_INDEX_VERSION_1);
            dassert(swl.isOK());  // make() w/ TEXT_INDEX_VERSION_1 guaranteed to not fail.
            return *swl.getValue();
        }
    }
    return *_defaultLanguage;
}
Beispiel #9
0
StatusWith<ParsedDistinct> ParsedDistinct::parse(OperationContext* txn,
                                                 const NamespaceString& nss,
                                                 const BSONObj& cmdObj,
                                                 const ExtensionsCallback& extensionsCallback,
                                                 bool isExplain) {
    // Extract the key field.
    BSONElement keyElt;
    auto statusKey = bsonExtractTypedField(cmdObj, kKeyField, BSONType::String, &keyElt);
    if (!statusKey.isOK()) {
        return {statusKey};
    }
    auto key = keyElt.valuestrsafe();

    auto qr = stdx::make_unique<QueryRequest>(nss);

    // Extract the query field. If the query field is nonexistent, an empty query is used.
    if (BSONElement queryElt = cmdObj[kQueryField]) {
        if (queryElt.type() == BSONType::Object) {
            qr->setFilter(queryElt.embeddedObject());
        } else if (queryElt.type() != BSONType::jstNULL) {
            return Status(ErrorCodes::TypeMismatch,
                          str::stream() << "\"" << kQueryField << "\" had the wrong type. Expected "
                                        << typeName(BSONType::Object)
                                        << " or "
                                        << typeName(BSONType::jstNULL)
                                        << ", found "
                                        << typeName(queryElt.type()));
        }
    }

    // Extract the collation field, if it exists.
    if (BSONElement collationElt = cmdObj[kCollationField]) {
        if (collationElt.type() != BSONType::Object) {
            return Status(ErrorCodes::TypeMismatch,
                          str::stream() << "\"" << kCollationField
                                        << "\" had the wrong type. Expected "
                                        << typeName(BSONType::Object)
                                        << ", found "
                                        << typeName(collationElt.type()));
        }
        qr->setCollation(collationElt.embeddedObject());
    }

    qr->setExplain(isExplain);

    auto cq = CanonicalQuery::canonicalize(txn, std::move(qr), extensionsCallback);
    if (!cq.isOK()) {
        return cq.getStatus();
    }

    return ParsedDistinct(std::move(cq.getValue()), std::move(key));
}
Beispiel #10
0
    /**
     * Used by explain() and run() to get the PlanExecutor for the query.
     */
    StatusWith<unique_ptr<PlanExecutor>> getPlanExecutor(OperationContext* txn,
                                                         Collection* collection,
                                                         const string& ns,
                                                         const BSONObj& cmdObj,
                                                         bool isExplain) const {
        // Extract the key field.
        BSONElement keyElt;
        auto statusKey = bsonExtractTypedField(cmdObj, kKeyField, BSONType::String, &keyElt);
        if (!statusKey.isOK()) {
            return {statusKey};
        }
        string key = keyElt.valuestrsafe();

        // Extract the query field. If the query field is nonexistent, an empty query is used.
        BSONObj query;
        if (BSONElement queryElt = cmdObj[kQueryField]) {
            if (queryElt.type() == BSONType::Object) {
                query = queryElt.embeddedObject();
            } else if (queryElt.type() != BSONType::jstNULL) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "\"" << kQueryField
                                            << "\" had the wrong type. Expected "
                                            << typeName(BSONType::Object) << " or "
                                            << typeName(BSONType::jstNULL) << ", found "
                                            << typeName(queryElt.type()));
            }
        }

        // Extract the collation field, if it exists.
        // TODO SERVER-23473: Pass this collation spec object down so that it can be converted into
        // a CollatorInterface.
        BSONObj collation;
        if (BSONElement collationElt = cmdObj[kCollationField]) {
            if (collationElt.type() != BSONType::Object) {
                return Status(ErrorCodes::TypeMismatch,
                              str::stream() << "\"" << kCollationField
                                            << "\" had the wrong type. Expected "
                                            << typeName(BSONType::Object) << ", found "
                                            << typeName(collationElt.type()));
            }
            collation = collationElt.embeddedObject();
        }

        auto executor = getExecutorDistinct(
            txn, collection, ns, query, key, isExplain, PlanExecutor::YIELD_AUTO);
        if (!executor.isOK()) {
            return executor.getStatus();
        }

        return std::move(executor.getValue());
    }
BSONObj removeFile(const BSONObj& args, void* data) {
    BSONElement e = singleArg(args);
    bool found = false;

    boost::filesystem::path root(e.valuestrsafe());
    if (boost::filesystem::exists(root)) {
        found = true;
        boost::filesystem::remove_all(root);
    }

    BSONObjBuilder b;
    b.appendBool("removed", found);
    return b.obj();
}
Beispiel #12
0
    /**
     * Returns true if 'e' contains a valid operation.
     */
    bool _checkOperation(const BSONElement& e, string& errmsg) {
        if (e.type() != Object) {
            errmsg = str::stream() << "op not an object: " << e.fieldName();
            return false;
        }
        BSONObj obj = e.Obj();
        // op - operation type
        BSONElement opElement = obj.getField("op");
        if (opElement.eoo()) {
            errmsg = str::stream()
                << "op does not contain required \"op\" field: " << e.fieldName();
            return false;
        }
        if (opElement.type() != mongol::String) {
            errmsg = str::stream() << "\"op\" field is not a string: " << e.fieldName();
            return false;
        }
        // operation type -- see logOp() comments for types
        const char* opType = opElement.valuestrsafe();
        if (*opType == '\0') {
            errmsg = str::stream() << "\"op\" field value cannot be empty: " << e.fieldName();
            return false;
        }

        // ns - namespace
        // Only operations of type 'n' are allowed to have an empty namespace.
        BSONElement nsElement = obj.getField("ns");
        if (nsElement.eoo()) {
            errmsg = str::stream()
                << "op does not contain required \"ns\" field: " << e.fieldName();
            return false;
        }
        if (nsElement.type() != mongol::String) {
            errmsg = str::stream() << "\"ns\" field is not a string: " << e.fieldName();
            return false;
        }
        if (nsElement.String().find('\0') != std::string::npos) {
            errmsg = str::stream() << "namespaces cannot have embedded null characters";
            return false;
        }
        if (*opType != 'n' && nsElement.String().empty()) {
            errmsg = str::stream()
                << "\"ns\" field value cannot be empty when op type is not 'n': " << e.fieldName();
            return false;
        }
        return true;
    }
Status WriteConcernOptions::parse(const BSONObj& obj) {
    reset();
    if (obj.isEmpty()) {
        return Status(ErrorCodes::FailedToParse, "write concern object cannot be empty");
    }

    BSONElement jEl = obj["j"];
    if (!jEl.eoo() && !jEl.isNumber() && jEl.type() != Bool) {
        return Status(ErrorCodes::FailedToParse, "j must be numeric or a boolean value");
    }

    const bool j = jEl.trueValue();

    BSONElement fsyncEl = obj["fsync"];
    if (!fsyncEl.eoo() && !fsyncEl.isNumber() && fsyncEl.type() != Bool) {
        return Status(ErrorCodes::FailedToParse, "fsync must be numeric or a boolean value");
    }

    const bool fsync = fsyncEl.trueValue();

    if (j && fsync)
        return Status(ErrorCodes::FailedToParse, "fsync and j options cannot be used together");

    if (j) {
        syncMode = SyncMode::JOURNAL;
    } else if (fsync) {
        syncMode = SyncMode::FSYNC;
    } else if (!jEl.eoo()) {
        syncMode = SyncMode::NONE;
    }

    BSONElement e = obj["w"];
    if (e.isNumber()) {
        wNumNodes = e.numberInt();
    } else if (e.type() == String) {
        wMode = e.valuestrsafe();
    } else if (e.eoo() || e.type() == jstNULL || e.type() == Undefined) {
        wNumNodes = 1;
    } else {
        return Status(ErrorCodes::FailedToParse, "w has to be a number or a string");
    }

    wTimeout = obj["wtimeout"].numberInt();

    return Status::OK();
}
Beispiel #14
0
        BSONObj cat(const BSONObj& args){
            BSONElement e = oneArg(args);
            stringstream ss;
            ifstream f(e.valuestrsafe());
            uassert(CANT_OPEN_FILE, "couldn't open file", f.is_open() );

            streamsize sz = 0;
            while( 1 ) {
                char ch = 0;
                // slow...maybe change one day
                f.get(ch);
                if( ch == 0 ) break;
                ss << ch;
                sz += 1;
                uassert(13301, "cat() : file to big to load as a variable", sz < 1024 * 1024 * 16);
            }
            return BSON( "" << ss.str() );
        }
Beispiel #15
0
        BSONObj md5sumFile(const BSONObj& args){
            BSONElement e = oneArg(args);
            stringstream ss;
            FILE* f = fopen(e.valuestrsafe(), "rb");
            uassert(CANT_OPEN_FILE, "couldn't open file", f );

            md5digest d;
            md5_state_t st;
            md5_init(&st);

            enum {BUFLEN = 4*1024};
            char buffer[BUFLEN];
            int bytes_read;
            while( (bytes_read = fread(buffer, 1, BUFLEN, f)) ) {
                md5_append( &st , (const md5_byte_t*)(buffer) , bytes_read );
            }

            md5_finish(&st, d);
            return BSON( "" << digestToString( d ) );
        }
        void run() {
            Client::WriteContext ctx(_ns);
            int numFinishedIndexesStart = _catalog->numIndexesReady();

            BSONObjBuilder b1;
            b1.append("key", BSON("x" << 1));
            b1.append("ns", _ns);
            b1.append("name", "_x_0");
            _catalog->createIndex(b1.obj(), true);

            BSONObjBuilder b2;
            b2.append("key", BSON("y" << 1));
            b2.append("ns", _ns);
            b2.append("name", "_y_0");
            _catalog->createIndex(b2.obj(), true);

            ASSERT_TRUE(_catalog->numIndexesReady() == numFinishedIndexesStart+2);

            IndexCatalog::IndexIterator ii = _catalog->getIndexIterator(false);
            int indexesIterated = 0;
            bool foundIndex = false;
            while (ii.more()) {
                IndexDescriptor* indexDesc = ii.next();
                indexesIterated++;
                BSONObjIterator boit(indexDesc->infoObj());
                while (boit.more() && !foundIndex) {
                    BSONElement e = boit.next();
                    if (str::equals(e.fieldName(), "name") &&
                            str::equals(e.valuestrsafe(), "_y_0")) {
                        foundIndex = true;
                        break;
                    }
                }
            }

            ASSERT_TRUE(indexesIterated == _catalog->numIndexesReady());
            ASSERT_TRUE(foundIndex);
        }
    Status WriteConcernOptions::parse( const BSONObj& obj ) {
        if ( obj.isEmpty() ) {
            return Status( ErrorCodes::BadValue, "write concern object cannot be empty" );
        }

        bool j = obj["j"].trueValue();
        bool fsync = obj["fsync"].trueValue();

        if ( j & fsync )
            return Status( ErrorCodes::BadValue, "fsync and j options cannot be used together" );

        if ( j ) {
            syncMode = JOURNAL;
        }
        if ( fsync ) {
            syncMode = FSYNC;
        }

        BSONElement e = obj["w"];
        if ( e.isNumber() ) {
            wNumNodes = e.numberInt();
        }
        else if ( e.type() == String ) {
            wMode = e.valuestrsafe();
        }
        else if ( e.eoo() ||
                  e.type() == jstNULL ||
                  e.type() == Undefined ) {
            wNumNodes = 1;
        }
        else {
            return Status( ErrorCodes::BadValue, "w has to be a number or a string" );
        }

        wTimeout = obj["wtimeout"].numberInt();

        return Status::OK();
    }
    // static
    void IndexBoundsBuilder::translate(const MatchExpression* expr, const BSONElement& elt,
                                       OrderedIntervalList* oilOut, bool* exactOut) {
        int direction = (elt.numberInt() >= 0) ? 1 : -1;

        Interval interval;
        bool exact = false;
        oilOut->name = elt.fieldName();

        bool isHashed = false;
        if (mongoutils::str::equals("hashed", elt.valuestrsafe())) {
            isHashed = true;
        }

        if (isHashed) {
            verify(MatchExpression::EQ == expr->matchType()
                   || MatchExpression::MATCH_IN == expr->matchType());
        }

        if (MatchExpression::EQ == expr->matchType()) {
            const EqualityMatchExpression* node =
                static_cast<const EqualityMatchExpression*>(expr);

            // We have to copy the data out of the parse tree and stuff it into the index
            // bounds.  BSONValue will be useful here.
            BSONObj dataObj;

            if (isHashed) {
                dataObj = ExpressionMapping::hash(node->getData());
            }
            else {
                dataObj = objFromElement(node->getData());
            }

            // UNITTEST 11738048
            if (Array == dataObj.firstElement().type()) {
                // XXX: build better bounds
                warning() << "building lazy bounds for " << expr->toString() << endl;
                interval = allValues();
                exact = false;
            }
            else {
                verify(dataObj.isOwned());
                interval = makePointInterval(dataObj);
                // XXX: it's exact if the index isn't sparse
                if (dataObj.firstElement().isNull()) {
                    exact = false;
                }
                else if (isHashed) {
                    exact = false;
                }
                else {
                    exact = true;
                }
            }
        }
        else if (MatchExpression::LTE == expr->matchType()) {
            const LTEMatchExpression* node = static_cast<const LTEMatchExpression*>(expr);
            BSONElement dataElt = node->getData();
            BSONObjBuilder bob;
            bob.appendMinForType("", dataElt.type());
            bob.append(dataElt);
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            interval = makeRangeInterval(dataObj, true, true);
            // XXX: only exact if not (null or array)
            exact = true;
        }
        else if (MatchExpression::LT == expr->matchType()) {
            const LTMatchExpression* node = static_cast<const LTMatchExpression*>(expr);
            BSONElement dataElt = node->getData();
            BSONObjBuilder bob;
            bob.appendMinForType("", dataElt.type());
            bob.append(dataElt);
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            interval = makeRangeInterval(dataObj, true, false);
            // XXX: only exact if not (null or array)
            exact = true;
        }
        else if (MatchExpression::GT == expr->matchType()) {
            const GTMatchExpression* node = static_cast<const GTMatchExpression*>(expr);
            BSONElement dataElt = node->getData();
            BSONObjBuilder bob;
            bob.append(node->getData());
            bob.appendMaxForType("", dataElt.type());
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            interval = makeRangeInterval(dataObj, false, true);
            // XXX: only exact if not (null or array)
            exact = true;
        }
        else if (MatchExpression::GTE == expr->matchType()) {
            const GTEMatchExpression* node = static_cast<const GTEMatchExpression*>(expr);
            BSONElement dataElt = node->getData();

            BSONObjBuilder bob;
            bob.append(dataElt);
            bob.appendMaxForType("", dataElt.type());
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            interval = makeRangeInterval(dataObj, true, true);
            // XXX: only exact if not (null or array)
            exact = true;
        }
        else if (MatchExpression::REGEX == expr->matchType()) {
            warning() << "building lazy bounds for " << expr->toString() << endl;
            interval = allValues();
            exact = false;
        }
        else if (MatchExpression::MOD == expr->matchType()) {
            BSONObjBuilder bob;
            bob.appendMinForType("", NumberDouble);
            bob.appendMaxForType("", NumberDouble);
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            interval = makeRangeInterval(dataObj, true, true);
            exact = false;
        }
        else if (MatchExpression::MATCH_IN == expr->matchType()) {
            warning() << "building lazy bounds for " << expr->toString() << endl;
            interval = allValues();
            exact = false;
        }
        else if (MatchExpression::TYPE_OPERATOR == expr->matchType()) {
            const TypeMatchExpression* tme = static_cast<const TypeMatchExpression*>(expr);
            BSONObjBuilder bob;
            bob.appendMinForType("", tme->getData());
            bob.appendMaxForType("", tme->getData());
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            interval = makeRangeInterval(dataObj, true, true);
            exact = false;
        }
        else if (MatchExpression::MATCH_IN == expr->matchType()) {
            warning() << "building lazy bounds for " << expr->toString() << endl;
            interval = allValues();
            exact = false;
        }
        else if (MatchExpression::GEO == expr->matchType()) {
            const GeoMatchExpression* gme = static_cast<const GeoMatchExpression*>(expr);
            // Can only do this for 2dsphere.
            if (!mongoutils::str::equals("2dsphere", elt.valuestrsafe())) {
                warning() << "Planner error trying to build geo bounds for " << elt.toString()
                          << " index element.";
                verify(0);
            }

            const S2Region& region = gme->getGeoQuery().getRegion();
            ExpressionMapping::cover2dsphere(region, oilOut);
            *exactOut = false;
            // XXX: restructure this method
            return;
        }
        else {
            warning() << "Planner error, trying to build bounds for expr "
                      << expr->toString() << endl;
            verify(0);
        }

        if (-1 == direction) {
            reverseInterval(&interval);
        }

        oilOut->intervals.push_back(interval);
        *exactOut = exact;
    }
Status WriteConcernOptions::parse(const BSONObj& obj) {
    reset();
    if (obj.isEmpty()) {
        return Status(ErrorCodes::FailedToParse, "write concern object cannot be empty");
    }

    BSONElement jEl;
    BSONElement fsyncEl;
    BSONElement wEl;


    for (auto e : obj) {
        const auto fieldName = e.fieldNameStringData();
        if (fieldName == kJFieldName) {
            jEl = e;
            if (!jEl.isNumber() && jEl.type() != Bool) {
                return Status(ErrorCodes::FailedToParse, "j must be numeric or a boolean value");
            }
        } else if (fieldName == kFSyncFieldName) {
            fsyncEl = e;
            if (!fsyncEl.isNumber() && fsyncEl.type() != Bool) {
                return Status(ErrorCodes::FailedToParse,
                              "fsync must be numeric or a boolean value");
            }
        } else if (fieldName == kWFieldName) {
            wEl = e;
        } else if (fieldName == kWTimeoutFieldName) {
            wTimeout = e.numberInt();
        } else if (fieldName == kWElectionIdFieldName) {
            // Ignore.
        } else if (fieldName == kWOpTimeFieldName) {
            // Ignore.
        } else if (fieldName.equalCaseInsensitive(kGetLastErrorFieldName)) {
            // Ignore GLE field.
        } else {
            return Status(ErrorCodes::FailedToParse,
                          str::stream() << "unrecognized write concern field: " << fieldName);
        }
    }

    const bool j = jEl.trueValue();
    const bool fsync = fsyncEl.trueValue();

    if (j && fsync)
        return Status(ErrorCodes::FailedToParse, "fsync and j options cannot be used together");

    if (j) {
        syncMode = SyncMode::JOURNAL;
    } else if (fsync) {
        syncMode = SyncMode::FSYNC;
    } else if (!jEl.eoo()) {
        syncMode = SyncMode::NONE;
    }

    if (wEl.isNumber()) {
        wNumNodes = wEl.numberInt();
    } else if (wEl.type() == String) {
        wMode = wEl.valuestrsafe();
    } else if (wEl.eoo() || wEl.type() == jstNULL || wEl.type() == Undefined) {
        wNumNodes = 1;
    } else {
        return Status(ErrorCodes::FailedToParse, "w has to be a number or a string");
    }

    return Status::OK();
}
    // static
    void IndexBoundsBuilder::translate(const MatchExpression* expr, const BSONElement& elt,
                                       OrderedIntervalList* oilOut, bool* exactOut) {
        oilOut->name = elt.fieldName();

        bool isHashed = false;
        if (mongoutils::str::equals("hashed", elt.valuestrsafe())) {
            isHashed = true;
        }

        if (isHashed) {
            verify(MatchExpression::EQ == expr->matchType()
                   || MatchExpression::MATCH_IN == expr->matchType());
        }

        if (MatchExpression::ELEM_MATCH_VALUE == expr->matchType()) {
            OrderedIntervalList acc;
            bool exact;
            translate(expr->getChild(0), elt, &acc, &exact);
            if (!exact) {
                *exactOut = false;
            }
            for (size_t i = 1; i < expr->numChildren(); ++i) {
                OrderedIntervalList next;
                translate(expr->getChild(i), elt, &next, &exact);
                if (!exact) {
                    *exactOut = false;
                }
                intersectize(next, &acc);
            }

            for (size_t i = 0; i < acc.intervals.size(); ++i) {
                oilOut->intervals.push_back(acc.intervals[i]);
            }

            if (!oilOut->intervals.empty()) {
                std::sort(oilOut->intervals.begin(), oilOut->intervals.end(), IntervalComparison);
            }
        }
        else if (MatchExpression::EQ == expr->matchType()) {
            const EqualityMatchExpression* node = static_cast<const EqualityMatchExpression*>(expr);
            translateEquality(node->getData(), isHashed, oilOut, exactOut);
        }
        else if (MatchExpression::LTE == expr->matchType()) {
            const LTEMatchExpression* node = static_cast<const LTEMatchExpression*>(expr);
            BSONElement dataElt = node->getData();

            // Everything is <= MaxKey.
            if (MaxKey == dataElt.type()) {
                oilOut->intervals.push_back(allValues());
                *exactOut = true;
                return;
            }

            BSONObjBuilder bob;
            bob.appendMinForType("", dataElt.type());
            bob.appendAs(dataElt, "");
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true));
            // XXX: only exact if not (null or array)
            *exactOut = true;
        }
        else if (MatchExpression::LT == expr->matchType()) {
            const LTMatchExpression* node = static_cast<const LTMatchExpression*>(expr);
            BSONElement dataElt = node->getData();

            // Everything is <= MaxKey.
            if (MaxKey == dataElt.type()) {
                oilOut->intervals.push_back(allValues());
                *exactOut = true;
                return;
            }

            BSONObjBuilder bob;
            bob.appendMinForType("", dataElt.type());
            bob.appendAs(dataElt, "");
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            QLOG() << "data obj is " << dataObj.toString() << endl;
            oilOut->intervals.push_back(makeRangeInterval(dataObj, true, false));
            // XXX: only exact if not (null or array)
            *exactOut = true;
        }
        else if (MatchExpression::GT == expr->matchType()) {
            const GTMatchExpression* node = static_cast<const GTMatchExpression*>(expr);
            BSONElement dataElt = node->getData();

            // Everything is > MinKey.
            if (MinKey == dataElt.type()) {
                oilOut->intervals.push_back(allValues());
                *exactOut = true;
                return;
            }

            BSONObjBuilder bob;
            bob.appendAs(node->getData(), "");
            bob.appendMaxForType("", dataElt.type());
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            oilOut->intervals.push_back(makeRangeInterval(dataObj, false, true));
            // XXX: only exact if not (null or array)
            *exactOut = true;
        }
        else if (MatchExpression::GTE == expr->matchType()) {
            const GTEMatchExpression* node = static_cast<const GTEMatchExpression*>(expr);
            BSONElement dataElt = node->getData();

            // Everything is >= MinKey.
            if (MinKey == dataElt.type()) {
                oilOut->intervals.push_back(allValues());
                *exactOut = true;
                return;
            }

            BSONObjBuilder bob;
            bob.appendAs(dataElt, "");
            bob.appendMaxForType("", dataElt.type());
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());

            oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true));
            // XXX: only exact if not (null or array)
            *exactOut = true;
        }
        else if (MatchExpression::REGEX == expr->matchType()) {
            const RegexMatchExpression* rme = static_cast<const RegexMatchExpression*>(expr);
            translateRegex(rme, oilOut, exactOut);
        }
        else if (MatchExpression::MOD == expr->matchType()) {
            BSONObjBuilder bob;
            bob.appendMinForType("", NumberDouble);
            bob.appendMaxForType("", NumberDouble);
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true));
            *exactOut = false;
        }
        else if (MatchExpression::TYPE_OPERATOR == expr->matchType()) {
            const TypeMatchExpression* tme = static_cast<const TypeMatchExpression*>(expr);
            BSONObjBuilder bob;
            bob.appendMinForType("", tme->getData());
            bob.appendMaxForType("", tme->getData());
            BSONObj dataObj = bob.obj();
            verify(dataObj.isOwned());
            oilOut->intervals.push_back(makeRangeInterval(dataObj, true, true));
            *exactOut = false;
        }
        else if (MatchExpression::MATCH_IN == expr->matchType()) {
            const InMatchExpression* ime = static_cast<const InMatchExpression*>(expr);
            const ArrayFilterEntries& afr = ime->getData();

            *exactOut = true;

            // Create our various intervals.

            bool thisBoundExact = false;
            for (BSONElementSet::iterator it = afr.equalities().begin();
                 it != afr.equalities().end(); ++it) {

                translateEquality(*it, isHashed, oilOut, &thisBoundExact);
                if (!thisBoundExact) {
                    *exactOut = false;
                }
            }

            for (size_t i = 0; i < afr.numRegexes(); ++i) {
                translateRegex(afr.regex(i), oilOut, &thisBoundExact);
                if (!thisBoundExact) {
                    *exactOut = false;
                }
            }

            // XXX: what happens here?
            if (afr.hasNull()) { }
            // XXX: what happens here as well?
            if (afr.hasEmptyArray()) { }

            unionize(oilOut);
        }
        else if (MatchExpression::GEO == expr->matchType()) {
            const GeoMatchExpression* gme = static_cast<const GeoMatchExpression*>(expr);
            // Can only do this for 2dsphere.
            if (!mongoutils::str::equals("2dsphere", elt.valuestrsafe())) {
                warning() << "Planner error trying to build geo bounds for " << elt.toString()
                          << " index element.";
                verify(0);
            }

            const S2Region& region = gme->getGeoQuery().getRegion();
            ExpressionMapping::cover2dsphere(region, oilOut);
            *exactOut = false;
        }
        else {
            warning() << "Planner error, trying to build bounds for expr "
                      << expr->toString() << endl;
            verify(0);
        }
    }
    Status validateKeyPattern(const BSONObj& key) {
        const ErrorCodes::Error code = ErrorCodes::CannotCreateIndex;

        if ( key.objsize() > 2048 )
            return Status(code, "Index key pattern too large.");

        if ( key.isEmpty() )
            return Status(code, "Index keys cannot be empty.");

        string pluginName = IndexNames::findPluginName( key );
        if ( pluginName.size() ) {
            if ( !IndexNames::isKnownName( pluginName ) )
                return Status(code,
                              mongoutils::str::stream() << "Unknown index plugin '"
                                                        << pluginName << '\'');
        }

        BSONObjIterator it( key );
        while ( it.more() ) {
            BSONElement keyElement = it.next();

            if ( !keyElement.isNumber() && keyElement.type() != String ) {
                return Status(code, "Index keys must have numeric type or string type.");
            }

            if ( keyElement.type() == String && pluginName != keyElement.str() ) {
                return Status(code, "Can't use more than one index plugin for a single index.");
            }

            // Ensure that the fields on which we are building the index are valid: a field must not
            // begin with a '$' unless it is part of a DBRef or text index, and a field path cannot
            // contain an empty field. If a field cannot be created or updated, it should not be
            // indexable.

            FieldRef keyField( keyElement.fieldName() );

            const size_t numParts = keyField.numParts();
            if ( numParts == 0 ) {
                return Status(code, "Index keys cannot be an empty field.");
            }

            // "$**" is acceptable for a text index.
            if ( mongoutils::str::equals( keyElement.fieldName(), "$**" ) &&
                 keyElement.valuestrsafe() == IndexNames::TEXT )
                continue;


            for ( size_t i = 0; i != numParts; ++i ) {
                const StringData part = keyField.getPart(i);

                // Check if the index key path contains an empty field.
                if ( part.empty() ) {
                    return Status(code, "Index keys cannot contain an empty field.");
                }

                if ( part[0] != '$' )
                    continue;

                // Check if the '$'-prefixed field is part of a DBRef: since we don't have the
                // necessary context to validate whether this is a proper DBRef, we allow index
                // creation on '$'-prefixed names that match those used in a DBRef.
                const bool mightBePartOfDbRef = (i != 0) &&
                                                (part == "$db" ||
                                                 part == "$id" ||
                                                 part == "$ref");

                if ( !mightBePartOfDbRef ) {
                    return Status(code, "Index key contains an illegal field name: "
                                        "field name starts with '$'.");
                }
            }
        }

        return Status::OK();
    }
Beispiel #22
0
   INT32 _omAgentNodeMgr::rmANode( const CHAR *arg1, const CHAR *arg2,
                                   const CHAR *roleStr, string *omsvc )
   {
      INT32 rc = SDB_OK ;
      const CHAR *pSvcName = _getSvcNameFromArg( arg1 ) ;
      BOOLEAN backupDialog = FALSE ;
      CHAR  cfgPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;
      CHAR  cfgFile[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;
      pmdOptionsCB nodeOptions ;
      BOOLEAN hasLock = FALSE ;

      if ( !pSvcName )
      {
         PD_LOG( PDERROR, "Failed to get svc name from arg" ) ;
         rc = SDB_INVALIDARG ;
         goto error ;
      }

      if ( arg2 )
      {
         try
         {
            BSONObj objArg2( arg2 ) ;
            if ( !objArg2.isEmpty() )
            {
               backupDialog = TRUE ;
            }
         }
         catch( std::exception &e )
         {
            PD_LOG( PDERROR, "Ocuur exception: %s", e.what() ) ;
            rc = SDB_INVALIDARG ;
            goto error ;
         }
      }

      rc = utilBuildFullPath( sdbGetOMAgentOptions()->getLocalCfgPath(),
                              pSvcName, OSS_MAX_PATHSIZE, cfgPath ) ;
      if ( rc )
      {
         PD_LOG( PDERROR, "Build config path for service[%s] failed, rc: %d",
                 pSvcName, rc ) ;
         goto error ;
      }

      rc = utilBuildFullPath( cfgPath, PMD_DFT_CONF, OSS_MAX_PATHSIZE,
                              cfgFile ) ;
      if ( rc )
      {
         PD_LOG( PDERROR, "Build config file for service[%s] failed, rc: %d",
                 pSvcName, rc ) ;
         goto error ;
      }

      lockBucket( pSvcName ) ;
      hasLock = TRUE ;

      rc = nodeOptions.initFromFile( cfgFile, FALSE ) ;
      if ( rc )
      {
         if ( SDB_FNE == rc )
         {
            rc = SDBCM_NODE_NOTEXISTED ;
         }
         else
         {
            PD_LOG( PDERROR, "Extract node[%s] config failed, rc: %d",
                    pSvcName, rc ) ;
         }
         goto error ;
      }
      if ( omsvc )
      {
         *omsvc = nodeOptions.getOMService() ;
      }

      if ( roleStr && 0 != *roleStr &&
           0 != ossStrcmp( nodeOptions.dbroleStr(), roleStr ) )
      {
         PD_LOG( PDERROR, "Role[%s] is not expect[%s]",
                 nodeOptions.dbroleStr(), roleStr ) ;
         rc = SDB_PERM ;
         goto error ;
      }

      try
      {
         BSONObj configObj( arg1 ) ;
         BSONObjIterator itr( configObj ) ;
         while ( itr.more() )
         {
            BSONElement e = itr.next() ;
            if ( 0 != ossStrcmp( e.fieldName(), PMD_OPTION_CLUSTER_NAME ) &&
                 0 != ossStrcmp( e.fieldName(), PMD_OPTION_BUSINESS_NAME ) &&
                 0 != ossStrcmp( e.fieldName(), PMD_OPTION_USERTAG ) )
            {
               continue ;
            }
            string name ;
            nodeOptions.getFieldStr( e.fieldName(), name, "" ) ;
            if ( 0 != ossStrcmp( e.valuestrsafe(), name.c_str() ) )
            {
               rc = SDBCM_NODE_NOTEXISTED ;
               goto error ;
            }
         }
      }
      catch( std::exception &e )
      {
         PD_LOG( PDERROR, "Extrace config obj occur exception: %s",
                 e.what() ) ;
         rc = SDB_INVALIDARG ;
         goto error ;
      }

      stopANode( pSvcName, NODE_START_CLIENT, FALSE ) ;

      if ( backupDialog )
      {
         CHAR bakPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;

         ossStrncpy( bakPath, nodeOptions.getDbPath(),
                     OSS_MAX_PATHSIZE ) ;
         ossStrncat( bakPath, "_bak", OSS_MAX_PATHSIZE ) ;

         if ( SDB_OK == ossAccess( bakPath ) )
         {
            ossDelete( bakPath ) ;
         }
         if ( SDB_OK == ( rc = ossRenamePath( nodeOptions.getDiagLogPath(),
                                              bakPath ) ) )
         {
            PD_LOG( PDEVENT, "Move node[%s] dialog[%s] to path[%s]",
                    pSvcName, nodeOptions.getDiagLogPath(), bakPath ) ;
         }
         else
         {
            PD_LOG( PDERROR, "Move node[%s] dialog[%s] to path[%s] failed, "
                    "rc: %d", pSvcName, nodeOptions.getDiagLogPath(),
                    bakPath, rc ) ;
         }
      }

      {
         pmdStartup startupFile ;
         if ( SDB_OK == startupFile.init( nodeOptions.getDbPath(), FALSE ) )
         {
            startupFile.final() ;

            rc = nodeOptions.removeAllDir() ;
            if ( rc )
            {
               PD_LOG( PDERROR, "Remove node[%s] directorys failed, rc: %d",
                       pSvcName, rc ) ;
               goto error ;
            }
         }
      }
Beispiel #23
0
   INT32 _omAgentNodeMgr::_addANode( const CHAR *arg1, const CHAR *arg2,
                                     BOOLEAN needLock, BOOLEAN isModify,
                                     string *omsvc )
   {
      INT32 rc = SDB_OK ;
      const CHAR *pSvcName = NULL ;
      const CHAR *pDBPath = NULL ;
      string otherCfg ;

      CHAR dbPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;
      CHAR cfgPath[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;
      CHAR cfgFile[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;

      BOOLEAN createDBPath    = FALSE ;
      BOOLEAN createCfgPath   = FALSE ;
      BOOLEAN createCfgFile   = FALSE ;
      BOOLEAN hasLock         = FALSE ;

      try
      {
         stringstream ss ;
         BSONObj objArg1( arg1 ) ;
         BSONObjIterator it ( objArg1 ) ;
         while ( it.more() )
         {
            BSONElement e = it.next() ;
            if ( 0 == ossStrcmp( e.fieldName(), PMD_OPTION_SVCNAME ) )
            {
               if ( e.type() != String )
               {
                  PD_LOG( PDERROR, "Param[%s] type[%d] is not string",
                          PMD_OPTION_SVCNAME, e.type() ) ;
                  rc = SDB_INVALIDARG ;
                  goto error ;
               }
               pSvcName = e.valuestrsafe() ;
            }
            else if ( 0 == ossStrcmp( e.fieldName(), PMD_OPTION_DBPATH ) )
            {
               if ( e.type() != String )
               {
                  PD_LOG( PDERROR, "Param[%s] type[%d] is not string",
                          PMD_OPTION_DBPATH, e.type() ) ;
                  rc = SDB_INVALIDARG ;
                  goto error ;
               }
               pDBPath = e.valuestrsafe() ;
            }
            else
            {
               ss << e.fieldName() << "=" ;
               switch( e.type() )
               {
                  case NumberDouble :
                     ss << e.numberDouble () ;
                     break ;
                  case NumberInt :
                     ss << e.numberLong () ;
                     break ;
                  case NumberLong :
                     ss << e.numberInt () ;
                     break ;
                  case String :
                     ss << e.valuestrsafe () ;
                     break ;
                  case Bool :
                     ss << ( e.boolean() ? "TRUE" : "FALSE" ) ;
                     break ;
                  default :
                     PD_LOG ( PDERROR, "Unexpected type[%d] for %s",
                              e.type(), e.toString().c_str() ) ;
                     rc = SDB_INVALIDARG ;
                     goto error ;
               }
               ss << endl ;
            }
         }
         otherCfg = ss.str() ;
      }
      catch( std::exception &e )
      {
         PD_LOG( PDERROR, "Occur exception: %s", e.what() ) ;
         rc = SDB_INVALIDARG ;
         goto error ;
      }

      if ( !pSvcName || !pDBPath )
      {
         PD_LOG( PDERROR, "Param [%s] or [%s] is not config",
                 PMD_OPTION_SVCNAME, PMD_OPTION_DBPATH ) ;
         rc = SDB_INVALIDARG ;
         goto error ;
      }

      if ( !ossGetRealPath( pDBPath, dbPath, OSS_MAX_PATHSIZE ) )
      {
         PD_LOG( PDERROR, "Invalid db path: %s", pDBPath ) ;
         rc = SDB_INVALIDARG ;
         goto error ;
      }

      if ( needLock )
      {
         lockBucket( pSvcName ) ;
         hasLock = TRUE ;
      }

      if ( isModify && !getNodeProcessInfo( pSvcName ) )
      {
         rc = SDBCM_NODE_NOTEXISTED ;
         goto error ;
      }

      rc = ossAccess( dbPath, W_OK ) ;
      if ( SDB_PERM == rc )
      {
         PD_LOG ( PDERROR, "Permission error for path: %s", dbPath ) ;
         goto error ;
      }
      else if ( SDB_FNE == rc )
      {
         rc = ossMkdir ( dbPath, OSS_CREATE|OSS_READWRITE ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "Failed to create config file in path: %s, "
                     "rc: %d", dbPath, rc ) ;
            goto error ;
         }
         createDBPath = TRUE ;
      }
      else if ( rc )
      {
         PD_LOG ( PDERROR, "System error for access path: %s, rc: %d",
                  dbPath, rc ) ;
         goto error ;
      }

      rc = utilBuildFullPath( sdbGetOMAgentOptions()->getLocalCfgPath(),
                              pSvcName, OSS_MAX_PATHSIZE, cfgPath ) ;
      if ( rc )
      {
         PD_LOG( PDERROR, "Build config path for service[%s] failed, rc: %d",
                 pSvcName, rc ) ;
         goto error ;
      }

      rc = ossAccess( cfgPath, W_OK ) ;
      if ( SDB_PERM == rc )
      {
         PD_LOG ( PDERROR, "Permission error for path[%s]", cfgPath ) ;
         goto error ;
      }
      else if ( SDB_FNE == rc )
      {
         rc = ossMkdir ( cfgPath, OSS_CREATE|OSS_READWRITE ) ;
         if ( rc )
         {
            PD_LOG ( PDERROR, "Failed to create directory: %s, rc: %d",
                     cfgPath, rc ) ;
            goto error ;
         }
         createCfgPath = TRUE ;
      }
      else if ( rc )
      {
         PD_LOG ( PDERROR, "System error for access path: %s, rc: %d",
                  cfgPath, rc ) ;
         goto error ;
      }
      else if ( !isModify )
      {
         PD_LOG ( PDERROR, "service[%s] node existed", pSvcName ) ;
         rc = SDBCM_NODE_EXISTED ;
         goto error ;
      }

      rc = utilBuildFullPath( cfgPath, PMD_DFT_CONF, OSS_MAX_PATHSIZE,
                              cfgFile ) ;
      if ( rc )
      {
         PD_LOG ( PDERROR, "Build config file for service[%s] failed, rc: %d",
                  pSvcName, rc ) ;
         goto error ;
      }
      {
         pmdOptionsCB nodeOptions ;
         stringstream ss ;
         ss << PMD_OPTION_SVCNAME << "=" << pSvcName << endl ;
         ss << PMD_OPTION_DBPATH << "=" << dbPath << endl ;
         ss << otherCfg ;

         rc = utilWriteConfigFile( cfgFile, ss.str().c_str(),
                                   isModify ? FALSE : TRUE ) ;
         if ( rc )
         {
            PD_LOG( PDERROR, "Write config file[%s] failed, rc: %d",
                    cfgFile, rc ) ;
            goto error ;
         }
         createCfgFile = TRUE ;

         rc = nodeOptions.initFromFile( cfgFile, FALSE ) ;
         if ( rc )
         {
            PD_LOG( PDERROR, "Extract node[%s] config failed, rc: %d",
                    pSvcName, rc ) ;
            goto error ;
         }
         if ( omsvc )
         {
            *omsvc = nodeOptions.getOMService() ;
         }
      }

      if ( isModify || !arg2 )
      {
         goto done ;
      }

      try
      {
         CHAR cataCfgFile[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;
         BSONObj objArg2( arg2 ) ;
         stringstream ss ;
         if ( objArg2.isEmpty() )
         {
            goto done ;
         }
         rc = utilBuildFullPath( cfgPath, PMD_DFT_CAT, OSS_MAX_PATHSIZE,
                                 cataCfgFile ) ;
         if ( rc )
         {
            PD_LOG( PDERROR, "Build cat config file failed in service[%s], "
                    "rc: %d", pSvcName, rc ) ;
            goto error ;
         }
         ss << objArg2 << endl ;

         rc = utilWriteConfigFile( cataCfgFile, ss.str().c_str(), TRUE ) ;
         if ( rc )
         {
            PD_LOG( PDERROR, "Write cat file[%s] failed in service[%s], rc: %d",
                    cataCfgFile, pSvcName, rc ) ;
            goto error ;
         }
      }
      catch( std::exception &e )
      {
         PD_LOG( PDERROR, "Occur exeption for extract the second args for "
                 "service[%s]: %s", pSvcName, e.what() ) ;
         rc = SDB_INVALIDARG ;
         goto error ;
      }

   done:
      if ( SDB_OK == rc )
      {
         if ( !isModify )
         {
            addNodeProcessInfo( pSvcName ) ;
            PD_LOG( PDEVENT, "Add node[%s] succeed", pSvcName ) ;
         }
         else
         {
            PD_LOG( PDEVENT, "Modify node[%s] succeed", pSvcName ) ;
         }
      }
      if ( hasLock )
      {
         releaseBucket( pSvcName ) ;
      }
      return rc ;
   error:
      if ( createCfgFile )
      {
         ossDelete( cfgFile ) ;
      }
      if ( createCfgPath )
      {
         ossDelete( cfgPath ) ;
      }
      if ( createDBPath )
      {
         ossDelete( dbPath ) ;
      }
      goto done ;
   }
Beispiel #24
0
StatusWith<BSONObj> FTSSpec::fixSpec(const BSONObj& spec) {
    if (spec["textIndexVersion"].numberInt() == TEXT_INDEX_VERSION_1) {
        return _fixSpecV1(spec);
    }

    map<string, int> m;

    BSONObj keyPattern;
    {
        BSONObjBuilder b;

        // Populate m and keyPattern.
        {
            bool addedFtsStuff = false;
            BSONObjIterator i(spec["key"].Obj());
            while (i.more()) {
                BSONElement e = i.next();
                if (e.fieldNameStringData() == "_fts") {
                    if (INDEX_NAME != e.valuestrsafe()) {
                        return {ErrorCodes::CannotCreateIndex, "expecting _fts:\"text\""};
                    }
                    addedFtsStuff = true;
                    b.append(e);
                } else if (e.fieldNameStringData() == "_ftsx") {
                    if (e.numberInt() != 1) {
                        return {ErrorCodes::CannotCreateIndex, "expecting _ftsx:1"};
                    }
                    b.append(e);
                } else if (e.type() == String && INDEX_NAME == e.valuestr()) {
                    if (!addedFtsStuff) {
                        _addFTSStuff(&b);
                        addedFtsStuff = true;
                    }

                    m[e.fieldName()] = 1;
                } else {
                    if (e.numberInt() != 1 && e.numberInt() != -1) {
                        return {ErrorCodes::CannotCreateIndex,
                                "expected value 1 or -1 for non-text key in compound index"};
                    }
                    b.append(e);
                }
            }
            verify(addedFtsStuff);
        }
        keyPattern = b.obj();

        // Verify that index key is in the correct format: extraBefore fields, then text
        // fields, then extraAfter fields.
        {
            BSONObjIterator i(spec["key"].Obj());
            verify(i.more());
            BSONElement e = i.next();

            // extraBefore fields
            while (String != e.type()) {
                Status notReservedStatus = verifyFieldNameNotReserved(e.fieldNameStringData());
                if (!notReservedStatus.isOK()) {
                    return notReservedStatus;
                }

                if (!i.more()) {
                    return {ErrorCodes::CannotCreateIndex,
                            "expected additional fields in text index key pattern"};
                }

                e = i.next();
            }

            // text fields
            bool alreadyFixed = (e.fieldNameStringData() == "_fts");
            if (alreadyFixed) {
                if (!i.more()) {
                    return {ErrorCodes::CannotCreateIndex, "expected _ftsx after _fts"};
                }
                e = i.next();
                if (e.fieldNameStringData() != "_ftsx") {
                    return {ErrorCodes::CannotCreateIndex, "expected _ftsx after _fts"};
                }
                e = i.next();
            } else {
                do {
                    Status notReservedStatus = verifyFieldNameNotReserved(e.fieldNameStringData());
                    if (!notReservedStatus.isOK()) {
                        return notReservedStatus;
                    }
                    e = i.next();
                } while (!e.eoo() && e.type() == String);
            }

            // extraAfterFields
            while (!e.eoo()) {
                if (e.type() == BSONType::String) {
                    return {ErrorCodes::CannotCreateIndex,
                            "'text' fields in index must all be adjacent"};
                }
                Status notReservedStatus = verifyFieldNameNotReserved(e.fieldNameStringData());
                if (!notReservedStatus.isOK()) {
                    return notReservedStatus;
                }
                e = i.next();
            }
        }
    }

    if (spec["weights"].type() == Object) {
        BSONObjIterator i(spec["weights"].Obj());
        while (i.more()) {
            BSONElement e = i.next();
            if (!e.isNumber()) {
                return {ErrorCodes::CannotCreateIndex, "weight for text index needs numeric type"};
            }
            m[e.fieldName()] = e.numberInt();
        }
    } else if (spec["weights"].str() == WILDCARD) {
        m[WILDCARD] = 1;
    } else if (!spec["weights"].eoo()) {
        return {ErrorCodes::CannotCreateIndex, "text index option 'weights' must be an object"};
    }

    if (m.empty()) {
        return {ErrorCodes::CannotCreateIndex,
                "text index option 'weights' must specify fields or the wildcard"};
    }

    BSONObj weights;
    {
        BSONObjBuilder b;
        for (map<string, int>::iterator i = m.begin(); i != m.end(); ++i) {
            if (i->second <= 0 || i->second >= MAX_WORD_WEIGHT) {
                return {ErrorCodes::CannotCreateIndex,
                        str::stream() << "text index weight must be in the exclusive interval (0,"
                                      << MAX_WORD_WEIGHT
                                      << ") but found: "
                                      << i->second};
            }

            // Verify weight refers to a valid field.
            if (i->first != "$**") {
                FieldRef keyField(i->first);
                if (keyField.numParts() == 0) {
                    return {ErrorCodes::CannotCreateIndex, "weight cannot be on an empty field"};
                }

                for (size_t partNum = 0; partNum < keyField.numParts(); partNum++) {
                    StringData part = keyField.getPart(partNum);
                    if (part.empty()) {
                        return {ErrorCodes::CannotCreateIndex,
                                "weight cannot have empty path component"};
                    }

                    if (part.startsWith("$")) {
                        return {ErrorCodes::CannotCreateIndex,
                                "weight cannot have path component with $ prefix"};
                    }
                }
            }

            b.append(i->first, i->second);
        }
        weights = b.obj();
    }

    BSONElement default_language_elt = spec["default_language"];
    string default_language(default_language_elt.str());
    if (default_language_elt.eoo()) {
        default_language = moduleDefaultLanguage;
    } else if (default_language_elt.type() != BSONType::String) {
        return {ErrorCodes::CannotCreateIndex, "default_language needs a string type"};
    }

    if (!FTSLanguage::make(default_language, TEXT_INDEX_VERSION_3).getStatus().isOK()) {
        return {ErrorCodes::CannotCreateIndex, "default_language is not valid"};
    }

    BSONElement language_override_elt = spec["language_override"];
    string language_override(language_override_elt.str());
    if (language_override_elt.eoo()) {
        language_override = "language";
    } else if (language_override_elt.type() != BSONType::String) {
        return {ErrorCodes::CannotCreateIndex, "language_override must be a string"};
    } else if (!validateOverride(language_override)) {
        return {ErrorCodes::CannotCreateIndex, "language_override is not valid"};
    }

    int version = -1;
    int textIndexVersion = TEXT_INDEX_VERSION_3;  // default text index version

    BSONObjBuilder b;
    BSONObjIterator i(spec);
    while (i.more()) {
        BSONElement e = i.next();
        StringData fieldName = e.fieldNameStringData();
        if (fieldName == "key") {
            b.append("key", keyPattern);
        } else if (fieldName == "weights") {
            b.append("weights", weights);
            weights = BSONObj();
        } else if (fieldName == "default_language") {
            b.append("default_language", default_language);
            default_language = "";
        } else if (fieldName == "language_override") {
            b.append("language_override", language_override);
            language_override = "";
        } else if (fieldName == "v") {
            version = e.numberInt();
        } else if (fieldName == "textIndexVersion") {
            if (!e.isNumber()) {
                return {ErrorCodes::CannotCreateIndex,
                        "text index option 'textIndexVersion' must be a number"};
            }

            textIndexVersion = e.numberInt();
            if (textIndexVersion != TEXT_INDEX_VERSION_2 &&
                textIndexVersion != TEXT_INDEX_VERSION_3) {
                return {ErrorCodes::CannotCreateIndex,
                        str::stream() << "bad textIndexVersion: " << textIndexVersion};
            }
        } else {
            b.append(e);
        }
    }

    if (!weights.isEmpty()) {
        b.append("weights", weights);
    }
    if (!default_language.empty()) {
        b.append("default_language", default_language);
    }
    if (!language_override.empty()) {
        b.append("language_override", language_override);
    }
    if (version >= 0) {
        b.append("v", version);
    }
    b.append("textIndexVersion", textIndexVersion);

    return b.obj();
}
Beispiel #25
0
Status validateKeyPattern(const BSONObj& key, IndexDescriptor::IndexVersion indexVersion) {
    const ErrorCodes::Error code = ErrorCodes::CannotCreateIndex;

    if (key.objsize() > 2048)
        return Status(code, "Index key pattern too large.");

    if (key.isEmpty())
        return Status(code, "Index keys cannot be empty.");

    string pluginName = IndexNames::findPluginName(key);
    if (pluginName.size()) {
        if (!IndexNames::isKnownName(pluginName))
            return Status(
                code, mongoutils::str::stream() << "Unknown index plugin '" << pluginName << '\'');
    }

    BSONObjIterator it(key);
    while (it.more()) {
        BSONElement keyElement = it.next();

        switch (indexVersion) {
            case IndexVersion::kV0:
            case IndexVersion::kV1: {
                if (keyElement.type() == BSONType::Object || keyElement.type() == BSONType::Array) {
                    return {code,
                            str::stream() << "Values in index key pattern cannot be of type "
                                          << typeName(keyElement.type())
                                          << " for index version v:"
                                          << static_cast<int>(indexVersion)};
                }

                if (pluginName == IndexNames::ALLPATHS) {
                    return {code,
                            str::stream() << "'" << pluginName
                                          << "' index plugin is not allowed with index version v:"
                                          << static_cast<int>(indexVersion)};
                }
                break;
            }
            case IndexVersion::kV2: {
                if (keyElement.isNumber()) {
                    double value = keyElement.number();
                    if (std::isnan(value)) {
                        return {code, "Values in the index key pattern cannot be NaN."};
                    } else if (value == 0.0) {
                        return {code, "Values in the index key pattern cannot be 0."};
                    }
                } else if (keyElement.type() != BSONType::String) {
                    return {code,
                            str::stream()
                                << "Values in v:2 index key pattern cannot be of type "
                                << typeName(keyElement.type())
                                << ". Only numbers > 0, numbers < 0, and strings are allowed."};
                }

                break;
            }
            default:
                MONGO_UNREACHABLE;
        }

        if (keyElement.type() == String && pluginName != keyElement.str()) {
            return Status(code, "Can't use more than one index plugin for a single index.");
        }

        // Check if the all paths index is compounded. If it is the key is invalid because
        // compounded all paths indexes are disallowed.
        if (pluginName == IndexNames::ALLPATHS && key.nFields() != 1) {
            return Status(code, "all paths indexes do not allow compounding");
        }

        // Ensure that the fields on which we are building the index are valid: a field must not
        // begin with a '$' unless it is part of an allPaths, DBRef or text index, and a field path
        // cannot contain an empty field. If a field cannot be created or updated, it should not be
        // indexable.

        FieldRef keyField(keyElement.fieldName());

        const size_t numParts = keyField.numParts();
        if (numParts == 0) {
            return Status(code, "Index keys cannot be an empty field.");
        }

        // "$**" is acceptable for a text index or all paths index.
        if (mongoutils::str::equals(keyElement.fieldName(), "$**") &&
            ((keyElement.isNumber()) || (keyElement.valuestrsafe() == IndexNames::TEXT)))
            continue;

        if (mongoutils::str::equals(keyElement.fieldName(), "_fts") &&
            keyElement.valuestrsafe() != IndexNames::TEXT) {
            return Status(code, "Index key contains an illegal field name: '_fts'");
        }

        for (size_t i = 0; i != numParts; ++i) {
            const StringData part = keyField.getPart(i);

            // Check if the index key path contains an empty field.
            if (part.empty()) {
                return Status(code, "Index keys cannot contain an empty field.");
            }

            if (part[0] != '$')
                continue;

            // Check if the '$'-prefixed field is part of a DBRef: since we don't have the
            // necessary context to validate whether this is a proper DBRef, we allow index
            // creation on '$'-prefixed names that match those used in a DBRef.
            const bool mightBePartOfDbRef =
                (i != 0) && (part == "$db" || part == "$id" || part == "$ref");

            const bool isPartOfAllPaths =
                (i == numParts - 1) && (part == "$**") && (pluginName == IndexNames::ALLPATHS);

            if (!mightBePartOfDbRef && !isPartOfAllPaths) {
                return Status(code,
                              "Index key contains an illegal field name: "
                              "field name starts with '$'.");
            }
        }
    }

    return Status::OK();
}
Beispiel #26
0
INT32 _fmpController::_handleOneLoop( const BSONObj &obj,
                                      INT32 step )
{
   INT32 rc = SDB_OK ;
   BSONObj res ;

   if ( FMP_CONTROL_STEP_BEGIN == step )
   {
      UINT32 seqID = 1 ;
      BSONElement beSeq = obj.getField( FMP_SEQ_ID ) ;
      if ( beSeq.isNumber() )
      {
         seqID = (UINT32)beSeq.numberInt() ;
      }
      BSONElement diag = obj.getField( FMP_DIAG_PATH ) ;
      if ( !diag.eoo() && String == diag.type() )
      {
         CHAR diaglogShort[ OSS_MAX_PATHSIZE + 1 ] = { 0 } ;
         ossSnprintf( diaglogShort, OSS_MAX_PATHSIZE, "%s_%u.%s",
                      PD_FMP_DIAGLOG_PREFIX, seqID, PD_FMP_DIAGLOG_SUBFIX ) ;

         CHAR diaglog[ OSS_MAX_PATHSIZE + 1 ] = {0} ;
         engine::utilBuildFullPath( diag.valuestrsafe(), diaglogShort,
                                    OSS_MAX_PATHSIZE, diaglog ) ;
         sdbEnablePD( diaglog ) ;
      }
      BSONElement localService = obj.getField( FMP_LOCAL_SERVICE ) ;
      if ( !localService.eoo() && String == localService.type() &&
           0 == ossStrlen(FMP_COORD_SERVICE) )
      {
         ossMemcpy( FMP_COORD_SERVICE, localService.valuestrsafe(),
                    ossStrlen( localService.valuestrsafe() ) + 1 ) ;
      }
      BSONElement localUser = obj.getField( FMP_LOCAL_USERNAME ) ;
      if ( String == localUser.type() )
      {
         ossStrncpy( g_UserName, localUser.valuestrsafe(),
                     OSS_MAX_PATHSIZE ) ;
      }
      BSONElement localPass = obj.getField( FMP_LOCAL_PASSWORD ) ;
      if ( String == localPass.type() )
      {
         ossStrncpy( g_Password, localPass.valuestrsafe(),
                     OSS_MAX_PATHSIZE ) ;
      }
      BSONElement fType = obj.getField( FMP_FUNC_TYPE ) ;
      if ( fType.eoo() )
      {
         rc = _createVM( FMP_FUNC_TYPE_JS ) ;
         if ( SDB_OK != rc )
         {
            PD_LOG(PDERROR, "failed to create vm:%d", rc ) ;
            res = BSON( FMP_ERR_MSG << "failed to create vm" <<
                        FMP_RES_CODE << rc ) ;
            goto error ;
         }

         rc = _vm->init( obj ) ;
         if ( SDB_OK != rc )
         {
            PD_LOG(PDERROR, "failed to init vm:%d", rc ) ;
            res = BSON( FMP_ERR_MSG << "failed to init vm" <<
                        FMP_RES_CODE << rc ) ;
            goto error ;
         }
      }
      else if ( NumberInt != fType.type() )
      {
         PD_LOG( PDERROR, "invalid type of func type:%s",
                 fType.toString().c_str() ) ;
         rc = SDB_SYS ;
         res = BSON( FMP_ERR_MSG << "invalid type of func type" <<
                     FMP_RES_CODE << SDB_SYS ) ;
         goto error ;
      }
      else
      {
         rc = _createVM( fType.Int() ) ;
         if ( SDB_OK != rc )
         {
            PD_LOG(PDERROR, "failed to create vm:%d", rc ) ;
            res = BSON( FMP_ERR_MSG << "failed to create vm" <<
                        FMP_RES_CODE << rc ) ;
            goto error ;
         }

         rc = _vm->init( obj ) ;
         if ( SDB_OK != rc )
         {
            PD_LOG(PDERROR, "failed to init vm:%d", rc ) ;
            res = BSON( FMP_ERR_MSG << "failed to init vm" <<
                        FMP_RES_CODE << rc ) ;
            goto error ;
         }
      }
   }
   else if ( FMP_CONTROL_STEP_DOWNLOAD == step )
   {
      SDB_ASSERT( NULL != _vm, "impossible" ) ;
      rc = _vm->eval( obj, res ) ;
      if ( SDB_OK  != rc )
      {
         PD_LOG( PDERROR, "failed to pre eval func:%s, rc:%d",
                 obj.toString(FALSE, TRUE).c_str(), rc ) ;
         if ( res.isEmpty() )
         {
            res = BSON( FMP_ERR_MSG << "failed to pre eval func" <<
                        FMP_RES_CODE << rc ) ;
         }
         goto error ;
      }
   }
   else if ( FMP_CONTROL_STEP_EVAL == step )
   {
      rc = _vm->initGlobalDB( res ) ;
      if ( rc )
      {
         PD_LOG( PDWARNING, "Failed to init global db: %s",
                 res.toString( FALSE, TRUE ).c_str() ) ;
      }

      rc = _vm->eval( obj, res ) ;
      if ( SDB_OK != rc )
      {
         PD_LOG( PDERROR, "failed to eval func:%s, rc:%d",
                 obj.toString(FALSE, TRUE).c_str(), rc ) ;
         if ( res.isEmpty() )
         {
            res = BSON( FMP_ERR_MSG << "failed to eval func" <<
                        FMP_RES_CODE << rc ) ;
         }
         goto error ;
      }
   }
   else if ( FMP_CONTROL_STEP_FETCH == step )
   {
      BSONObj next ;
      rc = _vm->fetch( next ) ;
      if ( !next.isEmpty() )
      {
         res = next ;
      }
      else
      {
         PD_LOG( PDERROR, "a empty obj was fetched out" ) ;
         rc = SDB_SYS ;
         res = BSON( FMP_ERR_MSG << "a empty obj was fetched out" <<
                     FMP_RES_CODE << rc ) ;
         goto error ;
      }

      if ( SDB_DMS_EOC == rc )
      {
         _clear() ;
      }
      else if ( SDB_OK != rc )
      {
         goto error ;
      }
   }
   else
   {
      SDB_ASSERT( FALSE, "impossible" ) ;
   }

done:
   {
   INT32 rrc = SDB_OK ;
   if ( !res.isEmpty() )
   {
      rrc = _writeMsg( res ) ;
   }
   else
   {
      rrc = _writeMsg( BSON( FMP_RES_CODE << rc ) ) ;
   }
   if ( SDB_OK != rrc )
   {
      rc = rrc ;
      PD_LOG( PDERROR, "failed to write msg:%d", rc ) ;
   }
   }
   return rc ;
error:
   goto done ;
}
Beispiel #27
0
BSONObj FTSSpec::fixSpec( const BSONObj& spec ) {
    if ( spec["textIndexVersion"].numberInt() == TEXT_INDEX_VERSION_1 ) {
        return _fixSpecV1( spec );
    }

    map<string,int> m;

    BSONObj keyPattern;
    {
        BSONObjBuilder b;

        // Populate m and keyPattern.
        {
            bool addedFtsStuff = false;
            BSONObjIterator i( spec["key"].Obj() );
            while ( i.more() ) {
                BSONElement e = i.next();
                if ( str::equals( e.fieldName(), "_fts" ) ) {
                    uassert( 17271,
                             "expecting _fts:\"text\"",
                             INDEX_NAME == e.valuestrsafe() );
                    addedFtsStuff = true;
                    b.append( e );
                }
                else if ( str::equals( e.fieldName(), "_ftsx" ) ) {
                    uassert( 17272, "expecting _ftsx:1", e.numberInt() == 1 );
                    b.append( e );
                }
                else if ( e.type() == String && INDEX_NAME == e.valuestr() ) {

                    if ( !addedFtsStuff ) {
                        _addFTSStuff( &b );
                        addedFtsStuff = true;
                    }

                    m[e.fieldName()] = 1;
                }
                else {
                    uassert( 17273,
                             "expected value 1 or -1 for non-text key in compound index",
                             e.numberInt() == 1 || e.numberInt() == -1 );
                    b.append( e );
                }
            }
            verify( addedFtsStuff );
        }
        keyPattern = b.obj();

        // Verify that index key is in the correct format: extraBefore fields, then text
        // fields, then extraAfter fields.
        {
            BSONObjIterator i( spec["key"].Obj() );
            BSONElement e;

            // extraBefore fields
            do {
                verify( i.more() );
                e = i.next();
            } while ( INDEX_NAME != e.valuestrsafe() );

            // text fields
            bool alreadyFixed = str::equals( e.fieldName(), "_fts" );
            if ( alreadyFixed ) {
                uassert( 17288, "expected _ftsx after _fts", i.more() );
                e = i.next();
                uassert( 17274,
                         "expected _ftsx after _fts",
                         str::equals( e.fieldName(), "_ftsx" ) );
                e = i.next();
            }
            else {
                do {
                    uassert( 17289,
                             "text index with reserved fields _fts/ftsx not allowed",
                             !str::equals( e.fieldName(), "_fts" ) &&
                             !str::equals( e.fieldName(), "_ftsx" ) );
                    e = i.next();
                } while ( !e.eoo() && INDEX_NAME == e.valuestrsafe() );
            }

            // extraAfterFields
            while ( !e.eoo() ) {
                uassert( 17290,
                         "compound text index key suffix fields must have value 1",
                         e.numberInt() == 1 && !str::equals( "_ftsx", e.fieldName() ) );
                e = i.next();
            }
        }

    }

    if ( spec["weights"].type() == Object ) {
        BSONObjIterator i( spec["weights"].Obj() );
        while ( i.more() ) {
            BSONElement e = i.next();
            uassert( 17283,
                     "weight for text index needs numeric type",
                     e.isNumber() );
            m[e.fieldName()] = e.numberInt();

            // Verify weight refers to a valid field.
            if ( str::equals( e.fieldName(), "$**" ) ) {
                continue;
            }
            FieldRef keyField( e.fieldName() );
            uassert( 17294,
                     "weight cannot be on an empty field",
                     keyField.numParts() != 0 );
            for ( size_t i = 0; i < keyField.numParts(); i++ ) {
                StringData part = keyField.getPart(i);
                uassert( 17291, "weight cannot have empty path component", !part.empty() );
                uassert( 17292,
                         "weight cannot have path component with $ prefix",
                         !part.startsWith( "$" ) );
            }
        }
    }
    else if ( spec["weights"].str() == WILDCARD ) {
        m[WILDCARD] = 1;
    }
    else if ( !spec["weights"].eoo() ) {
        uasserted( 17284, "text index option 'weights' must be an object" );
    }

    BSONObj weights;
    {
        BSONObjBuilder b;
        for ( map<string,int>::iterator i = m.begin(); i != m.end(); ++i ) {
            uassert( 16674, "score for word too high",
                     i->second > 0 && i->second < MAX_WORD_WEIGHT );
            b.append( i->first, i->second );
        }
        weights = b.obj();
    }

    BSONElement default_language_elt = spec["default_language"];
    string default_language( default_language_elt.str() );
    if ( default_language_elt.eoo() ) {
        default_language = moduleDefaultLanguage;
    }
    else {
        uassert( 17263,
                 "default_language needs a string type",
                 default_language_elt.type() == String );
    }
    uassert( 17264,
             "default_language is not valid",
             FTSLanguage::make( default_language,
                                TEXT_INDEX_VERSION_2 ).getStatus().isOK() );

    BSONElement language_override_elt = spec["language_override"];
    string language_override( language_override_elt.str() );
    if ( language_override_elt.eoo() ) {
        language_override = "language";
    }
    else {
        uassert( 17136,
                 "language_override is not valid",
                 language_override_elt.type() == String
                 && validateOverride( language_override ) );
    }

    int version = -1;
    int textIndexVersion = TEXT_INDEX_VERSION_2;

    BSONObjBuilder b;
    BSONObjIterator i( spec );
    while ( i.more() ) {
        BSONElement e = i.next();
        if ( str::equals( e.fieldName(), "key" ) ) {
            b.append( "key", keyPattern );
        }
        else if ( str::equals( e.fieldName(), "weights" ) ) {
            b.append( "weights", weights );
            weights = BSONObj();
        }
        else if ( str::equals( e.fieldName(), "default_language" ) ) {
            b.append( "default_language", default_language);
            default_language = "";
        }
        else if ( str::equals( e.fieldName(), "language_override" ) ) {
            b.append( "language_override", language_override);
            language_override = "";
        }
        else if ( str::equals( e.fieldName(), "v" ) ) {
            version = e.numberInt();
        }
        else if ( str::equals( e.fieldName(), "textIndexVersion" ) ) {
            uassert( 17293,
                     "text index option 'textIndexVersion' must be a number",
                     e.isNumber() );
            textIndexVersion = e.numberInt();
            uassert( 16730,
                     str::stream() << "bad textIndexVersion: " << textIndexVersion,
                     textIndexVersion == TEXT_INDEX_VERSION_2 );
        }
        else {
            b.append( e );
        }
    }

    if ( !weights.isEmpty() )
        b.append( "weights", weights );
    if ( !default_language.empty() )
        b.append( "default_language", default_language);
    if ( !language_override.empty() )
        b.append( "language_override", language_override);

    if ( version >= 0 )
        b.append( "v", version );

    b.append( "textIndexVersion", textIndexVersion );

    return b.obj();

}