From 4d2097912d3034d416e540ea44cb5af79e374569 Mon Sep 17 00:00:00 2001 From: David Glasser Date: Wed, 14 Aug 2013 13:36:44 -0700 Subject: [PATCH] Add cursorSupportedByOplogTailing. --- packages/mongo-livedata/mongo_driver.js | 39 +++++++++++++++++++++++++ packages/mongo-livedata/oplog_tests.js | 32 ++++++++++++++++++++ packages/mongo-livedata/package.js | 3 ++ 3 files changed, 74 insertions(+) create mode 100644 packages/mongo-livedata/oplog_tests.js diff --git a/packages/mongo-livedata/mongo_driver.js b/packages/mongo-livedata/mongo_driver.js index aa68b16ba6..e0d9b676bc 100644 --- a/packages/mongo-livedata/mongo_driver.js +++ b/packages/mongo-livedata/mongo_driver.js @@ -1264,9 +1264,48 @@ MongoConnection.prototype._observeChangesTailable = function ( }; }; +// Does our oplog tailing code support this cursor? For now, we are being very +// conservative and allowing only simple queries with simple options. +var cursorSupportedByOplogTailing = function (cursorDescription) { + // First, check the options. + var options = cursorDescription.options; + + // We don't yet implement field filtering for oplog tailing (just because it's + // not implemented, not because there's a deep problem with implementing it). + if (options.fields) return false; + + // This option (which are mostly used for sorted cursors) require us to figure + // out where a given document fits in an order to know if it's included or + // not, and we don't track that information when doing oplog tailing. + if (options.limit || options.skip) return false; + + // For now, we're just dealing with equality queries: no $operators, regexps, + // or $and/$or/$where/etc clauses. We can expand the scope of what we're + // comfortable processing later. + return _.all(cursorDescription.selector, function (value, field) { + // No logical operators like $and. + if (field.substr(0, 1) === '$') + return false; + // We only allow scalars, not sub-documents or $operators or RegExp. + // XXX Date would be easy too, though I doubt anyone is doing equality + // lookups on dates + return typeof value === "string" || + typeof value === "number" || + typeof value === "boolean" || + value === null || + value instanceof Meteor.Collection.ObjectID; + }); +}; + + + // XXX We probably need to find a better way to expose this. Right now // it's only used by tests, but in fact you need it in normal // operation to interact with capped collections (eg, Galaxy uses it). MongoInternals.MongoTimestamp = MongoDB.Timestamp; MongoInternals.Connection = MongoConnection; + +MongoTest = { + cursorSupportedByOplogTailing: cursorSupportedByOplogTailing +}; diff --git a/packages/mongo-livedata/oplog_tests.js b/packages/mongo-livedata/oplog_tests.js new file mode 100644 index 0000000000..d8f27c7727 --- /dev/null +++ b/packages/mongo-livedata/oplog_tests.js @@ -0,0 +1,32 @@ +var OplogCollection = new Meteor.Collection("oplog-" + Random.id()); + +Tinytest.add("mongo-livedata - oplog - cursorSupportedByOplogTailing", function (test) { + var supported = function (expected, selector) { + var cursor = OplogCollection.find(selector); + test.equal( + MongoTest.cursorSupportedByOplogTailing(cursor._cursorDescription), + expected); + }; + + supported(true, "asdf"); + supported(true, 1234); + supported(true, new Meteor.Collection.ObjectID()); + + supported(true, {_id: "asdf"}); + supported(true, {_id: 1234}); + supported(true, {_id: new Meteor.Collection.ObjectID()}); + + supported(true, {foo: "asdf", + bar: 1234, + baz: new Meteor.Collection.ObjectID(), + eeney: true, + miney: false, + moe: null}); + + supported(true, {}); + + supported(false, {$and: [{foo: "asdf"}, {bar: "baz"}]}); + supported(false, {foo: {x: 1}}); + supported(false, {foo: {$gt: 1}}); + supported(false, {foo: [1, 2, 3]}); +}); diff --git a/packages/mongo-livedata/package.js b/packages/mongo-livedata/package.js index 400bf7de31..194ac21192 100644 --- a/packages/mongo-livedata/package.js +++ b/packages/mongo-livedata/package.js @@ -35,6 +35,8 @@ Package.on_use(function (api) { // Stuff that should be exposed via a real API, but we haven't yet. api.export('MongoInternals', 'server'); + // For tests only. + api.export('MongoTest', 'server'); api.add_files('mongo_driver.js', 'server'); api.add_files('local_collection_driver.js', ['client', 'server']); @@ -53,4 +55,5 @@ Package.on_test(function (api) { api.add_files('allow_tests.js', ['client', 'server']); api.add_files('collection_tests.js', ['client', 'server']); api.add_files('observe_changes_tests.js', ['client', 'server']); + api.add_files('oplog_tests.js', 'server'); });