Skip to content

Commit f61f965

Browse files
author
rstam
committed
CSHARP-589: Refactor some logic from MongoCollection and other classes into a set of Operations classes.
1 parent 050fe3f commit f61f965

19 files changed

+1307
-407
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/* Copyright 2010-2013 10gen Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using System.Collections;
18+
using System.Collections.Generic;
19+
using MongoDB.Bson;
20+
using MongoDB.Driver.Internal;
21+
22+
namespace MongoDB.Driver
23+
{
24+
/// <summary>
25+
/// Represents a container for the CanCommandBeSentToSecondary delegate.
26+
/// </summary>
27+
public static class CanCommandBeSentToSecondary
28+
{
29+
// private static fields
30+
private static Func<BsonDocument, bool> __delegate = DefaultImplementation;
31+
private static HashSet<string> __secondaryOkCommands = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
32+
{
33+
"group",
34+
"aggregate",
35+
"collStats",
36+
"dbStats",
37+
"count",
38+
"distinct",
39+
"geoNear",
40+
"geoSearch",
41+
"geoWalk"
42+
};
43+
44+
// public static properties
45+
/// <summary>
46+
/// Gets or sets the CanCommandBeSentToSecondary delegate.
47+
/// </summary>
48+
public static Func<BsonDocument, bool> Delegate
49+
{
50+
get { return __delegate; }
51+
set
52+
{
53+
if (value == null)
54+
{
55+
throw new ArgumentNullException("value");
56+
}
57+
__delegate = value;
58+
}
59+
}
60+
61+
// public static methods
62+
/// <summary>
63+
/// Default implementation of the CanCommandBeSentToSecondary delegate.
64+
/// </summary>
65+
/// <param name="document">The command.</param>
66+
/// <returns>True if the command can be sent to a secondary member of a replica set.</returns>
67+
public static bool DefaultImplementation(BsonDocument document)
68+
{
69+
if (document.ElementCount == 0)
70+
{
71+
return false;
72+
}
73+
74+
var commandName = document.GetElement(0).Name;
75+
76+
if (__secondaryOkCommands.Contains(commandName))
77+
{
78+
return true;
79+
}
80+
81+
if (commandName.Equals("mapreduce", StringComparison.InvariantCultureIgnoreCase))
82+
{
83+
BsonValue outValue;
84+
if (document.TryGetValue("out", out outValue) && outValue.IsBsonDocument)
85+
{
86+
return outValue.AsBsonDocument.Contains("inline");
87+
}
88+
}
89+
90+
return false;
91+
}
92+
}
93+
}

MongoDB.Driver/Communication/MongoConnection.cs

Lines changed: 4 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@
1919
using System.Net.Sockets;
2020
using System.Security.Authentication;
2121
using System.Security.Cryptography.X509Certificates;
22-
using MongoDB.Bson;
2322
using MongoDB.Bson.IO;
2423
using MongoDB.Bson.Serialization;
25-
using MongoDB.Bson.Serialization.Serializers;
2624
using MongoDB.Driver.Communication.Security;
2725

2826
namespace MongoDB.Driver.Internal
@@ -242,63 +240,6 @@ internal void Open()
242240
.Authenticate();
243241
}
244242

245-
// this is a low level method that doesn't require a MongoServer
246-
// so it can be used while connecting to a MongoServer
247-
internal TCommandResult RunCommandAs<TCommandResult>(
248-
string databaseName,
249-
QueryFlags queryFlags,
250-
CommandDocument command,
251-
bool throwOnError) where TCommandResult : CommandResult
252-
{
253-
var commandResultSerializer = BsonSerializer.LookupSerializer(typeof(TCommandResult));
254-
IBsonSerializationOptions commandResultSerializationOptions = null;
255-
return RunCommandAs<TCommandResult>(databaseName, queryFlags, command, commandResultSerializer, commandResultSerializationOptions, throwOnError);
256-
}
257-
258-
internal TCommandResult RunCommandAs<TCommandResult>(
259-
string databaseName,
260-
QueryFlags queryFlags,
261-
CommandDocument command,
262-
IBsonSerializer commandResultSerializer,
263-
IBsonSerializationOptions commandResultSerializationOptions,
264-
bool throwOnError) where TCommandResult : CommandResult
265-
{
266-
var commandName = command.GetElement(0).Name;
267-
268-
var writerSettings = new BsonBinaryWriterSettings
269-
{
270-
Encoding = _serverInstance.Settings.WriteEncoding ?? MongoDefaults.WriteEncoding,
271-
GuidRepresentation = GuidRepresentation.Unspecified,
272-
MaxDocumentSize = _serverInstance.MaxDocumentSize
273-
};
274-
275-
var queryMessage = new MongoQueryMessage(writerSettings, databaseName + ".$cmd", queryFlags, 0, 1, command, null);
276-
SendMessage(queryMessage, null, databaseName); // write concern doesn't apply to queries
277-
278-
var readerSettings = new BsonBinaryReaderSettings
279-
{
280-
Encoding = _serverInstance.Settings.ReadEncoding ?? MongoDefaults.ReadEncoding,
281-
GuidRepresentation = GuidRepresentation.Unspecified,
282-
MaxDocumentSize = _serverInstance.MaxDocumentSize
283-
};
284-
var reply = ReceiveMessage<TCommandResult>(readerSettings, commandResultSerializer, commandResultSerializationOptions);
285-
if (reply.NumberReturned == 0)
286-
{
287-
var message = string.Format("Command '{0}' failed. No response returned.", commandName);
288-
throw new MongoCommandException(message);
289-
}
290-
291-
var commandResult = reply.Documents[0];
292-
commandResult.Command = command;
293-
294-
if (throwOnError && !commandResult.Ok)
295-
{
296-
throw new MongoCommandException(commandResult);
297-
}
298-
299-
return commandResult;
300-
}
301-
302243
internal MongoReplyMessage<TDocument> ReceiveMessage<TDocument>(
303244
BsonBinaryReaderSettings readerSettings,
304245
IBsonSerializer serializer,
@@ -334,35 +275,13 @@ internal MongoReplyMessage<TDocument> ReceiveMessage<TDocument>(
334275
}
335276
}
336277

337-
internal WriteConcernResult SendMessage(BsonBuffer buffer, MongoRequestMessage message, WriteConcern writeConcern, string databaseName)
278+
internal void SendMessage(BsonBuffer buffer, int requestId)
338279
{
339280
if (_state == MongoConnectionState.Closed) { throw new InvalidOperationException("Connection is closed."); }
340281
lock (_connectionLock)
341282
{
342283
_lastUsedAt = DateTime.UtcNow;
343-
_requestId = message.RequestId;
344-
345-
CommandDocument getLastErrorCommand = null;
346-
if (writeConcern != null && writeConcern.Enabled)
347-
{
348-
var fsync = (writeConcern.FSync == null) ? null : (BsonValue)writeConcern.FSync;
349-
var journal = (writeConcern.Journal == null) ? null : (BsonValue)writeConcern.Journal;
350-
var w = (writeConcern.W == null) ? null : writeConcern.W.ToGetLastErrorWValue();
351-
var wTimeout = (writeConcern.WTimeout == null) ? null : (BsonValue)(int)writeConcern.WTimeout.Value.TotalMilliseconds;
352-
353-
getLastErrorCommand = new CommandDocument
354-
{
355-
{ "getlasterror", 1 }, // use all lowercase for backward compatibility
356-
{ "fsync", fsync, fsync != null },
357-
{ "j", journal, journal != null },
358-
{ "w", w, w != null },
359-
{ "wtimeout", wTimeout, wTimeout != null }
360-
};
361-
362-
// piggy back on network transmission for message
363-
var getLastErrorMessage = new MongoQueryMessage(message.WriterSettings, databaseName + ".$cmd", QueryFlags.None, 0, 1, getLastErrorCommand, null);
364-
getLastErrorMessage.WriteToBuffer(buffer);
365-
}
284+
_requestId = requestId;
366285

367286
try
368287
{
@@ -380,46 +299,15 @@ internal WriteConcernResult SendMessage(BsonBuffer buffer, MongoRequestMessage m
380299
HandleException(ex);
381300
throw;
382301
}
383-
384-
WriteConcernResult writeConcernResult = null;
385-
if (writeConcern != null && writeConcern.Enabled)
386-
{
387-
var readerSettings = new BsonBinaryReaderSettings
388-
{
389-
Encoding = _serverInstance.Settings.ReadEncoding ?? MongoDefaults.ReadEncoding,
390-
GuidRepresentation = message.WriterSettings.GuidRepresentation,
391-
MaxDocumentSize = _serverInstance.MaxDocumentSize
392-
};
393-
var writeConcernResultSerializer = BsonSerializer.LookupSerializer(typeof(WriteConcernResult));
394-
var replyMessage = ReceiveMessage<WriteConcernResult>(readerSettings, writeConcernResultSerializer, null);
395-
writeConcernResult = replyMessage.Documents[0];
396-
writeConcernResult.Command = getLastErrorCommand;
397-
if (!writeConcernResult.Ok)
398-
{
399-
var errorMessage = string.Format(
400-
"WriteConcern detected an error '{0}'. (response was {1}).",
401-
writeConcernResult.ErrorMessage, writeConcernResult.Response.ToJson());
402-
throw new WriteConcernException(errorMessage, writeConcernResult);
403-
}
404-
if (writeConcernResult.HasLastErrorMessage)
405-
{
406-
var errorMessage = string.Format(
407-
"WriteConcern detected an error '{0}'. (Response was {1}).",
408-
writeConcernResult.LastErrorMessage, writeConcernResult.Response.ToJson());
409-
throw new WriteConcernException(errorMessage, writeConcernResult);
410-
}
411-
}
412-
413-
return writeConcernResult;
414302
}
415303
}
416304

417-
internal WriteConcernResult SendMessage(MongoRequestMessage message, WriteConcern writeConcern, string databaseName)
305+
internal void SendMessage(MongoRequestMessage message)
418306
{
419307
using (var buffer = new BsonBuffer(new MultiChunkBuffer(BsonChunkPool.Default), true))
420308
{
421309
message.WriteToBuffer(buffer);
422-
return SendMessage(buffer, message, writeConcern, databaseName);
310+
SendMessage(buffer, message.RequestId);
423311
}
424312
}
425313

MongoDB.Driver/Communication/MongoServerInstance.cs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
using System.Net;
2020
using System.Net.Sockets;
2121
using System.Threading;
22+
using MongoDB.Bson.IO;
23+
using MongoDB.Bson.Serialization;
2224
using MongoDB.Driver.Internal;
25+
using MongoDB.Driver.Operations;
2326

2427
namespace MongoDB.Driver
2528
{
@@ -535,26 +538,21 @@ private void LookupServerInformation(MongoConnection connection)
535538
try
536539
{
537540
var isMasterCommand = new CommandDocument("ismaster", 1);
538-
isMasterResult = connection.RunCommandAs<IsMasterResult>("admin", QueryFlags.SlaveOk, isMasterCommand, false);
539-
isMasterResult.Command = isMasterCommand;
540-
if (!isMasterResult.Ok)
541-
{
542-
throw new MongoCommandException(isMasterResult);
543-
}
541+
isMasterResult = RunCommandAs<IsMasterResult>(connection, "admin", isMasterCommand);
544542

545543
MongoServerBuildInfo buildInfo;
546-
var buildInfoCommand = new CommandDocument("buildinfo", 1);
547-
var buildInfoResult = connection.RunCommandAs<CommandResult>("admin", QueryFlags.SlaveOk, buildInfoCommand, false);
548-
if (buildInfoResult.Ok)
544+
try
549545
{
546+
var buildInfoCommand = new CommandDocument("buildinfo", 1);
547+
var buildInfoResult = RunCommandAs<CommandResult>(connection, "admin", buildInfoCommand);
550548
buildInfo = MongoServerBuildInfo.FromCommandResult(buildInfoResult);
551549
}
552-
else
550+
catch (MongoCommandException ex)
553551
{
554552
// short term fix: if buildInfo fails due to auth we don't know the server version; see CSHARP-324
555-
if (buildInfoResult.ErrorMessage != "need to login")
553+
if (ex.CommandResult.ErrorMessage != "need to login")
556554
{
557-
throw new MongoCommandException(buildInfoResult);
555+
throw;
558556
}
559557
buildInfo = null;
560558
}
@@ -648,7 +646,7 @@ private void Ping(MongoConnection connection)
648646
{
649647
var pingCommand = new CommandDocument("ping", 1);
650648
Stopwatch stopwatch = Stopwatch.StartNew();
651-
connection.RunCommandAs<CommandResult>("admin", QueryFlags.SlaveOk, pingCommand, true);
649+
RunCommandAs<CommandResult>(connection, "admin", pingCommand);
652650
stopwatch.Stop();
653651
var currentAverage = _pingTimeAggregator.Average;
654652
_pingTimeAggregator.Include(stopwatch.Elapsed);
@@ -666,6 +664,27 @@ private void Ping(MongoConnection connection)
666664
}
667665
}
668666

667+
private TCommandResult RunCommandAs<TCommandResult>(MongoConnection connection, string databaseName, IMongoCommand command)
668+
where TCommandResult : CommandResult
669+
{
670+
var readerSettings = new BsonBinaryReaderSettings();
671+
var writerSettings = new BsonBinaryWriterSettings();
672+
var resultSerializer = BsonSerializer.LookupSerializer(typeof(TCommandResult));
673+
674+
var commandOperation = new CommandOperation<TCommandResult>(
675+
databaseName,
676+
readerSettings,
677+
writerSettings,
678+
command,
679+
QueryFlags.SlaveOk,
680+
null, // options
681+
null, // readPreference
682+
null, // serializationOptions
683+
resultSerializer);
684+
685+
return commandOperation.Execute(connection);
686+
}
687+
669688
private void StateVerificationTimerCallback()
670689
{
671690
if (_inStateVerification)

0 commit comments

Comments
 (0)