예제 #1
0
pair<vector<BSONObj>, vector<BSONObj>> IndexAccessMethod::setDifference(const BSONObjSet& left,
                                                                        const BSONObjSet& right) {
    // Two iterators to traverse the two sets in sorted order.
    auto leftIt = left.begin();
    auto rightIt = right.begin();
    vector<BSONObj> onlyLeft;
    vector<BSONObj> onlyRight;

    while (leftIt != left.end() && rightIt != right.end()) {
        const int cmp = leftIt->woCompare(*rightIt);
        if (cmp == 0) {
            // 'leftIt' and 'rightIt' compare equal using woCompare(), but may not be identical,
            // which should result in an index change.
            if (!leftIt->binaryEqual(*rightIt)) {
                onlyLeft.push_back(*leftIt);
                onlyRight.push_back(*rightIt);
            }
            ++leftIt;
            ++rightIt;
            continue;
        } else if (cmp > 0) {
            onlyRight.push_back(*rightIt);
            ++rightIt;
        } else {
            onlyLeft.push_back(*leftIt);
            ++leftIt;
        }
    }

    // Add the rest of 'left' to 'onlyLeft', and the rest of 'right' to 'onlyRight', if any.
    onlyLeft.insert(onlyLeft.end(), leftIt, left.end());
    onlyRight.insert(onlyRight.end(), rightIt, right.end());

    return {std::move(onlyLeft), std::move(onlyRight)};
}
예제 #2
0
파일: s2index.cpp 프로젝트: ahopedog/mongo
        void getKeys(const BSONObj& obj, BSONObjSet& keys) const {
            verify(_fields.size() >= 1);

            BSONObjSet keysToAdd;
            // We output keys in the same order as the fields we index.
            for (size_t i = 0; i < _fields.size(); ++i) {
                const IndexedField &field = _fields[i];

                // First, we get the keys that this field adds.  Either they're added literally from
                // the value of the field, or they're transformed if the field is geo.
                BSONElementSet fieldElements;
                // false means Don't expand the last array, duh.
                obj.getFieldsDotted(field.name, fieldElements, false);

                BSONObjSet keysForThisField;
                if (IndexedField::GEO == field.type) {
                    getGeoKeys(fieldElements, &keysForThisField);
                } else if (IndexedField::LITERAL == field.type) {
                    getLiteralKeys(fieldElements, &keysForThisField);
                } else {
                    verify(0);
                }

                // We expect there to be _spec->_missingField() present in the keys if data is
                // missing.  So, this should be non-empty.
                verify(!keysForThisField.empty());

                // We take the Cartesian product of all of the keys.  This requires that we have
                // some keys to take the Cartesian product with.  If keysToAdd.empty(), we
                // initialize it.  
                if (keysToAdd.empty()) {
                    keysToAdd = keysForThisField;
                    continue;
                }

                BSONObjSet updatedKeysToAdd;
                for (BSONObjSet::const_iterator it = keysToAdd.begin(); it != keysToAdd.end();
                     ++it) {
                    for (BSONObjSet::const_iterator newIt = keysForThisField.begin();
                         newIt!= keysForThisField.end(); ++newIt) {
                        BSONObjBuilder b;
                        b.appendElements(*it);
                        b.append(newIt->firstElement());
                        updatedKeysToAdd.insert(b.obj());
                    }
                }
                keysToAdd = updatedKeysToAdd;
            }

            if (keysToAdd.size() > _params.maxKeysPerInsert) {
                warning() << "insert of geo object generated lots of keys (" << keysToAdd.size()
                          << ") consider creating larger buckets. obj="
                          << obj;
            }

            for (BSONObjSet::const_iterator it = keysToAdd.begin(); it != keysToAdd.end(); ++it) {
                keys.insert(*it);
            }
        }
