-
Notifications
You must be signed in to change notification settings - Fork 106
NODE-1259 Refactor mongodb-core to use a single Topology type (part 1) #303
Conversation
This is the core definition of a single Topology type meant to replace the existing `Mongos` and `Replset` types. It presently passes all SDAM tests, however is not yet hooked up to use the existing `Server` type for internal representation of servers. NODE-1259
This adds an incomplete, but sufficient amount of SDAM monitoring to the new Topology type in order to pass the SDAM monitoring YAML tests. NODE-1259
The server selection test runner is nearly the same as that used for max staleness tests. I've included both into the same file, with an eye towards refactoring the runner out in the future.
This adds a `maxStalenessReducer` to our server selectors, and adds it in all the right places in the `readPreferenceServerSelector`.
To prevent breaking changes, we will still support passing in tags as an object rather than the documented required array. This will change in 4.x
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preliminary feedback
* @return {MongoTimeoutError} A MongoTimeoutError instance | ||
* @extends {MongoError} | ||
*/ | ||
const MongoTimeoutError = function(message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be done with class
and extends
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but I was just following existing convention in the file. I'd prefer to convert them in a separate commit wholesale
@@ -98,7 +98,12 @@ function executeEntry(file, path) { | |||
}); | |||
|
|||
// Create read preference | |||
var rp = new ReadPreference(convert(readPreference.mode), readPreference.tag_sets); | |||
var rp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let
const MAX_SUPPORTED_WIRE_VERSION = 5; | ||
|
||
// An enumeration of topology types we know about | ||
const TopologyType = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
['Single', 'ReplicaSetNoPrimary', 'ReplicaSetWithPrimary', 'Sharded', 'Unknown'].reduce((memo, key) => {
memo[key] = key;
return memo;
}, {});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tbh that feels way less readable to me for the sake of reducing very limited (and unlikely to ever change) text duplication
* @param {number} maxSetVersion | ||
* @param {ObjectId} maxElectionId | ||
*/ | ||
constructor(topologyType, serverDescriptions, setName, maxSetVersion, maxElectionId, options) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should POJO this constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this request keeps coming up in code reviews, is there a particular reason you want to do that beyond readability? This is an internal type to boot, so I'm not sure what it buys us.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better from a maintenance perspective. You can see a bunch of the benefits of RORO here. We don't get everything b/c we still have Node 4, but from a maintenance perspective it is really useful.
Also, from past experience, I have been burned by not following RORO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dunno, I'm not convinced. Should we make a class called TopologyUpdateParameters
? I think it's a little overkill just for the benefit of having named parameters. The named parameters example in that article is also not very compelling - agreed, definitely don't use "magic" boolean parameters. In this case, we are very clearly passing in named variables, essentially giving us the same benefit. On top of that, requiring an extra allocation of an object just to call a function seems needlessly wasteful. I we can discuss POJOs for the future, but I don't think this PR is the place to make that choice
this.compatible = false; | ||
this.compatibilityError = `Server at ${serverDescription.address} requires wire version ${ | ||
serverDescription.minWireVersion | ||
}, but this version of the driver only supports up to ${MAX_SUPPORTED_WIRE_VERSION}.`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should there be a break
after this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not according to spec
lib/sdam/topology.js
Outdated
? TopologyType.ReplicaSetNoPrimary | ||
: TopologyType.Unknown; | ||
|
||
const topologyId = globalTopologyCounter++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make a topologyCounter()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what do you mean by this? a function on the class itself? a package-local variable seems fine to me, what would we gain otherwise?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just don't like the idea of incrementing the globalTopologyCounter
inline. I'd rather that we wrap it in a topologyCounter
function that internally handles it.
lib/sdam/topology.js
Outdated
const topologyId = globalTopologyCounter++; | ||
|
||
const serverDescriptions = seedlist.reduce((result, seed) => { | ||
const address = seed.port ? `${seed.host}:${seed.port}` : `${seed.host}:27017`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets make an address(...)
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be used only here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, just to clean it up.
options.serverSelectionTimeoutMS, | ||
process.hrtime(), | ||
(err, servers) => { | ||
if (err) return callback(err, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we needed to wrap the callback
in this arrow function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't follow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I missed randomSelection
. Nvm.
* @param {authResultCallback} callback A callback function | ||
*/ | ||
auth(mechanism, db, options, callback) { | ||
callback(null, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this not implemented yet?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes these are all stubs right now
* @param {authResultCallback} callback A callback function | ||
*/ | ||
logout(db, callback) { | ||
callback(null, null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same Q
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes these are all stubs right now
This PR introduces a single
Topology
type meant to completely replaceServer
/Replset
/Mongos
in bothmongodb-core
andnode-mongodb-native
. Presently it is not hooked up at all to the driver, but passes all SDAM, server selection and max-staleness tests. The next step will be to actually connect the internal pieces so we can effectively replace the existing topologies. (Broken apart to give a glimmer of a chance at reviewing)