9
9
using Microsoft . Extensions . Logging ;
10
10
using System ;
11
11
using System . Collections . Generic ;
12
+ using System . Diagnostics ;
12
13
using System . Linq ;
13
14
using System . Threading ;
14
15
using System . Threading . Tasks ;
@@ -48,7 +49,7 @@ public class CacheEntry<TE> where TE : T
48
49
49
50
private const ushort MaxTimeToLiveInSeconds = 600 ;
50
51
private const ushort MaxTrimCountPerRecycle = 256 ;
51
-
52
+
52
53
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim ( 1 , 1 ) ;
53
54
private readonly Dictionary < string , CacheEntry < T > > _entries = new Dictionary < string , CacheEntry < T > > ( ) ;
54
55
private readonly string _name ;
@@ -81,11 +82,11 @@ protected AmqpEntityCache(string name, uint capacity, ushort timeToLiveInSeconds
81
82
throw new ArgumentOutOfRangeException ( nameof ( timeToLiveInSeconds ) , $ "Argument cannot exceed { MaxTimeToLiveInSeconds } .") ;
82
83
if ( maxTrimCountPerRecycle > MaxTrimCountPerRecycle )
83
84
throw new ArgumentOutOfRangeException ( nameof ( maxTrimCountPerRecycle ) , $ "Argument cannot exceed { MaxTrimCountPerRecycle } .") ;
84
-
85
+
85
86
_name = name ;
86
- Capacity = capacity ;
87
- _timeToLiveInSeconds = timeToLiveInSeconds ;
88
- _maxTrimCountPerRecycle = maxTrimCountPerRecycle ;
87
+ Capacity = capacity ;
88
+ _timeToLiveInSeconds = timeToLiveInSeconds ;
89
+ _maxTrimCountPerRecycle = maxTrimCountPerRecycle ;
89
90
}
90
91
91
92
/// <summary>
@@ -108,16 +109,22 @@ public async Task<T> CreateAsync(ILogger logger, string path)
108
109
if ( _shutdownPending ) return null ;
109
110
110
111
CacheEntry < T > entry ;
112
+ Stopwatch stopwatch = new Stopwatch ( ) ;
113
+ stopwatch . Start ( ) ;
114
+
115
+ logger . LogInformation ( "Start-TrimEntriesAsync" ) ;
111
116
await TrimEntriesAsync ( logger ) . ConfigureAwait ( false ) ; // see if we need to trim entries
117
+ logger . LogInformation ( $ "End-TrimEntriesAsync: Execution time: { stopwatch . ElapsedMilliseconds } ") ;
118
+
119
+ stopwatch . Restart ( ) ;
120
+ logger . LogInformation ( "Start-AddCacheEntries" ) ;
112
121
await _semaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
113
122
try
114
123
{
115
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "Start-MessagingEntityCache::Create: Create entry for {Path}" , path ) ;
116
124
// create an entry if it doesn't exist
117
125
if ( _entries . ContainsKey ( path ) == false )
118
126
{
119
127
// create a new record for this entity
120
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache::Create: Creating entry for {Path}" , path ) ;
121
128
entry = new CacheEntry < T > ( )
122
129
{
123
130
ActiveCount = 1 ,
@@ -127,28 +134,27 @@ public async Task<T> CreateAsync(ILogger logger, string path)
127
134
} ;
128
135
_entries . Add ( path , entry ) ;
129
136
130
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "End-MessagingEntityCache::Create: Create entry for {Path}. ActiveCount={ActiveCount} CacheEntryCount={CacheEntryCount}" , path , entry . ActiveCount , _entries . Count ) ;
131
137
return entry . Entity ;
132
138
}
133
139
134
140
entry = _entries [ path ] ;
135
141
136
- if ( _incrementActiveCount )
142
+ if ( _incrementActiveCount )
137
143
entry . ActiveCount ++ ;
138
144
entry . LastUsed = DateTime . UtcNow ;
139
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , $ "MessagingEntityCache::Create: Updating entry for { path } ActiveCount={ entry . ActiveCount } ") ;
140
145
141
146
// if this entity previously was closed, we need to create a new instance
142
147
if ( entry . Entity is { IsClosed : false } ) return entry . Entity ;
143
148
144
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache::Create: Creating new entity for {Path} ActiveCount={ActiveCount}" , path , entry . ActiveCount ) ;
145
149
entry . Entity = await CreateEntityAsync ( logger , path ) . ConfigureAwait ( false ) ;
146
150
}
147
151
finally
148
152
{
149
153
_semaphore . Release ( ) ;
150
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "End-MessagingEntityCache::Create: Create entry for {Path}" , path ) ;
151
154
}
155
+
156
+ logger . LogInformation ( $ "End-AddCacheEntries: Execution time: { stopwatch . ElapsedMilliseconds } ") ;
157
+ stopwatch . Stop ( ) ;
152
158
return entry . Entity ;
153
159
}
154
160
@@ -165,21 +171,16 @@ public async Task ReleaseAsync(ILogger logger, string path)
165
171
await _semaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
166
172
try
167
173
{
168
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "Start-MessagingEntityCache::Release: Path={Path}" , path ) ;
169
-
170
174
if ( _entries . TryGetValue ( path , out CacheEntry < T > entry ) == false )
171
175
{
172
176
return ;
173
177
}
174
178
// under normal conditions, we just decrease the active count
175
- if ( entry . ActiveCount > 0 )
179
+ if ( entry . ActiveCount > 0 )
176
180
entry . ActiveCount -- ;
177
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache::Release: Releasing entry for Path={Path} ActiveCount={ActiveCount}" , path , entry . ActiveCount ) ;
178
181
}
179
182
finally
180
183
{
181
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "End-MessagingEntityCache::Release: Path={Path}" , path ) ;
182
-
183
184
_semaphore . Release ( ) ;
184
185
}
185
186
}
@@ -191,8 +192,6 @@ private static async Task CloseEntityAsync(ILogger logger, CacheEntry<T> entry,
191
192
{
192
193
try
193
194
{
194
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "Start-MessagingEntityCache::CloseEntity: Path={Path} ActiveCount={ActiveCount}" , path , entry . ActiveCount ) ;
195
-
196
195
await entry . Entity . CloseAsync ( ) . ConfigureAwait ( false ) ;
197
196
}
198
197
catch ( Exception ex )
@@ -204,7 +203,6 @@ private static async Task CloseEntityAsync(ILogger logger, CacheEntry<T> entry,
204
203
// Even if we get an exception when we close the Link or Session we need to null the entity or we
205
204
// will end up in an unsynchronized state where we reuse the entity.
206
205
entry . Entity = null ;
207
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "End-MessagingEntityCache::CloseEntity: Path={Path} ActiveCount={ActiveCount}" , path , entry . ActiveCount ) ;
208
206
}
209
207
}
210
208
}
@@ -215,7 +213,8 @@ public async Task ShutdownAsync(ILogger logger)
215
213
{
216
214
_shutdownPending = true ;
217
215
await _semaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
218
- try {
216
+ try
217
+ {
219
218
logger . LogInformation ( EventIds . MessagingEntityCacheProcessor , "Shutting down: {CacheName}" , _name ) ;
220
219
221
220
foreach ( var key in _entries . Keys )
@@ -235,34 +234,27 @@ private async Task TrimEntriesAsync(ILogger logger)
235
234
await _semaphore . WaitAsync ( ) . ConfigureAwait ( false ) ;
236
235
try
237
236
{
238
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache: Start-TrimEntries CacheCapacity={CacheCapacity} CacheEntryCount={CacheEntryCount}" , Capacity , _entries . Keys . Count ) ;
239
-
240
237
// we haven't reached our max capacity yet
241
238
if ( _entries . Keys . Count <= Capacity ) return ;
242
239
243
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache: Trimming entries" ) ;
244
240
var count = ( int ) Math . Min ( _entries . Keys . Count - Capacity , _maxTrimCountPerRecycle ) ;
245
-
241
+
246
242
// get the oldest n entries
247
243
var removal = ( from v in _entries . Values
248
- orderby v . LastUsed ascending
249
- where v . Entity != null
250
- && v . Entity . IsClosed == false
251
- && v . LastUsed < DateTime . UtcNow . AddSeconds ( - _timeToLiveInSeconds )
252
- && v . ActiveCount == 0
253
- select v ) . Take ( count ) . ToList ( ) ;
244
+ orderby v . LastUsed ascending
245
+ where v . Entity != null
246
+ && v . Entity . IsClosed == false
247
+ && v . LastUsed < DateTime . UtcNow . AddSeconds ( - _timeToLiveInSeconds )
248
+ && v . ActiveCount == 0
249
+ select v ) . Take ( count ) . ToList ( ) ;
254
250
255
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache: Trimming entries ActualRemovalCount={ActualRemovalCount} RemovalCount={ProposedRemovalCount} CacheCapacity={CacheCapacity} CacheEntryCount={CacheEntryCount}" , removal . Count ( ) , count , Capacity , _entries . Keys . Count ) ;
256
-
257
251
foreach ( var item in removal )
258
252
{
259
253
await CloseEntityAsync ( logger , item , item . Path ) . ConfigureAwait ( false ) ;
260
254
}
261
255
}
262
256
finally
263
257
{
264
- logger . LogDebug ( EventIds . MessagingEntityCacheProcessor , "MessagingEntityCache: End-TrimEntries CacheCapacity={CacheCapacity} CacheEntryCount={CacheEntryCount}" , Capacity , _entries . Keys . Count ) ;
265
-
266
258
_semaphore . Release ( ) ;
267
259
}
268
260
}
0 commit comments