예제 #3
0
    void S2AccessMethod::getKeys(const BSONObj& obj, BSONObjSet* keys) {
        BSONObjSet keysToAdd;
        // We output keys in the same order as the fields we index.
        BSONObjIterator i(_descriptor->keyPattern());
        while (i.more()) {
            BSONElement e = i.next();

            // First, we get the keys that this field adds.  Either they're added literally from
            // the value of the field, or they're transformed if the field is geo.
            BSONElementSet fieldElements;
            // false means Don't expand the last array, duh.
            obj.getFieldsDotted(e.fieldName(), fieldElements, false);

            BSONObjSet keysForThisField;
            if (IndexNames::GEO_2DSPHERE == e.valuestr()) {
                // We can't ever return documents that don't have geometry so don't bother indexing
                // them.
                if (fieldElements.empty()) { return; }
                getGeoKeys(obj, fieldElements, &keysForThisField);
            } else {
                getLiteralKeys(fieldElements, &keysForThisField);
            }

            // We expect there to be the missing field element present in the keys if data is
            // missing.  So, this should be non-empty.
            verify(!keysForThisField.empty());

            // We take the Cartesian product of all of the keys.  This requires that we have
            // some keys to take the Cartesian product with.  If keysToAdd.empty(), we
            // initialize it.  
            if (keysToAdd.empty()) {
                keysToAdd = keysForThisField;
                continue;
            }

            BSONObjSet updatedKeysToAdd;
            for (BSONObjSet::const_iterator it = keysToAdd.begin(); it != keysToAdd.end();
                    ++it) {
                for (BSONObjSet::const_iterator newIt = keysForThisField.begin();
                        newIt!= keysForThisField.end(); ++newIt) {
                    BSONObjBuilder b;
                    b.appendElements(*it);
                    b.append(newIt->firstElement());
                    updatedKeysToAdd.insert(b.obj());
                }
            }
            keysToAdd = updatedKeysToAdd;
        }

        if (keysToAdd.size() > _params.maxKeysPerInsert) {
            warning() << "insert of geo object generated lots of keys (" << keysToAdd.size()
                << ") consider creating larger buckets. obj="
                << obj;
        }

        *keys = keysToAdd;
    }
예제 #4
0
Status IndexAccessMethod::BulkBuilder::insert(OperationContext* txn,
                                              const BSONObj& obj,
                                              const RecordId& loc,
                                              const InsertDeleteOptions& options,
                                              int64_t* numInserted) {
    BSONObjSet keys = SimpleBSONObjComparator::kInstance.makeBSONObjSet();
    MultikeyPaths multikeyPaths;
    _real->getKeys(obj, &keys, &multikeyPaths);

    _everGeneratedMultipleKeys = _everGeneratedMultipleKeys || (keys.size() > 1);

    if (!multikeyPaths.empty()) {
        if (_indexMultikeyPaths.empty()) {
            _indexMultikeyPaths = multikeyPaths;
        } else {
            invariant(_indexMultikeyPaths.size() == multikeyPaths.size());
            for (size_t i = 0; i < multikeyPaths.size(); ++i) {
                _indexMultikeyPaths[i].insert(multikeyPaths[i].begin(), multikeyPaths[i].end());
            }
        }
    }

    for (BSONObjSet::iterator it = keys.begin(); it != keys.end(); ++it) {
        _sorter->add(*it, loc);
        _keysInserted++;
    }

    if (NULL != numInserted) {
        *numInserted += keys.size();
    }

    return Status::OK();
}
예제 #5
0
    void NamespaceDetails::ColdIndexer::build() {
        Lock::assertWriteLocked(_d->_ns);
        if (_isSecondaryIndex) {
            IndexDetails::Builder builder(*_idx);

            const int indexNum = _d->idxNo(*_idx);
            for (shared_ptr<Cursor> cursor(BasicCursor::make(_d));
                 cursor->ok(); cursor->advance()) {
                BSONObj pk = cursor->currPK();
                BSONObj obj = cursor->current();
                BSONObjSet keys;
                _idx->getKeysFromObject(obj, keys);
                if (keys.size() > 1) {
                    _d->setIndexIsMultikey(indexNum);
                }
                for (BSONObjSet::const_iterator ki = keys.begin(); ki != keys.end(); ++ki) {
                    builder.insertPair(*ki, &pk, obj);
                }
                killCurrentOp.checkForInterrupt(); // uasserts if we should stop
            }

            builder.done();

            // If the index is unique, check all adjacent keys for a duplicate.
            if (_idx->unique()) {
                _d->checkIndexUniqueness(*_idx);
            }
        }
    }
