Skip to content

Commit 2d021c5

Browse files
authored
CSHARP-2450: Improved deserialization performance by switching from HashSet<T> protected by a ReaderWriterLockSlim to a ConcurrentDictionary<K,V> outside the ReaderWriterLockSlim. (#482)
1 parent b0614b4 commit 2d021c5

File tree

1 file changed

+10
-13
lines changed

1 file changed

+10
-13
lines changed

src/MongoDB.Bson/Serialization/BsonSerializer.cs

+10-13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
using System;
17+
using System.Collections.Concurrent;
1718
using System.Collections.Generic;
1819
using System.IO;
1920
using System.Linq;
@@ -41,7 +42,8 @@ public static class BsonSerializer
4142
private static HashSet<Type> __discriminatedTypes = new HashSet<Type>();
4243
private static BsonSerializerRegistry __serializerRegistry;
4344
private static TypeMappingSerializationProvider __typeMappingSerializationProvider;
44-
private static HashSet<Type> __typesWithRegisteredKnownTypes = new HashSet<Type>();
45+
// ConcurrentDictionary<Type, object> is being used as a concurrent set of Type. The values will always be null.
46+
private static ConcurrentDictionary<Type, object> __typesWithRegisteredKnownTypes = new ConcurrentDictionary<Type, object>();
4547

4648
private static bool __useNullIdChecker = false;
4749
private static bool __useZeroIdChecker = false;
@@ -679,23 +681,15 @@ public static void Serialize(
679681
// internal static methods
680682
internal static void EnsureKnownTypesAreRegistered(Type nominalType)
681683
{
682-
__configLock.EnterReadLock();
683-
try
684-
{
685-
if (__typesWithRegisteredKnownTypes.Contains(nominalType))
686-
{
687-
return;
688-
}
689-
}
690-
finally
684+
if (__typesWithRegisteredKnownTypes.ContainsKey(nominalType))
691685
{
692-
__configLock.ExitReadLock();
686+
return;
693687
}
694688

695689
__configLock.EnterWriteLock();
696690
try
697691
{
698-
if (!__typesWithRegisteredKnownTypes.Contains(nominalType))
692+
if (!__typesWithRegisteredKnownTypes.ContainsKey(nominalType))
699693
{
700694
// only call LookupClassMap for classes with a BsonKnownTypesAttribute
701695
#if NET452
@@ -709,7 +703,10 @@ internal static void EnsureKnownTypesAreRegistered(Type nominalType)
709703
LookupSerializer(nominalType);
710704
}
711705

712-
__typesWithRegisteredKnownTypes.Add(nominalType);
706+
// NOTE: The nominalType MUST be added to __typesWithRegisteredKnownTypes after all registration
707+
// work is done to ensure that other threads don't access a partially registered nominalType
708+
// when performing the initial check above outside the __config lock.
709+
__typesWithRegisteredKnownTypes[nominalType] = null;
713710
}
714711
}
715712
finally

0 commit comments

Comments
 (0)