int ixmBucketManager::_processData(BSONObj &record, dmsRecordID &recordID, unsigned int &hashNum, ixmEleHash &eleHash, unsigned int &random) { int rc = EDB_OK; BSONElement element = record.getField(IXM_KEY_FIELDNAME); // check if _id exists and correct if(element.eoo()|| (element.type() != NumberInt && element.type() != String)) { rc = EDB_INVALIDARG; PD_LOG(PDERROR, "record must be with _id"); goto error; } // hash _id hashNum = ossHash(element.value(), element.valuesize()); random = hashNum % IXM_HASH_MAP_SIZE; eleHash.data = element.rawdata(); eleHash.recordID = recordID; done: return rc; error: goto done; }
/* dur:: version */ void BSONElementManipulator::ReplaceTypeAndValue( const BSONElement &e ) { char *d = data(); char *v = value(); int valsize = e.valuesize(); int ofs = (int) (v-d); dassert( ofs > 0 ); char *p = (char *) getDur().writingPtr(d, valsize + ofs); *p = e.type(); memcpy( p + ofs, e.value(), valsize ); }
int ixmBucketManager::ixmBucket::removeIndex(unsigned int hashNum, ixmEleHash &eleHash) { int rc = EDB_OK; BSONElement destEle; BSONElement sourEle; ixmEleHash existEle; std::pair<std::multimap<unsigned int, ixmEleHash>::iterator, std::multimap<unsigned int, ixmEleHash>::iterator> ret; _mutex.get(); ret = _bucketMap.equal_range(hashNum); sourEle = BSONElement(eleHash.data); for(std::multimap<unsigned int, ixmEleHash>::iterator it = ret.first; it != ret.second; ++it) { existEle = it->second; destEle = BSONElement(existEle.data); if(sourEle.type() == destEle.type()) { if(sourEle.valuesize() == destEle.valuesize()) { if(!memcmp(sourEle.value(), destEle.value(), destEle.valuesize())) { eleHash.recordID = existEle.recordID; _bucketMap.erase(it); goto done; } } } } rc = EDB_INVALIDARG; PD_LOG(PDERROR, "record _id does not exist"); goto error; done: _mutex.release(); return rc; error: goto done; }
bool BSONElement::binaryEqualValues(const BSONElement& rhs) const { // The binaryEqual method above implicitly compares the type, but we need to do so explicitly // here. It doesn't make sense to consider to BSONElement objects as binaryEqual if they have // the same bit pattern but different types (consider an integer and a double). if (type() != rhs.type()) return false; const int valueSize = valuesize(); if (valueSize != rhs.valuesize()) { return false; } return (valueSize == 0) || (memcmp(value(), rhs.value(), valueSize) == 0); }
int ixmBucketManager::ixmBucket::isIDExist(unsigned int hashNum, ixmEleHash &eleHash) { int rc = EDB_OK; BSONElement destEle; BSONElement sourEle; ixmEleHash existEle; std::pair<std::multimap<unsigned int, ixmEleHash>::iterator, std::multimap<unsigned int, ixmEleHash>::iterator> ret; _mutex.get_shared(); ret = _bucketMap.equal_range(hashNum); sourEle = BSONElement(eleHash.data); for(std::multimap<unsigned int, ixmEleHash>::iterator it = ret.first; it != ret.second; ++it) { existEle = it->second; destEle = BSONElement(existEle.data); if(sourEle.type() == destEle.type()) { if(sourEle.valuesize() == destEle.valuesize()) { if(!memcmp(sourEle.value(), destEle.value(), destEle.valuesize())) { rc = EDB_IXM_ID_EXIST; PD_LOG(PDERROR, "record _id does exist"); goto error; } } } } done: _mutex.release_shared(); return rc; error: goto done; }
void BSONElementHasher::recursiveHash( Hasher* h , const BSONElement& e , bool includeFieldName ) { int canonicalType = e.canonicalType(); h->addData( &canonicalType , sizeof( canonicalType ) ); if ( includeFieldName ){ h->addData( e.fieldName() , e.fieldNameSize() ); } if ( !e.mayEncapsulate() ){ //if there are no embedded objects (subobjects or arrays), //compute the hash, squashing numeric types to 64-bit ints if ( e.isNumber() ){ long long int i = e.safeNumberLong(); //well-defined for troublesome doubles h->addData( &i , sizeof( i ) ); } else { h->addData( e.value() , e.valuesize() ); } } else { //else identify the subobject. //hash any preceding stuff (in the case of codeWscope) //then each sub-element //then finish with the EOO element. BSONObj b; if ( e.type() == CodeWScope ) { h->addData( e.codeWScopeCode() , e.codeWScopeCodeLen() ); b = e.codeWScopeObject(); } else { b = e.embeddedObject(); } BSONObjIterator i(b); while( i.moreWithEOO() ) { BSONElement el = i.next(); recursiveHash( h , el , true ); } } }
/* must be same type! */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; double x; switch ( l.type() ) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: f = l.type() - r.type(); if ( f<0 ) return -1; return f==0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case Timestamp: case Date: if ( l.date() < r.date() ) return -1; return l.date() == r.date() ? 0 : 1; case NumberInt: case NumberDouble: { double left = l.number(); double right = r.number(); bool lNan = !( left <= numeric_limits< double >::max() && left >= -numeric_limits< double >::max() ); bool rNan = !( right <= numeric_limits< double >::max() && right >= -numeric_limits< double >::max() ); if ( lNan ) { if ( rNan ) { return 0; } else { return -1; } } else if ( rNan ) { return 1; } x = left - right; if ( x < 0 ) return -1; return x == 0 ? 0 : 1; } case jstOID: return memcmp(l.value(), r.value(), 12); case Code: case Symbol: case String: /* todo: utf version */ return strcmp(l.valuestr(), r.valuestr()); case Object: case Array: return l.embeddedObject().woCompare( r.embeddedObject() ); case DBRef: case BinData: { int lsz = l.valuesize(); int rsz = r.valuesize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case RegEx: { int c = strcmp(l.regex(), r.regex()); if ( c ) return c; return strcmp(l.regexFlags(), r.regexFlags()); } default: out() << "compareElementValues: bad type " << (int) l.type() << endl; assert(false); } return -1; }
void BSONComparatorInterfaceBase<T>::hashCombineBSONElement( size_t& hash, BSONElement elemToHash, bool considerFieldName, const StringData::ComparatorInterface* stringComparator) { boost::hash_combine(hash, elemToHash.canonicalType()); const StringData fieldName = elemToHash.fieldNameStringData(); if (considerFieldName && !fieldName.empty()) { SimpleStringDataComparator::kInstance.hash_combine(hash, fieldName); } switch (elemToHash.type()) { // Order of types is the same as in compareElementValues(). case mongo::EOO: case mongo::Undefined: case mongo::jstNULL: case mongo::MaxKey: case mongo::MinKey: // These are valueless types break; case mongo::Bool: boost::hash_combine(hash, elemToHash.boolean()); break; case mongo::bsonTimestamp: boost::hash_combine(hash, elemToHash.timestamp().asULL()); break; case mongo::Date: boost::hash_combine(hash, elemToHash.date().asInt64()); break; case mongo::NumberDecimal: { const Decimal128 dcml = elemToHash.numberDecimal(); if (dcml.toAbs().isGreater(Decimal128(std::numeric_limits<double>::max(), Decimal128::kRoundTo34Digits, Decimal128::kRoundTowardZero)) && !dcml.isInfinite() && !dcml.isNaN()) { // Normalize our decimal to force equivalent decimals // in the same cohort to hash to the same value Decimal128 dcmlNorm(dcml.normalize()); boost::hash_combine(hash, dcmlNorm.getValue().low64); boost::hash_combine(hash, dcmlNorm.getValue().high64); break; } // Else, fall through and convert the decimal to a double and hash. // At this point the decimal fits into the range of doubles, is infinity, or is NaN, // which doubles have a cheaper representation for. } case mongo::NumberDouble: case mongo::NumberLong: case mongo::NumberInt: { // This converts all numbers to doubles, which ignores the low-order bits of // NumberLongs > 2**53 and precise decimal numbers without double representations, // but that is ok since the hash will still be the same for equal numbers and is // still likely to be different for different numbers. (Note: this issue only // applies for decimals when they are outside of the valid double range. See // the above case.) // SERVER-16851 const double dbl = elemToHash.numberDouble(); if (std::isnan(dbl)) { boost::hash_combine(hash, std::numeric_limits<double>::quiet_NaN()); } else { boost::hash_combine(hash, dbl); } break; } case mongo::jstOID: elemToHash.__oid().hash_combine(hash); break; case mongo::String: { if (stringComparator) { stringComparator->hash_combine(hash, elemToHash.valueStringData()); } else { SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); } break; } case mongo::Code: case mongo::Symbol: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.valueStringData()); break; case mongo::Object: case mongo::Array: hashCombineBSONObj(hash, elemToHash.embeddedObject(), true, // considerFieldName stringComparator); break; case mongo::DBRef: case mongo::BinData: // All bytes of the value are required to be identical. SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.value(), elemToHash.valuesize())); break; case mongo::RegEx: SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regex()); SimpleStringDataComparator::kInstance.hash_combine(hash, elemToHash.regexFlags()); break; case mongo::CodeWScope: { SimpleStringDataComparator::kInstance.hash_combine( hash, StringData(elemToHash.codeWScopeCode(), elemToHash.codeWScopeCodeLen())); hashCombineBSONObj(hash, elemToHash.codeWScopeObject(), true, // considerFieldName &SimpleStringDataComparator::kInstance); break; } } }
/* must be same type when called, unless both sides are #s */ int compareElementValues(const BSONElement& l, const BSONElement& r) { int f; double x; switch ( l.type() ) { case EOO: case Undefined: case jstNULL: case MaxKey: case MinKey: f = l.canonicalType() - r.canonicalType(); if ( f<0 ) return -1; return f==0 ? 0 : 1; case Bool: return *l.value() - *r.value(); case Timestamp: case Date: if ( l.date() < r.date() ) return -1; return l.date() == r.date() ? 0 : 1; case NumberLong: if( r.type() == NumberLong ) { long long L = l._numberLong(); long long R = r._numberLong(); if( L < R ) return -1; if( L == R ) return 0; return 1; } // else fall through case NumberInt: case NumberDouble: { double left = l.number(); double right = r.number(); bool lNan = !( left <= numeric_limits< double >::max() && left >= -numeric_limits< double >::max() ); bool rNan = !( right <= numeric_limits< double >::max() && right >= -numeric_limits< double >::max() ); if ( lNan ) { if ( rNan ) { return 0; } else { return -1; } } else if ( rNan ) { return 1; } x = left - right; if ( x < 0 ) return -1; return x == 0 ? 0 : 1; } case jstOID: return memcmp(l.value(), r.value(), 12); case Code: case Symbol: case String: /* todo: utf version */ return strcmp(l.valuestr(), r.valuestr()); case Object: case Array: return l.embeddedObject().woCompare( r.embeddedObject() ); case DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BinData: { int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); if ( lsz - rsz != 0 ) return lsz - rsz; return memcmp(l.value()+4, r.value()+4, lsz+1); } case RegEx: { int c = strcmp(l.regex(), r.regex()); if ( c ) return c; return strcmp(l.regexFlags(), r.regexFlags()); } case CodeWScope : { f = l.canonicalType() - r.canonicalType(); if ( f ) return f; f = strcmp( l.codeWScopeCode() , r.codeWScopeCode() ); if ( f ) return f; f = strcmp( l.codeWScopeScopeData() , r.codeWScopeScopeData() ); if ( f ) return f; return 0; } default: out() << "compareElementValues: bad type " << (int) l.type() << endl; assert(false); } return -1; }
int BSONElement::compareElements(const BSONElement& l, const BSONElement& r, ComparisonRulesSet rules, const StringData::ComparatorInterface* comparator) { switch (l.type()) { case BSONType::EOO: case BSONType::Undefined: // EOO and Undefined are same canonicalType case BSONType::jstNULL: case BSONType::MaxKey: case BSONType::MinKey: { auto f = l.canonicalType() - r.canonicalType(); if (f < 0) return -1; return f == 0 ? 0 : 1; } case BSONType::Bool: return *l.value() - *r.value(); case BSONType::bsonTimestamp: // unsigned compare for timestamps - note they are not really dates but (ordinal + // time_t) if (l.timestamp() < r.timestamp()) return -1; return l.timestamp() == r.timestamp() ? 0 : 1; case BSONType::Date: // Signed comparisons for Dates. { const Date_t a = l.Date(); const Date_t b = r.Date(); if (a < b) return -1; return a == b ? 0 : 1; } case BSONType::NumberInt: { // All types can precisely represent all NumberInts, so it is safe to simply convert to // whatever rhs's type is. switch (r.type()) { case NumberInt: return compareInts(l._numberInt(), r._numberInt()); case NumberLong: return compareLongs(l._numberInt(), r._numberLong()); case NumberDouble: return compareDoubles(l._numberInt(), r._numberDouble()); case NumberDecimal: return compareIntToDecimal(l._numberInt(), r._numberDecimal()); default: MONGO_UNREACHABLE; } } case BSONType::NumberLong: { switch (r.type()) { case NumberLong: return compareLongs(l._numberLong(), r._numberLong()); case NumberInt: return compareLongs(l._numberLong(), r._numberInt()); case NumberDouble: return compareLongToDouble(l._numberLong(), r._numberDouble()); case NumberDecimal: return compareLongToDecimal(l._numberLong(), r._numberDecimal()); default: MONGO_UNREACHABLE; } } case BSONType::NumberDouble: { switch (r.type()) { case NumberDouble: return compareDoubles(l._numberDouble(), r._numberDouble()); case NumberInt: return compareDoubles(l._numberDouble(), r._numberInt()); case NumberLong: return compareDoubleToLong(l._numberDouble(), r._numberLong()); case NumberDecimal: return compareDoubleToDecimal(l._numberDouble(), r._numberDecimal()); default: MONGO_UNREACHABLE; } } case BSONType::NumberDecimal: { switch (r.type()) { case NumberDecimal: return compareDecimals(l._numberDecimal(), r._numberDecimal()); case NumberInt: return compareDecimalToInt(l._numberDecimal(), r._numberInt()); case NumberLong: return compareDecimalToLong(l._numberDecimal(), r._numberLong()); case NumberDouble: return compareDecimalToDouble(l._numberDecimal(), r._numberDouble()); default: MONGO_UNREACHABLE; } } case BSONType::jstOID: return memcmp(l.value(), r.value(), OID::kOIDSize); case BSONType::Code: return compareElementStringValues(l, r); case BSONType::Symbol: case BSONType::String: { if (comparator) { return comparator->compare(l.valueStringData(), r.valueStringData()); } else { return compareElementStringValues(l, r); } } case BSONType::Object: case BSONType::Array: { return l.embeddedObject().woCompare( r.embeddedObject(), BSONObj(), rules | BSONElement::ComparisonRules::kConsiderFieldName, comparator); } case BSONType::DBRef: { int lsz = l.valuesize(); int rsz = r.valuesize(); if (lsz - rsz != 0) return lsz - rsz; return memcmp(l.value(), r.value(), lsz); } case BSONType::BinData: { int lsz = l.objsize(); // our bin data size in bytes, not including the subtype byte int rsz = r.objsize(); if (lsz - rsz != 0) return lsz - rsz; return memcmp(l.value() + 4, r.value() + 4, lsz + 1 /*+1 for subtype byte*/); } case BSONType::RegEx: { int c = strcmp(l.regex(), r.regex()); if (c) return c; return strcmp(l.regexFlags(), r.regexFlags()); } case BSONType::CodeWScope: { int cmp = StringData(l.codeWScopeCode(), l.codeWScopeCodeLen() - 1) .compare(StringData(r.codeWScopeCode(), r.codeWScopeCodeLen() - 1)); if (cmp) return cmp; // When comparing the scope object, we should consider field names. Special string // comparison semantics do not apply to strings nested inside the CodeWScope scope // object, so we do not pass through the string comparator. return l.codeWScopeObject().woCompare( r.codeWScopeObject(), BSONObj(), rules | BSONElement::ComparisonRules::kConsiderFieldName); } } MONGO_UNREACHABLE; }