예제 #6
0
파일: index_update.cpp 프로젝트: JKO/mongo
 /* add keys to index idxNo for a new record */
 static void addKeysToIndex(const char *ns, NamespaceDetails *d, int idxNo, BSONObj& obj,
                            DiskLoc recordLoc, bool dupsAllowed) {
     IndexDetails& idx = d->idx(idxNo);
     BSONObjSet keys;
     idx.getKeysFromObject(obj, keys);
     if( keys.empty() ) 
         return;
     BSONObj order = idx.keyPattern();
     IndexInterface& ii = idx.idxInterface();
     Ordering ordering = Ordering::make(order);
     int n = 0;
     for ( BSONObjSet::iterator i=keys.begin(); i != keys.end(); i++ ) {
         if( ++n == 2 ) {
             d->setIndexIsMultikey(ns, idxNo);
         }
         verify( !recordLoc.isNull() );
         try {
             ii.bt_insert(idx.head, recordLoc, *i, ordering, dupsAllowed, idx);
         }
         catch (AssertionException& e) {
             if( e.getCode() == 10287 && idxNo == d->nIndexes ) {
                 DEV log() << "info: caught key already in index on bg indexing (ok)" << endl;
                 continue;
             }
             if( !dupsAllowed ) {
                 // dup key exception, presumably.
                 throw;
             }
             problem() << " caught assertion addKeysToIndex " << idx.indexNamespace() << " " << obj["_id"] << endl;
         }
     }
 }
 // Return keys in l that are not in r.
 // Lifted basically verbatim from elsewhere.
 static void setDifference(const BSONObjSet &l, const BSONObjSet &r, vector<BSONObj*> *diff) {
     // l and r must use the same ordering spec.
     verify(l.key_comp().order() == r.key_comp().order());
     BSONObjSet::const_iterator i = l.begin();
     BSONObjSet::const_iterator j = r.begin();
     while ( 1 ) {
         if ( i == l.end() )
             break;
         while ( j != r.end() && j->woCompare( *i ) < 0 )
             j++;
         if ( j == r.end() || i->woCompare(*j) != 0  ) {
             const BSONObj *jo = &*i;
             diff->push_back( (BSONObj *) jo );
         }
         i++;
     }
 }
    // Find the keys for obj, put them in the tree pointing to loc
    Status BtreeBasedAccessMethod::insert(OperationContext* txn,
                                          const BSONObj& obj,
                                          const DiskLoc& loc,
                                          const InsertDeleteOptions& options,
                                          int64_t* numInserted) {
        *numInserted = 0;

        BSONObjSet keys;
        // Delegate to the subclass.
        getKeys(obj, &keys);

        Status ret = Status::OK();
        for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
            Status status = _newInterface->insert(txn, *i, loc, options.dupsAllowed);

            // Everything's OK, carry on.
            if (status.isOK()) {
                ++*numInserted;
                continue;
            }

            // Error cases.

            if (ErrorCodes::KeyTooLong == status.code()) {
                // Ignore this error if we're on a secondary.
                if (!txn->isPrimaryFor(_btreeState->ns())) {
                    continue;
                }

                // The user set a parameter to ignore key too long errors.
                if (!failIndexKeyTooLong) {
                    continue;
                }
            }

            if (ErrorCodes::UniqueIndexViolation == status.code()) {
                // We ignore it for some reason in BG indexing.
                if (!_btreeState->isReady()) {
                    DEV log() << "info: key already in index during bg indexing (ok)\n";
                    continue;
                }
            }

            // Clean up after ourselves.
            for (BSONObjSet::const_iterator j = keys.begin(); j != i; ++j) {
                removeOneKey(txn, *j, loc);
                *numInserted = 0;
            }

            return status;
        }

        if (*numInserted > 1) {
            _btreeState->setMultikey( txn );
        }

        return ret;
    }
