@@ -41,6 +41,7 @@ protected override void Configure(Configuration configuration)
41
41
{
42
42
configuration . SetProperty ( Environment . UseSecondLevelCache , "true" ) ;
43
43
configuration . SetProperty ( Environment . UseQueryCache , "true" ) ;
44
+ configuration . SetProperty ( Environment . GenerateStatistics , "true" ) ;
44
45
configuration . SetProperty ( Environment . CacheProvider , typeof ( BatchableCacheProvider ) . AssemblyQualifiedName ) ;
45
46
}
46
47
@@ -706,14 +707,7 @@ public async Task QueryCacheTestAsync()
706
707
if ( ! Sfi . ConnectionProvider . Driver . SupportsMultipleQueries )
707
708
Assert . Ignore ( $ "{ Sfi . ConnectionProvider . Driver } does not support multiple queries") ;
708
709
709
- var queryCache = Sfi . GetQueryCache ( null ) ;
710
- var field = typeof ( StandardQueryCache ) . GetField (
711
- "_cache" ,
712
- BindingFlags . NonPublic | BindingFlags . Instance ) ;
713
- Assert . That ( field , Is . Not . Null , "Unable to find _cache field" ) ;
714
- var cache = ( BatchableCache ) field . GetValue ( queryCache ) ;
715
- Assert . That ( cache , Is . Not . Null , "_cache is null" ) ;
716
-
710
+ var cache = GetDefaultQueryCache ( ) ;
717
711
var timestamp = Sfi . UpdateTimestampsCache ;
718
712
var tsField = typeof ( UpdateTimestampsCache ) . GetField (
719
713
"_updateTimestamps" ,
@@ -870,6 +864,218 @@ public async Task QueryCacheTestAsync()
870
864
}
871
865
}
872
866
867
+ [ TestCase ( true ) ]
868
+ [ TestCase ( false ) ]
869
+ public async Task QueryEntityBatchCacheTestAsync ( bool clearEntityCacheAfterQuery , CancellationToken cancellationToken = default ( CancellationToken ) )
870
+ {
871
+ var persister = Sfi . GetEntityPersister ( typeof ( ReadOnlyItem ) . FullName ) ;
872
+ var cache = ( BatchableCache ) persister . Cache . Cache ;
873
+ var queryCache = GetDefaultQueryCache ( ) ;
874
+
875
+ Sfi . Statistics . Clear ( ) ;
876
+ await ( Sfi . EvictQueriesAsync ( cancellationToken ) ) ;
877
+ cache . ClearStatistics ( ) ;
878
+ queryCache . ClearStatistics ( ) ;
879
+
880
+ List < ReadOnlyItem > items ;
881
+
882
+ using ( var s = OpenSession ( ) )
883
+ using ( var tx = s . BeginTransaction ( ) )
884
+ {
885
+ items = await ( s . Query < ReadOnlyItem > ( )
886
+ . WithOptions ( o => o . SetCacheable ( true ) )
887
+ . ToListAsync ( cancellationToken ) ) ;
888
+
889
+ await ( tx . CommitAsync ( cancellationToken ) ) ;
890
+ }
891
+
892
+ Assert . That ( queryCache . GetCalls , Has . Count . EqualTo ( 1 ) , "Unexpected query cache GetCalls" ) ;
893
+ Assert . That ( queryCache . PutCalls , Has . Count . EqualTo ( 1 ) , "Unexpected query cache PutCalls" ) ;
894
+ Assert . That ( cache . PutMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected entity cache PutMultipleCalls" ) ;
895
+ Assert . That ( cache . GetMultipleCalls , Has . Count . EqualTo ( 0 ) , "Unexpected entity cache GetMultipleCalls" ) ;
896
+ Assert . That ( items , Has . Count . EqualTo ( 36 ) , "Unexpected items count" ) ;
897
+ Assert . That ( Sfi . Statistics . QueryExecutionCount , Is . EqualTo ( 1 ) , "Unexpected execution count" ) ;
898
+ Assert . That ( Sfi . Statistics . QueryCachePutCount , Is . EqualTo ( 1 ) , "Unexpected cache put count" ) ;
899
+ Assert . That ( Sfi . Statistics . QueryCacheMissCount , Is . EqualTo ( 1 ) , "Unexpected cache miss count" ) ;
900
+
901
+ cache . ClearStatistics ( ) ;
902
+ queryCache . ClearStatistics ( ) ;
903
+
904
+ if ( clearEntityCacheAfterQuery )
905
+ {
906
+ await ( cache . ClearAsync ( cancellationToken ) ) ;
907
+ }
908
+
909
+ Sfi . Statistics . Clear ( ) ;
910
+
911
+ using ( var s = OpenSession ( ) )
912
+ using ( var tx = s . BeginTransaction ( ) )
913
+ {
914
+ items = await ( s . Query < ReadOnlyItem > ( )
915
+ . WithOptions ( o => o . SetCacheable ( true ) )
916
+ . ToListAsync ( cancellationToken ) ) ;
917
+
918
+ await ( tx . CommitAsync ( cancellationToken ) ) ;
919
+ }
920
+
921
+ Assert . That ( queryCache . GetCalls , Has . Count . EqualTo ( 1 ) , "Unexpected query cache GetCalls" ) ;
922
+ Assert . That ( queryCache . PutCalls , Has . Count . EqualTo ( 0 ) , "Unexpected query cache PutCalls" ) ;
923
+ // Ideally the PutMultipleCalls count should be 1 when clearing the cache after the first query, in order to achieve this
924
+ // the CacheBatcher would need to be on the session and executed once the query is processed
925
+ Assert . That ( cache . PutMultipleCalls , Has . Count . EqualTo ( clearEntityCacheAfterQuery ? 9 : 0 ) , "Unexpected entity cache PutMultipleCalls" ) ;
926
+ Assert . That ( cache . GetMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected entity cache GetMultipleCalls" ) ;
927
+ Assert . That ( items , Has . Count . EqualTo ( 36 ) ) ;
928
+ Assert . That ( Sfi . Statistics . QueryExecutionCount , Is . EqualTo ( 0 ) , "Unexpected execution count" ) ;
929
+ Assert . That ( Sfi . Statistics . QueryCachePutCount , Is . EqualTo ( 0 ) , "Unexpected cache put count" ) ;
930
+ Assert . That ( Sfi . Statistics . QueryCacheMissCount , Is . EqualTo ( 0 ) , "Unexpected cache miss count" ) ;
931
+ Assert . That ( Sfi . Statistics . QueryCacheHitCount , Is . EqualTo ( 1 ) , "Unexpected cache hit count" ) ;
932
+ }
933
+
934
+ [ TestCase ( true , false ) ]
935
+ [ TestCase ( false , false ) ]
936
+ [ TestCase ( true , true ) ]
937
+ [ TestCase ( false , true ) ]
938
+ public async Task QueryFetchCollectionBatchCacheTestAsync ( bool clearEntityCacheAfterQuery , bool future , CancellationToken cancellationToken = default ( CancellationToken ) )
939
+ {
940
+ if ( future && ! Sfi . ConnectionProvider . Driver . SupportsMultipleQueries )
941
+ {
942
+ Assert . Ignore ( $ "{ Sfi . ConnectionProvider . Driver } does not support multiple queries") ;
943
+ }
944
+
945
+ var persister = Sfi . GetEntityPersister ( typeof ( ReadOnly ) . FullName ) ;
946
+ var itemPersister = Sfi . GetEntityPersister ( typeof ( ReadOnlyItem ) . FullName ) ;
947
+ var collectionPersister = Sfi . GetCollectionPersister ( $ "{ typeof ( ReadOnly ) . FullName } .Items") ;
948
+ var cache = ( BatchableCache ) persister . Cache . Cache ;
949
+ var itemCache = ( BatchableCache ) itemPersister . Cache . Cache ;
950
+ var collectionCache = ( BatchableCache ) collectionPersister . Cache . Cache ;
951
+ var queryCache = GetDefaultQueryCache ( ) ;
952
+
953
+ int middleId ;
954
+
955
+ using ( var s = OpenSession ( ) )
956
+ {
957
+ var ids = await ( s . Query < ReadOnly > ( ) . Select ( o => o . Id ) . OrderBy ( o => o ) . ToListAsync ( cancellationToken ) ) ;
958
+ middleId = ids [ 2 ] ;
959
+ }
960
+
961
+ Sfi . Statistics . Clear ( ) ;
962
+ await ( Sfi . EvictQueriesAsync ( cancellationToken ) ) ;
963
+ queryCache . ClearStatistics ( ) ;
964
+ cache . ClearStatistics ( ) ;
965
+ await ( cache . ClearAsync ( cancellationToken ) ) ;
966
+ itemCache . ClearStatistics ( ) ;
967
+ await ( itemCache . ClearAsync ( cancellationToken ) ) ;
968
+ collectionCache . ClearStatistics ( ) ;
969
+ await ( collectionCache . ClearAsync ( cancellationToken ) ) ;
970
+
971
+ List < ReadOnly > items ;
972
+ using ( var s = OpenSession ( ) )
973
+ using ( var tx = s . BeginTransaction ( ) )
974
+ {
975
+ if ( future )
976
+ {
977
+ s . Query < ReadOnly > ( )
978
+ . WithOptions ( o => o . SetCacheable ( true ) )
979
+ . FetchMany ( o => o . Items )
980
+ . Where ( o => o . Id > middleId )
981
+ . ToFuture ( ) ;
982
+
983
+ items = s . Query < ReadOnly > ( )
984
+ . WithOptions ( o => o . SetCacheable ( true ) )
985
+ . FetchMany ( o => o . Items )
986
+ . Where ( o => o . Id <= middleId )
987
+ . ToFuture ( )
988
+ . ToList ( ) ;
989
+ }
990
+ else
991
+ {
992
+ items = await ( s . Query < ReadOnly > ( )
993
+ . WithOptions ( o => o . SetCacheable ( true ) )
994
+ . FetchMany ( o => o . Items )
995
+ . ToListAsync ( cancellationToken ) ) ;
996
+ }
997
+
998
+ await ( tx . CommitAsync ( cancellationToken ) ) ;
999
+ }
1000
+
1001
+ Assert . That ( queryCache . GetCalls , Has . Count . EqualTo ( future ? 0 : 1 ) , "Unexpected query cache GetCalls" ) ;
1002
+ Assert . That ( queryCache . GetMultipleCalls , Has . Count . EqualTo ( future ? 1 : 0 ) , "Unexpected query cache GetMultipleCalls" ) ;
1003
+ Assert . That ( queryCache . PutCalls , Has . Count . EqualTo ( future ? 0 : 1 ) , "Unexpected query cache PutCalls" ) ;
1004
+ Assert . That ( queryCache . PutMultipleCalls , Has . Count . EqualTo ( future ? 1 : 0 ) , "Unexpected query cache PutMultipleCalls" ) ;
1005
+ Assert . That ( cache . PutMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected entity cache PutMultipleCalls" ) ;
1006
+ Assert . That ( cache . GetMultipleCalls , Has . Count . EqualTo ( 0 ) , "Unexpected entity cache GetMultipleCalls" ) ;
1007
+ Assert . That ( collectionCache . PutMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected collection cache PutMultipleCalls" ) ;
1008
+ Assert . That ( collectionCache . GetMultipleCalls , Has . Count . EqualTo ( 0 ) , "Unexpected collection cache GetMultipleCalls" ) ;
1009
+ Assert . That ( items , Has . Count . EqualTo ( future ? 3 : 6 ) , "Unexpected items count" ) ;
1010
+ Assert . That ( Sfi . Statistics . QueryExecutionCount , Is . EqualTo ( 1 ) , "Unexpected execution count" ) ;
1011
+ Assert . That ( Sfi . Statistics . QueryCachePutCount , Is . EqualTo ( future ? 2 : 1 ) , "Unexpected cache put count" ) ;
1012
+ Assert . That ( Sfi . Statistics . QueryCacheMissCount , Is . EqualTo ( future ? 2 : 1 ) , "Unexpected cache miss count" ) ;
1013
+
1014
+ cache . ClearStatistics ( ) ;
1015
+ itemCache . ClearStatistics ( ) ;
1016
+ collectionCache . ClearStatistics ( ) ;
1017
+ queryCache . ClearStatistics ( ) ;
1018
+
1019
+ if ( clearEntityCacheAfterQuery )
1020
+ {
1021
+ await ( cache . ClearAsync ( cancellationToken ) ) ;
1022
+ await ( collectionCache . ClearAsync ( cancellationToken ) ) ;
1023
+ await ( itemCache . ClearAsync ( cancellationToken ) ) ;
1024
+ }
1025
+
1026
+ Sfi . Statistics . Clear ( ) ;
1027
+
1028
+ using ( var s = OpenSession ( ) )
1029
+ using ( var tx = s . BeginTransaction ( ) )
1030
+ {
1031
+ if ( future )
1032
+ {
1033
+ s . Query < ReadOnly > ( )
1034
+ . WithOptions ( o => o . SetCacheable ( true ) )
1035
+ . FetchMany ( o => o . Items )
1036
+ . Where ( o => o . Id > middleId )
1037
+ . ToFuture ( ) ;
1038
+
1039
+ items = s . Query < ReadOnly > ( )
1040
+ . WithOptions ( o => o . SetCacheable ( true ) )
1041
+ . FetchMany ( o => o . Items )
1042
+ . Where ( o => o . Id <= middleId )
1043
+ . ToFuture ( )
1044
+ . ToList ( ) ;
1045
+ }
1046
+ else
1047
+ {
1048
+ items = await ( s . Query < ReadOnly > ( )
1049
+ . WithOptions ( o => o . SetCacheable ( true ) )
1050
+ . FetchMany ( o => o . Items )
1051
+ . ToListAsync ( cancellationToken ) ) ;
1052
+ }
1053
+
1054
+ await ( tx . CommitAsync ( cancellationToken ) ) ;
1055
+ }
1056
+
1057
+ Assert . That ( queryCache . GetCalls , Has . Count . EqualTo ( future ? 0 : 1 ) , "Unexpected query cache GetCalls" ) ;
1058
+ Assert . That ( queryCache . GetMultipleCalls , Has . Count . EqualTo ( future ? 1 : 0 ) , "Unexpected query cache GetCalls" ) ;
1059
+ Assert . That ( queryCache . PutCalls , Has . Count . EqualTo ( 0 ) , "Unexpected query cache PutCalls" ) ;
1060
+ Assert . That ( queryCache . PutMultipleCalls , Has . Count . EqualTo ( 0 ) , "Unexpected query cache PutMultipleCalls" ) ;
1061
+ Assert . That ( collectionCache . GetMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected collection cache GetMultipleCalls" ) ;
1062
+ Assert . That ( collectionCache . GetMultipleCalls [ 0 ] , Has . Length . EqualTo ( 6 ) , "Unexpected collection cache GetMultipleCalls length" ) ;
1063
+ Assert . That ( cache . GetMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected entity cache GetMultipleCalls" ) ;
1064
+ Assert . That ( cache . GetMultipleCalls [ 0 ] , Has . Length . EqualTo ( 6 ) , "Unexpected entity cache GetMultipleCalls length" ) ;
1065
+ Assert . That ( itemCache . GetMultipleCalls , Has . Count . EqualTo ( 1 ) , "Unexpected entity item cache GetMultipleCalls" ) ;
1066
+ Assert . That ( itemCache . GetMultipleCalls [ 0 ] , Has . Length . EqualTo ( 36 ) , "Unexpected entity item cache GetMultipleCalls length" ) ;
1067
+ // Ideally the PutMultipleCalls count should be 1 when clearing the cache after the first query, in order to achieve this
1068
+ // the CacheBatcher would need to be on the session and executed once the batch fetch queries are processed
1069
+ Assert . That ( cache . PutMultipleCalls , Has . Count . EqualTo ( clearEntityCacheAfterQuery ? 2 : 0 ) , "Unexpected entity cache PutMultipleCalls" ) ;
1070
+ Assert . That ( collectionCache . PutMultipleCalls , Has . Count . EqualTo ( clearEntityCacheAfterQuery ? 2 : 0 ) , "Unexpected collection cache PutMultipleCalls" ) ;
1071
+ Assert . That ( itemCache . PutMultipleCalls , Has . Count . EqualTo ( clearEntityCacheAfterQuery ? 9 : 0 ) , "Unexpected entity item cache PutMultipleCalls" ) ;
1072
+ Assert . That ( items , Has . Count . EqualTo ( future ? 3 : 6 ) ) ;
1073
+ Assert . That ( Sfi . Statistics . QueryExecutionCount , Is . EqualTo ( 0 ) , "Unexpected execution count" ) ;
1074
+ Assert . That ( Sfi . Statistics . QueryCachePutCount , Is . EqualTo ( 0 ) , "Unexpected cache put count" ) ;
1075
+ Assert . That ( Sfi . Statistics . QueryCacheMissCount , Is . EqualTo ( 0 ) , "Unexpected cache miss count" ) ;
1076
+ Assert . That ( Sfi . Statistics . QueryCacheHitCount , Is . EqualTo ( future ? 2 : 1 ) , "Unexpected cache hit count" ) ;
1077
+ }
1078
+
873
1079
private async Task AssertMultipleCacheCallsAsync < TEntity > ( IEnumerable < int > loadIds , IReadOnlyList < int > getIds , int idIndex ,
874
1080
int [ ] [ ] fetchedIdIndexes , int [ ] putIdIndexes , Func < int , bool > cacheBeforeLoadFn = null , CancellationToken cancellationToken = default ( CancellationToken ) )
875
1081
where TEntity : CacheEntity
@@ -996,5 +1202,18 @@ private void AssertEquivalent(List<int> ids, int[][] expectedIdIndexes, List<obj
996
1202
}
997
1203
}
998
1204
1205
+ private BatchableCache GetDefaultQueryCache ( )
1206
+ {
1207
+ var queryCache = Sfi . GetQueryCache ( null ) ;
1208
+ var field = typeof ( StandardQueryCache ) . GetField (
1209
+ "_cache" ,
1210
+ BindingFlags . NonPublic | BindingFlags . Instance ) ;
1211
+ Assert . That ( field , Is . Not . Null , "Unable to find _cache field" ) ;
1212
+ var cache = ( BatchableCache ) field . GetValue ( queryCache ) ;
1213
+ Assert . That ( cache , Is . Not . Null , "_cache is null" ) ;
1214
+
1215
+ return cache ;
1216
+ }
1217
+
999
1218
}
1000
1219
}
0 commit comments