// find all oplog entries for a given OID in the oplog.refs collection and apply them // TODO this should be a range query on oplog.refs where _id.oid == oid and applyOps to // each entry found. The locking of the query interleaved with the locking in the applyOps // did not work, so it a sequence of point queries. // TODO verify that the query plan is a indexed lookup. // TODO verify that the query plan does not fetch too many docs and then only process one of them. void applyRefOp(BSONObj entry) { OID oid = entry["ref"].OID(); LOG(3) << "apply ref " << entry << " oid " << oid << endl; long long seq = 0; // note that 0 is smaller than any of the seq numbers while (1) { BSONObj entry; { LOCK_REASON(lockReason, "repl: finding oplog.refs entry to apply"); Client::ReadContext ctx(rsOplogRefs, lockReason); // TODO: Should this be using rsOplogRefsDetails, verifying non-null? Collection *cl = getCollection(rsOplogRefs); if (cl == NULL || !cl->findOne(BSON("_id" << BSON("$gt" << BSON("oid" << oid << "seq" << seq))), entry, true)) { break; } } BSONElement e = entry.getFieldDotted("_id.seq"); seq = e.Long(); BSONElement eOID = entry.getFieldDotted("_id.oid"); if (oid != eOID.OID()) { break; } LOG(3) << "apply " << entry << " seq=" << seq << endl; applyOps(entry["ops"].Array()); } }
double StatUtil::diff( const string& name , const BSONObj& a , const BSONObj& b ) { BSONElement x = a.getFieldDotted( name.c_str() ); BSONElement y = b.getFieldDotted( name.c_str() ); if ( ! x.isNumber() || ! y.isNumber() ) return -1; return ( y.number() - x.number() ) / _seconds; }
bool GeoParser::isGeoJSONPolygon(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_POLYGON != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinates = coordElt.Array(); // Must be at least one element, the outer shell if (coordinates.empty()) { return false; } // Verify that the shell is a bunch'a coordinates. for (size_t i = 0; i < coordinates.size(); ++i) { if (Array != coordinates[i].type()) { return false; } const vector<BSONElement>& thisLoop = coordinates[i].Array(); // A triangle is the simplest 2d shape, and we repeat a vertex, so, 4. if (thisLoop.size() < 4) { return false; } if (!isArrayOfCoordinates(thisLoop)) { return false; } if (!isLoopClosed(thisLoop)) { return false; } } return true; }
double StatUtil::percent( const char * outof , const char * val , const BSONObj& a , const BSONObj& b ) { double x = ( b.getFieldDotted( val ).number() - a.getFieldDotted( val ).number() ); double y = ( b.getFieldDotted( outof ).number() - a.getFieldDotted( outof ).number() ); if ( y == 0 ) return 0; double p = x / y; p = (double)((int)(p * 1000)) / 10; return p; }
bool GeoParser::isLine(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_LINESTRING != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } return isValidLineString(coordElt.Array()); }
static bool isGeoJSONPolygon(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_POLYGON != type.String()) { return false; } if (!GeoParser::crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } return isGeoJSONPolygonCoordinates(coordElt.Array()); }
bool GeoParser::parsePolygon(const BSONObj &obj, PolygonWithCRS *out) { if (isGeoJSONPolygon(obj)) { const vector<BSONElement>& coordinates = obj.getFieldDotted(GEOJSON_COORDINATES).Array(); if (!parseGeoJSONCRS(obj, &out->crs)) return false; if (out->crs == SPHERE) { out->s2Polygon.reset(new S2Polygon()); if (!parseGeoJSONPolygonCoordinates(coordinates, obj, out->s2Polygon.get())) { return false; } } else if (out->crs == STRICT_SPHERE) { out->bigPolygon.reset(new BigSimplePolygon()); if (!parseBigSimplePolygonCoordinates(coordinates, obj, out->bigPolygon.get())) { return false; } } } else { BSONObjIterator typeIt(obj); BSONElement type = typeIt.next(); BSONObjIterator coordIt(type.embeddedObject()); vector<Point> points; while (coordIt.more()) { Point p; if (!parseLegacyPoint(coordIt.next().Obj(), &p)) { return false; } points.push_back(p); } out->oldPolygon.init(points); out->crs = FLAT; } return true; }
ShardStatus::ShardStatus( const Shard& shard , const BSONObj& obj , const BSONObj& dblistobj ) : _shard( shard ), _isDraining(shard.isDraining()) { _dataSize = dblistobj.getFieldDotted("totalUncompressedSize").numberLong(); _hasOpsQueued = obj["writeBacksQueued"].Bool(); _writeLock = 0; // TODO _mongoVersion = obj["version"].String(); }
/* well ordered compare */ int BSONObj::woSortOrder(const BSONObj& other, const BSONObj& sortKey , bool useDotted ) const { if ( isEmpty() ) return other.isEmpty() ? 0 : -1; if ( other.isEmpty() ) return 1; uassert( 10060 , "woSortOrder needs a non-empty sortKey" , ! sortKey.isEmpty() ); BSONObjIterator i(sortKey); while ( 1 ) { BSONElement f = i.next(); if ( f.eoo() ) return 0; BSONElement l = useDotted ? getFieldDotted( f.fieldName() ) : getField( f.fieldName() ); if ( l.eoo() ) l = staticNull.firstElement(); BSONElement r = useDotted ? other.getFieldDotted( f.fieldName() ) : other.getField( f.fieldName() ); if ( r.eoo() ) r = staticNull.firstElement(); int x = l.woCompare( r, false ); if ( f.number() < 0 ) x = -x; if ( x != 0 ) return x; } return -1; }
Status GeoParser::parseMultiPolygon(const BSONObj& obj, bool skipValidation, MultiPolygonWithCRS* out) { Status status = Status::OK(); status = parseGeoJSONCRS(obj, &out->crs); if (!status.isOK()) return status; BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (Array != coordElt.type()) return BAD_VALUE("MultiPolygon coordinates must be an array"); out->polygons.clear(); vector<S2Polygon*>& polygons = out->polygons.mutableVector(); BSONObjIterator it(coordElt.Obj()); // Iterate array while (it.more()) { polygons.push_back(new S2Polygon()); status = parseGeoJSONPolygonCoordinates(it.next(), skipValidation, polygons.back()); if (!status.isOK()) return status; } if (0 == polygons.size()) return BAD_VALUE("MultiPolygon coordinates must have at least 1 element"); return Status::OK(); }
Status WiredTigerKVEngine::createSortedDataInterface(OperationContext* opCtx, StringData ident, const IndexDescriptor* desc) { _checkIdentPath(ident); std::string collIndexOptions; const Collection* collection = desc->getCollection(); // Treat 'collIndexOptions' as an empty string when the collection member of 'desc' is NULL in // order to allow for unit testing WiredTigerKVEngine::createSortedDataInterface(). if (collection) { const CollectionCatalogEntry* cce = collection->getCatalogEntry(); const CollectionOptions collOptions = cce->getCollectionOptions(opCtx); if (!collOptions.indexOptionDefaults["storageEngine"].eoo()) { BSONObj storageEngineOptions = collOptions.indexOptionDefaults["storageEngine"].Obj(); collIndexOptions = storageEngineOptions.getFieldDotted("wiredTiger.configString").valuestrsafe(); } } StatusWith<std::string> result = WiredTigerIndex::generateCreateString(_indexOptions, collIndexOptions, *desc); if (!result.isOK()) { return result.getStatus(); } std::string config = result.getValue(); LOG(2) << "WiredTigerKVEngine::createSortedDataInterface ident: " << ident << " config: " << config; return wtRCToStatus(WiredTigerIndex::Create(opCtx, _uri(ident), config)); }
void getKeys( const BSONObj &obj, BSONObjSet &keys ) const { BSONElement loc = obj.getFieldDotted( _geo ); if ( loc.eoo() ) return; uassert( 13323 , "latlng not an array" , loc.isABSONObj() ); string root; { BSONObjIterator i( loc.Obj() ); BSONElement x = i.next(); BSONElement y = i.next(); root = makeString( hash(x) , hash(y) ); } verify( _other.size() == 1 ); BSONElementSet all; obj.getFieldsDotted( _other[0] , all ); if ( all.size() == 0 ) { _add( obj , root , BSONElement() , keys ); } else { for ( BSONElementSet::iterator i=all.begin(); i!=all.end(); ++i ) { _add( obj , root , *i , keys ); } } }
Status FTSSpec::getIndexPrefix( const BSONObj& query, BSONObj* out ) const { if ( numExtraBefore() == 0 ) { *out = BSONObj(); return Status::OK(); } BSONObjBuilder b; for ( unsigned i = 0; i < numExtraBefore(); i++ ) { BSONElement e = query.getFieldDotted(extraBefore(i)); if ( e.eoo() ) return Status( ErrorCodes::BadValue, str::stream() << "need have an equality filter on: " << extraBefore(i) ); if ( e.isABSONObj() && e.Obj().firstElement().getGtLtOp( -1 ) != -1 ) return Status( ErrorCodes::BadValue, str::stream() << "need have an equality filter on: " << extraBefore(i) ); b.append( e ); } *out = b.obj(); return Status::OK(); }
void GeoParser::parseGeoJSONPolygon(const BSONObj& obj, S2Polygon* out) { const vector<BSONElement>& coordinates = obj.getFieldDotted(GEOJSON_COORDINATES).Array(); const vector<BSONElement>& exteriorRing = coordinates[0].Array(); vector<S2Point> exteriorVertices; parsePoints(exteriorRing, &exteriorVertices); S2PolygonBuilderOptions polyOptions; polyOptions.set_validate(true); S2PolygonBuilder polyBuilder(polyOptions); S2Loop exteriorLoop(exteriorVertices); if (exteriorLoop.is_hole()) { exteriorLoop.Invert(); } polyBuilder.AddLoop(&exteriorLoop); // Subsequent arrays of coordinates are interior rings/holes. for (size_t i = 1; i < coordinates.size(); ++i) { vector<S2Point> holePoints; parsePoints(coordinates[i].Array(), &holePoints); // Interior rings are clockwise. S2Loop holeLoop(holePoints); if (!holeLoop.is_hole()) { holeLoop.Invert(); } polyBuilder.AddLoop(&holeLoop); } polyBuilder.AssemblePolygon(out, NULL); }
Status GeoParser::parseMultiLine(const BSONObj &obj, MultiLineWithCRS *out) { Status status = Status::OK(); status = parseGeoJSONCRS(obj, &out->crs); if (!status.isOK()) return status; BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (Array != coordElt.type()) return BAD_VALUE("MultiLineString coordinates must be an array"); out->lines.clear(); vector<S2Polyline*>& lines = out->lines.mutableVector(); BSONObjIterator it(coordElt.Obj()); // Iterate array while (it.more()) { lines.push_back(new S2Polyline()); status = parseGeoJSONLineCoordinates(it.next(), lines.back()); if (!status.isOK()) return status; } if (0 == lines.size()) return BAD_VALUE("MultiLineString coordinates must have at least 1 element"); return Status::OK(); }
static void handleCursorCommand(CursorId id, BSONObj& cmdObj, BSONObjBuilder& result) { BSONElement batchSizeElem = cmdObj.getFieldDotted("cursor.batchSize"); const long long batchSize = batchSizeElem.isNumber() ? batchSizeElem.numberLong() : 101; // same as query ClientCursorPin pin(id); ClientCursor* cursor = pin.c(); massert(16958, "Cursor shouldn't have been deleted", cursor); verify(cursor->isAggCursor); PipelineRunner* runner = dynamic_cast<PipelineRunner*>(cursor->getRunner()); verify(runner); try { const string cursorNs = cursor->ns(); // we need this after cursor may have been deleted // can't use result BSONObjBuilder directly since it won't handle exceptions correctly. BSONArrayBuilder resultsArray; const int byteLimit = MaxBytesToReturnToClientAtOnce; BSONObj next; for (int objCount = 0; objCount < batchSize; objCount++) { // The initial getNext() on a PipelineRunner may be very expensive so we don't do it // when batchSize is 0 since that indicates a desire for a fast return. if (runner->getNext(&next, NULL) != Runner::RUNNER_ADVANCED) { pin.deleteUnderlying(); id = 0; cursor = NULL; // make it an obvious error to use cursor after this point break; } if (resultsArray.len() + next.objsize() > byteLimit) { // too big. next will be the first doc in the second batch runner->pushBack(next); break; } resultsArray.append(next); } if (cursor) { // If a time limit was set on the pipeline, remaining time is "rolled over" to the // cursor (for use by future getmore ops). cursor->setLeftoverMaxTimeMicros( cc().curop()->getRemainingMaxTimeMicros() ); } BSONObjBuilder cursorObj(result.subobjStart("cursor")); cursorObj.append("id", id); cursorObj.append("ns", cursorNs); cursorObj.append("firstBatch", resultsArray.arr()); cursorObj.done(); } catch (...) { // Clean up cursor on way out of scope. pin.deleteUnderlying(); throw; } }
bool GeoParser::isGeoJSONLineString(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_LINESTRING != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinateArray = coordElt.Array(); if (coordinateArray.size() < 2) { return false; } return isArrayOfCoordinates(coordinateArray); }
bool GeoParser::isMultiPoint(const BSONObj &obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_MULTI_POINT != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinates = coordElt.Array(); if (0 == coordinates.size()) { return false; } return isArrayOfCoordinates(coordinates); }
// { "type": "GeometryCollection", // "geometries": [ // { "type": "Point", // "coordinates": [100.0, 0.0] // }, // { "type": "LineString", // "coordinates": [ [101.0, 0.0], [102.0, 1.0] ] // } // ] // } Status GeoParser::parseGeometryCollection(const BSONObj& obj, bool skipValidation, GeometryCollection* out) { BSONElement coordElt = obj.getFieldDotted(GEOJSON_GEOMETRIES); if (Array != coordElt.type()) return BAD_VALUE("GeometryCollection geometries must be an array"); const vector<BSONElement>& geometries = coordElt.Array(); if (0 == geometries.size()) return BAD_VALUE("GeometryCollection geometries must have at least 1 element"); for (size_t i = 0; i < geometries.size(); ++i) { if (Object != geometries[i].type()) return BAD_VALUE("Element " << i << " of \"geometries\" is not an object"); const BSONObj& geoObj = geometries[i].Obj(); GeoJSONType type = parseGeoJSONType(geoObj); if (GEOJSON_UNKNOWN == type) return BAD_VALUE("Unknown GeoJSON type: " << geometries[i].toString(false)); if (GEOJSON_GEOMETRY_COLLECTION == type) return BAD_VALUE( "GeometryCollections cannot be nested: " << geometries[i].toString(false)); Status status = Status::OK(); if (GEOJSON_POINT == type) { out->points.resize(out->points.size() + 1); status = parseGeoJSONPoint(geoObj, &out->points.back()); } else if (GEOJSON_LINESTRING == type) { out->lines.mutableVector().push_back(new LineWithCRS()); status = parseGeoJSONLine(geoObj, skipValidation, out->lines.vector().back()); } else if (GEOJSON_POLYGON == type) { out->polygons.mutableVector().push_back(new PolygonWithCRS()); status = parseGeoJSONPolygon(geoObj, skipValidation, out->polygons.vector().back()); } else if (GEOJSON_MULTI_POINT == type) { out->multiPoints.mutableVector().push_back(new MultiPointWithCRS()); status = parseMultiPoint(geoObj, out->multiPoints.mutableVector().back()); } else if (GEOJSON_MULTI_LINESTRING == type) { out->multiLines.mutableVector().push_back(new MultiLineWithCRS()); status = parseMultiLine(geoObj, skipValidation, out->multiLines.mutableVector().back()); } else if (GEOJSON_MULTI_POLYGON == type) { out->multiPolygons.mutableVector().push_back(new MultiPolygonWithCRS()); status = parseMultiPolygon( geoObj, skipValidation, out->multiPolygons.mutableVector().back()); } else { // Should not reach here. invariant(false); } // Check parsing result. if (!status.isOK()) return status; } return Status::OK(); }
// Entry point for a search. virtual shared_ptr<Cursor> newCursor(const BSONObj& query, const BSONObj& order, int numWanted) const { vector<QueryGeometry> regions; double maxDistance = DBL_MAX; bool isNear = false; bool isIntersect = false; // Go through the fields that we index, and for each geo one, make a QueryGeometry // object for the S2Cursor class to do intersection testing/cover generating with. for (size_t i = 0; i < _fields.size(); ++i) { const IndexedField &field = _fields[i]; if (IndexedField::GEO != field.type) { continue; } BSONElement e = query.getFieldDotted(field.name); if (e.eoo()) { continue; } if (!e.isABSONObj()) { continue; } BSONObj obj = e.Obj(); QueryGeometry geoQueryField(field.name); if (parseLegacy(obj, &geoQueryField, &isNear, &isIntersect, &maxDistance)) { regions.push_back(geoQueryField); } else if (parseQuery(obj, &geoQueryField, &isNear, &isIntersect, &maxDistance)) { regions.push_back(geoQueryField); } else { uasserted(16535, "can't parse query for *2d geo search: " + obj.toString()); } } if (isNear && isIntersect ) { uasserted(16474, "Can't do both near and intersect, query: " + query.toString()); } // I copied this from 2d.cpp. Guard against perversion. if (numWanted < 0) numWanted *= -1; if (0 == numWanted) numWanted = INT_MAX; BSONObjBuilder geoFieldsToNuke; for (size_t i = 0; i < _fields.size(); ++i) { const IndexedField &field = _fields[i]; if (IndexedField::GEO != field.type) { continue; } geoFieldsToNuke.append(field.name, ""); } // false means we want to filter OUT geoFieldsToNuke, not filter to include only that. BSONObj filteredQuery = query.filterFieldsUndotted(geoFieldsToNuke.obj(), false); if (isNear) { S2NearCursor *cursor = new S2NearCursor(keyPattern(), getDetails(), filteredQuery, regions, _params, numWanted, maxDistance); return shared_ptr<Cursor>(cursor); } else { // Default to intersect. S2Cursor *cursor = new S2Cursor(keyPattern(), getDetails(), filteredQuery, regions, _params, numWanted); return shared_ptr<Cursor>(cursor); } }
//// What we publicly export bool GeoParser::isGeoJSONPoint(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_POINT != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinates = coordElt.Array(); if (coordinates.size() != 2) { return false; } if (!coordinates[0].isNumber() || !coordinates[1].isNumber()) { return false; } double lat = coordinates[1].Number(); return lat >= -90 && lat <= 90; }
bool GeoParser::parseLine(const BSONObj& obj, LineWithCRS* out) { vector<S2Point> vertices; if (!parsePoints(obj.getFieldDotted(GEOJSON_COORDINATES).Array(), &vertices)) { return false; } eraseDuplicatePoints(&vertices); out->line.Init(vertices); out->crs = SPHERE; return true; }
bool ShardKeyPattern::hasShardKey( const BSONObj& obj ) const { /* this is written s.t. if obj has lots of fields, if the shard key fields are early, it is fast. so a bit more work to try to be semi-fast. */ for(set<string>::const_iterator it = patternfields.begin(); it != patternfields.end(); ++it) { if(obj.getFieldDotted(it->c_str()).eoo()) return false; } return true; }
bool GeoParser::isGeoJSONLineString(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_LINESTRING != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinateArray = coordElt.Array(); if (coordinateArray.size() < 2) { return false; } if (!isArrayOfCoordinates(coordinateArray)) { return false; } vector<S2Point> vertices; parsePoints(obj.getFieldDotted(GEOJSON_COORDINATES).Array(), &vertices); eraseDuplicatePoints(&vertices); return S2Polyline::IsValid(vertices); }
static bool isGeoJSONPoint(const BSONObj& obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_POINT != type.String()) { return false; } if (!GeoParser::crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinates = coordElt.Array(); if (coordinates.size() != 2) { return false; } if (!coordinates[0].isNumber() || !coordinates[1].isNumber()) { return false; } // For now, we assume all GeoJSON must be within WGS84 - this may change double lat = coordinates[1].Number(); double lng = coordinates[0].Number(); return isValidLngLat(lng, lat); }
// Copy a range of documents to the local oplog.refs collection static void copyOplogRefsRange(OplogReader &r, OID oid) { shared_ptr<DBClientCursor> c = r.getOplogRefsCursor(oid); Client::ReadContext ctx(rsOplogRefs); while (c->more()) { BSONObj b = c->next(); BSONElement eOID = b.getFieldDotted("_id.oid"); if (oid != eOID.OID()) { break; } LOG(6) << "copyOplogRefsRange " << b << endl; writeEntryToOplogRefs(b); } }
bool GeoParser::isGeometryCollection(const BSONObj &obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_GEOMETRY_COLLECTION != type.String()) { return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_GEOMETRIES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinates = coordElt.Array(); if (0 == coordinates.size()) { return false; } for (size_t i = 0; i < coordinates.size(); ++i) { if (coordinates[i].eoo() || (Object != coordinates[i].type())) { return false; } BSONObj obj = coordinates[i].Obj(); if (!isGeoJSONPoint(obj) && !isLine(obj) && !isGeoJSONPolygon(obj) && !isMultiPoint(obj) && !isMultiPolygon(obj) && !isMultiLine(obj)) { return false; } } return true; }
bool GeoParser::isMultiPolygon(const BSONObj &obj) { BSONElement type = obj.getFieldDotted(GEOJSON_TYPE); if (type.eoo() || (String != type.type())) { return false; } if (GEOJSON_TYPE_MULTI_POLYGON != type.String()) { return false; } if (!crsIsOK(obj)) { warning() << "Invalid CRS: " << obj.toString() << endl; return false; } BSONElement coordElt = obj.getFieldDotted(GEOJSON_COORDINATES); if (coordElt.eoo() || (Array != coordElt.type())) { return false; } const vector<BSONElement>& coordinates = coordElt.Array(); if (0 == coordinates.size()) { return false; } for (size_t i = 0; i < coordinates.size(); ++i) { if (coordinates[i].eoo() || (Array != coordinates[i].type())) { return false; } if (!isGeoJSONPolygonCoordinates(coordinates[i].Array())) { return false; } } return true; }
void rollbackRefOp(BSONObj entry) { OID oid = entry["ref"].OID(); LOG(3) << "rollback ref " << entry << " oid " << oid << endl; long long seq = LLONG_MAX; while (1) { BSONObj currEntry; { LOCK_REASON(lockReason, "repl: rolling back entry from oplog.refs"); Client::ReadContext ctx(rsOplogRefs, lockReason); verify(rsOplogRefsDetails != NULL); shared_ptr<Cursor> c( Cursor::make( rsOplogRefsDetails, rsOplogRefsDetails->getPKIndex(), KeyPattern::toKeyFormat(BSON( "_id" << BSON("oid" << oid << "seq" << seq))), // right endpoint KeyPattern::toKeyFormat(BSON( "_id" << BSON("oid" << oid << "seq" << 0))), // left endpoint false, -1 // direction ) ); if (c->ok()) { currEntry = c->current().copy(); } else { break; } } BSONElement e = currEntry.getFieldDotted("_id.seq"); seq = e.Long(); BSONElement eOID = currEntry.getFieldDotted("_id.oid"); if (oid != eOID.OID()) { break; } LOG(3) << "apply " << currEntry << " seq=" << seq << endl; rollbackOps(currEntry["ops"].Array()); // decrement seq so next query gets the next value seq--; } }
/* return has eoo() true if no match supports "." notation to reach into embedded objects */ BSONElement BSONObj::getFieldDotted(const char *name) const { BSONElement e = getField( name ); if ( e.eoo() ) { const char *p = strchr(name, '.'); if ( p ) { string left(name, p-name); BSONObj sub = getObjectField(left.c_str()); return sub.isEmpty() ? nullElement : sub.getFieldDotted(p+1); } } return e; }