예제 #9
0
AllowedIndicesFilter::AllowedIndicesFilter(const BSONObjSet& indexKeyPatterns,
        const stdx::unordered_set<std::string>& indexNames)
    : indexKeyPatterns(SimpleBSONObjComparator::kInstance.makeBSONObjSet()),
      indexNames(indexNames) {
    for (BSONObjSet::const_iterator i = indexKeyPatterns.begin(); i != indexKeyPatterns.end();
            ++i) {
        const BSONObj& indexKeyPattern = *i;
        this->indexKeyPatterns.insert(indexKeyPattern.getOwned());
    }
}
    Status BtreeBasedAccessMethod::touch(const BSONObj& obj) {
        BSONObjSet keys;
        getKeys(obj, &keys);

        boost::scoped_ptr<BtreeInterface::Cursor> cursor(_newInterface->newCursor(1));
        for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
            cursor->locate(*i, DiskLoc());
        }

        return Status::OK();
    }
예제 #11
0
    Status IndexAccessMethod::touch(OperationContext* txn, const BSONObj& obj) {
        BSONObjSet keys;
        getKeys(obj, &keys);

        boost::scoped_ptr<SortedDataInterface::Cursor> cursor(_newInterface->newCursor(txn, 1));
        for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
            cursor->locate(*i, RecordId());
        }

        return Status::OK();
    }
예제 #12
0
    Status IndexAccessMethod::touch(OperationContext* txn, const BSONObj& obj) {
        BSONObjSet keys;
        getKeys(obj, &keys);

        std::unique_ptr<SortedDataInterface::Cursor> cursor(_newInterface->newCursor(txn));
        for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
            cursor->seekExact(*i);
        }

        return Status::OK();
    }
예제 #13
0
    Status BtreeBasedAccessMethod::touch(const BSONObj& obj) {
        BSONObjSet keys;
        getKeys(obj, &keys);

        DiskLoc loc;
        int keyPos;
        for (BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i) {
            _newInterface->locate(*i, DiskLoc(), 1, &loc, &keyPos);
        }

        return Status::OK();
    }
예제 #14
0
 BSONObj keyTooLong(const BSONObj& a, void* data) {
     BSONObj index = a[0]["index"].Obj();
     BSONObj doc = a[0]["doc"].Obj();
     BSONObjSet keys;
     getKeysForUpgradeChecking(index, doc, &keys);
     for (BSONObjSet::const_iterator key = keys.begin(); key != keys.end(); ++key) { 
         if (key->objsize() > 1024) {
             return BSON("" << true);
         }
     }                                                                           
     return BSON("" << false);
 }
예제 #15
0
        TEST( FTSIndexFormat, Simple1 ) {
            FTSSpec spec( FTSSpec::fixSpec( BSON( "key" << BSON( "data" << "text" ) ) ) );
            BSONObjSet keys;
            FTSIndexFormat::getKeys( spec, BSON( "data" << "cat sat" ), &keys );

            ASSERT_EQUALS( 2U, keys.size() );
            for ( BSONObjSet::const_iterator i = keys.begin(); i != keys.end(); ++i ) {
                BSONObj key = *i;
                ASSERT_EQUALS( 2, key.nFields() );
                ASSERT_EQUALS( String, key.firstElement().type() );
            }
        }