1- // Copyright (C) 2008-2020 Xtensive LLC.
1+ // Copyright (C) 2008-2021 Xtensive LLC.
22// This code is distributed under MIT license terms.
33// See the License.txt file in the project root for more information.
44// Created by: Dmitri Maximov
@@ -19,24 +19,24 @@ namespace Xtensive.Orm.Internals
1919{
2020 internal class EntityDataReader : DomainBound
2121 {
22- private class RecordPartMapping
22+ private readonly struct RecordPartMapping
2323 {
24- public int TypeIdColumnIndex { get ; private set ; }
25- public Pair < int > [ ] Columns { get ; private set ; }
26- public TypeInfo ApproximateType { get ; private set ; }
24+ public int TypeIdColumnIndex { get ; }
25+ public IReadOnlyList < Pair < int > > Columns { get ; }
26+ public TypeInfo ApproximateType { get ; }
2727
28- public RecordPartMapping ( int typeIdColumnIndex , Pair < int > [ ] columns , TypeInfo approximateType )
28+ public RecordPartMapping ( int typeIdColumnIndex , IReadOnlyList < Pair < int > > columns , TypeInfo approximateType )
2929 {
3030 TypeIdColumnIndex = typeIdColumnIndex ;
3131 Columns = columns ;
3232 ApproximateType = approximateType ;
3333 }
3434 }
3535
36- private class CacheItem
36+ private readonly struct CacheItem
3737 {
38- public RecordSetHeader Header { get ; private set ; }
39- public RecordPartMapping [ ] Mappings { get ; private set ; }
38+ public RecordSetHeader Header { get ; }
39+ public RecordPartMapping [ ] Mappings { get ; }
4040
4141 public CacheItem ( RecordSetHeader header , RecordPartMapping [ ] mappings )
4242 {
@@ -46,77 +46,70 @@ public CacheItem(RecordSetHeader header, RecordPartMapping[] mappings)
4646 }
4747
4848 private readonly ICache < RecordSetHeader , CacheItem > cache ;
49- private readonly object _lock = new object ( ) ;
50-
49+
5150 public IEnumerable < Record > Read ( IEnumerable < Tuple > source , RecordSetHeader header , Session session )
5251 {
53- CacheItem cacheItem ;
54- var recordPartCount = header . ColumnGroups . Count ;
52+ var columns = header . Columns ;
53+ var columnGroups = header . ColumnGroups ;
54+ var recordPartCount = columnGroups . Count ;
5555 var context = new MaterializationContext ( session , recordPartCount ) ;
56- lock ( _lock ) {
57- if ( ! cache . TryGetItem ( header , false , out cacheItem ) ) {
58- var typeIdColumnName = Domain . Handlers . NameBuilder . TypeIdColumnName ;
59- var model = context . Model ;
60- var mappings = new RecordPartMapping [ recordPartCount ] ;
61- for ( int i = 0 ; i < recordPartCount ; i ++ ) {
62- var columnGroup = header . ColumnGroups [ i ] ;
63- var approximateType = columnGroup . TypeInfoRef . Resolve ( model ) ;
64- var columnMapping = new List < Pair < int > > ( ) ;
65- var typeIdColumnIndex = - 1 ;
66- foreach ( var columnIndex in columnGroup . Columns ) {
67- var column = ( MappedColumn ) header . Columns [ columnIndex ] ;
68- var columnInfo = column . ColumnInfoRef . Resolve ( model ) ;
69- FieldInfo fieldInfo ;
70- if ( ! approximateType . Fields . TryGetValue ( columnInfo . Field . Name , out fieldInfo ) )
71- continue ;
56+ if ( ! cache . TryGetItem ( header , false , out var cacheItem ) ) {
57+ var typeIdColumnName = Domain . Handlers . NameBuilder . TypeIdColumnName ;
58+ var model = context . Model ;
59+ var mappings = new RecordPartMapping [ recordPartCount ] ;
60+ for ( int i = 0 ; i < recordPartCount ; i ++ ) {
61+ var columnGroup = columnGroups [ i ] ;
62+ var approximateType = columnGroup . TypeInfoRef . Resolve ( model ) ;
63+ var columnMapping = new List < Pair < int > > ( columnGroup . Columns . Count ) ;
64+ var typeIdColumnIndex = - 1 ;
65+ foreach ( var columnIndex in columnGroup . Columns ) {
66+ var column = ( MappedColumn ) columns [ columnIndex ] ;
67+ var columnInfo = column . ColumnInfoRef . Resolve ( model ) ;
68+ if ( approximateType . Fields . TryGetValue ( columnInfo . Field . Name , out var fieldInfo ) ) {
7269 var targetColumnIndex = fieldInfo . MappingInfo . Offset ;
73- if ( columnInfo . Name == typeIdColumnName )
70+ if ( columnInfo . Name == typeIdColumnName ) {
7471 typeIdColumnIndex = column . Index ;
72+ }
7573 columnMapping . Add ( new Pair < int > ( targetColumnIndex , columnIndex ) ) ;
7674 }
77- mappings [ i ] = new RecordPartMapping ( typeIdColumnIndex , columnMapping . ToArray ( ) , approximateType ) ;
7875 }
79- cacheItem = new CacheItem ( header , mappings ) ;
80- cache . Add ( cacheItem ) ;
76+ mappings [ i ] = new RecordPartMapping ( typeIdColumnIndex , columnMapping , approximateType ) ;
8177 }
78+ cacheItem = new CacheItem ( header , mappings ) ;
79+ cache . Add ( cacheItem ) ;
8280 }
8381 return source . Select ( tuple => ParseRow ( tuple , context , cacheItem . Mappings ) ) ;
8482 }
8583
86- private Record ParseRow ( Tuple tuple , MaterializationContext context , RecordPartMapping [ ] recordPartMappings )
87- {
88- var count = recordPartMappings . Length ;
89-
90- if ( count == 1 )
91- return new Record ( tuple , ParseColumnGroup ( tuple , context , 0 , recordPartMappings [ 0 ] ) ) ;
84+ private Record ParseRow ( Tuple tuple , MaterializationContext context , RecordPartMapping [ ] recordPartMappings ) =>
85+ recordPartMappings . Length == 1
86+ ? new Record ( tuple , ParseColumnGroup ( tuple , context , 0 , recordPartMappings [ 0 ] ) )
87+ : new Record ( tuple , recordPartMappings . Select (
88+ ( recordPartMapping , i ) => ParseColumnGroup ( tuple , context , i , recordPartMapping ) )
89+ ) ;
9290
93- var pairs = new List < Pair < Key , Tuple > > (
94- recordPartMappings
95- . Select ( ( recordPartMapping , i ) => ParseColumnGroup ( tuple , context , i , recordPartMapping ) ) ) ;
96- return new Record ( tuple , pairs ) ;
97- }
98-
99- private Pair < Key , Tuple > ParseColumnGroup ( Tuple tuple , MaterializationContext context , int groupIndex , RecordPartMapping mapping )
91+ private Pair < Key , Tuple > ParseColumnGroup ( Tuple tuple , MaterializationContext context , int groupIndex , in RecordPartMapping mapping )
10092 {
101- TypeReferenceAccuracy accuracy ;
102- int typeId = ExtractTypeId ( mapping . ApproximateType , context . TypeIdRegistry , tuple , mapping . TypeIdColumnIndex , out accuracy ) ;
103- var typeMapping = typeId == TypeInfo . NoTypeId ? null : context . GetTypeMapping ( groupIndex , mapping . ApproximateType , typeId , mapping . Columns ) ;
104- if ( typeMapping == null )
93+ int typeId = ExtractTypeId ( mapping . ApproximateType , context . TypeIdRegistry , tuple , mapping . TypeIdColumnIndex , out var accuracy ) ;
94+ if ( typeId == TypeInfo . NoTypeId ) {
10595 return new Pair < Key , Tuple > ( null , null ) ;
106-
107- bool canCache = accuracy == TypeReferenceAccuracy . ExactType ;
108- Key key ;
109- if ( typeMapping . KeyTransform . Descriptor . Count <= WellKnown . MaxGenericKeyLength )
110- key = KeyFactory . Materialize ( Domain , context . Session . StorageNodeId , typeMapping . Type , tuple , accuracy , canCache , typeMapping . KeyIndexes ) ;
111- else {
112- var keyTuple = typeMapping . KeyTransform . Apply ( TupleTransformType . TransformedTuple , tuple ) ;
113- key = KeyFactory . Materialize ( Domain , context . Session . StorageNodeId , typeMapping . Type , keyTuple , accuracy , canCache , null ) ;
11496 }
115- if ( accuracy == TypeReferenceAccuracy . ExactType ) {
116- var entityTuple = typeMapping . Transform . Apply ( TupleTransformType . Tuple , tuple ) ;
117- return new Pair < Key , Tuple > ( key , entityTuple ) ;
97+ var typeMapping = context . GetTypeMapping ( groupIndex , mapping . ApproximateType , typeId , mapping . Columns ) ;
98+
99+ bool canCache = accuracy == TypeReferenceAccuracy . ExactType ;
100+ var keyTuple = tuple ;
101+ var keyIndexes = typeMapping . KeyIndexes ;
102+ if ( typeMapping . KeyTransform . Descriptor . Count > WellKnown . MaxGenericKeyLength ) {
103+ keyTuple = typeMapping . KeyTransform . Apply ( TupleTransformType . TransformedTuple , tuple ) ;
104+ keyIndexes = null ;
118105 }
119- return new Pair < Key , Tuple > ( key , null ) ;
106+ var key = KeyFactory . Materialize ( Domain , context . Session . StorageNodeId , typeMapping . Type , keyTuple , accuracy , canCache , keyIndexes ) ;
107+ return new Pair < Key , Tuple > (
108+ key ,
109+ accuracy == TypeReferenceAccuracy . ExactType
110+ ? typeMapping . Transform . Apply ( TupleTransformType . Tuple , tuple )
111+ : null
112+ ) ;
120113 }
121114
122115 public static int ExtractTypeId ( TypeInfo type , TypeIdRegistry typeIdRegistry , Tuple tuple , int typeIdIndex , out TypeReferenceAccuracy accuracy )
@@ -146,8 +139,10 @@ public static int ExtractTypeId(TypeInfo type, TypeIdRegistry typeIdRegistry, Tu
146139 internal EntityDataReader ( Domain domain )
147140 : base ( domain )
148141 {
149- cache = new LruCache < RecordSetHeader , CacheItem > ( domain . Configuration . RecordSetMappingCacheSize ,
150- m => m . Header , new WeakestCache < RecordSetHeader , CacheItem > ( false , false , m => m . Header ) ) ;
142+ cache = new FastConcurrentLruCache < RecordSetHeader , CacheItem > (
143+ domain . Configuration . RecordSetMappingCacheSize ,
144+ m => m . Header
145+ ) ;
151146 }
152147 }
153- }
148+ }
0 commit comments