10
10
using System . Linq ;
11
11
using System . Threading ;
12
12
using Xtensive . Caching ;
13
- using Xtensive . Core ;
14
13
using KeyCache = Xtensive . Caching . ICache < Xtensive . Orm . Key , Xtensive . Orm . Key > ;
15
14
16
15
namespace Xtensive . Orm . Internals
@@ -22,33 +21,24 @@ public sealed class EntitySetState : TransactionalStateContainer<KeyCache>,
22
21
IEnumerable < Key > ,
23
22
IInvalidatable
24
23
{
25
- private class BackupedState
26
- {
27
- public bool IsLoaded { get ; private set ; }
28
- public long ? TotalItemCount { get ; private set ; }
29
- public IEnumerable < Key > AddedKeys { get ; private set ; }
30
- public IEnumerable < Key > RemovedKeys { get ; private set ; }
31
-
32
- public BackupedState ( EntitySetState state )
33
- {
34
- IsLoaded = state . IsLoaded ;
35
- TotalItemCount = state . TotalItemCount ;
36
- AddedKeys = state . addedKeys . Values . ToList ( ) ;
37
- RemovedKeys = state . removedKeys . Values . ToList ( ) ;
38
- }
39
- }
24
+ private readonly record struct BackedUpState
25
+ (
26
+ bool IsLoaded ,
27
+ long ? TotalItemCount ,
28
+ IEnumerable < Key > AddedKeys ,
29
+ IEnumerable < Key > RemovedKeys
30
+ ) ;
40
31
41
- private readonly EntitySetBase owner ;
42
32
private readonly bool isDisconnected ;
43
33
44
- private Guid lastManualPrefetchId ;
34
+ private Guid lastManualPrefetchId = Guid . Empty ;
45
35
private bool isLoaded ;
46
36
private long ? totalItemCount ;
47
- private int version ;
48
- private IDictionary < Key , Key > addedKeys ;
49
- private IDictionary < Key , Key > removedKeys ;
37
+ private volatile int version = int . MinValue ;
38
+ private HashSet < Key > addedKeys = new ( ) ;
39
+ private HashSet < Key > removedKeys = new ( ) ;
50
40
51
- private BackupedState previousState ;
41
+ private BackedUpState ? previousState ;
52
42
53
43
public KeyCache FetchedKeys
54
44
{
@@ -71,8 +61,7 @@ public long? TotalItemCount
71
61
/// <summary>
72
62
/// Gets the number of cached items.
73
63
/// </summary>
74
- public long CachedItemCount
75
- => FetchedItemsCount - RemovedItemsCount + AddedItemsCount ;
64
+ public long CachedItemCount => FetchedItemsCount - RemovedItemsCount + AddedItemsCount ;
76
65
77
66
/// <summary>
78
67
/// Gets the number of fetched keys.
@@ -138,16 +127,8 @@ public void Update(IEnumerable<Key> keys, long? count)
138
127
/// </summary>
139
128
/// <param name="key">The key.</param>
140
129
/// <returns>Check result.</returns>
141
- public bool Contains ( Key key )
142
- {
143
- if ( removedKeys . ContainsKey ( key ) ) {
144
- return false ;
145
- }
146
- if ( addedKeys . ContainsKey ( key ) ) {
147
- return true ;
148
- }
149
- return FetchedKeys . ContainsKey ( key ) ;
150
- }
130
+ public bool Contains ( Key key ) =>
131
+ ! removedKeys . Contains ( key ) && ( addedKeys . Contains ( key ) || FetchedKeys . ContainsKey ( key ) ) ;
151
132
152
133
/// <summary>
153
134
/// Registers the specified fetched key in cached state.
@@ -162,15 +143,13 @@ public bool Contains(Key key)
162
143
public void Add ( Key key )
163
144
{
164
145
if ( ! removedKeys . Remove ( key ) ) {
165
- addedKeys [ key ] = key ;
146
+ addedKeys . Add ( key ) ;
166
147
}
167
148
if ( TotalItemCount != null ) {
168
149
TotalItemCount ++ ;
169
150
}
170
151
171
- unchecked {
172
- _ = Interlocked . Add ( ref version , 1 ) ;
173
- }
152
+ _ = Interlocked . Increment ( ref version ) ;
174
153
Rebind ( ) ;
175
154
}
176
155
@@ -181,15 +160,13 @@ public void Add(Key key)
181
160
public void Remove ( Key key )
182
161
{
183
162
if ( ! addedKeys . Remove ( key ) ) {
184
- removedKeys [ key ] = key ;
163
+ removedKeys . Add ( key ) ;
185
164
}
186
165
if ( TotalItemCount != null ) {
187
166
TotalItemCount -- ;
188
167
}
189
168
190
- unchecked {
191
- _ = Interlocked . Add ( ref version , 1 ) ;
192
- }
169
+ _ = Interlocked . Increment ( ref version ) ;
193
170
Rebind ( ) ;
194
171
}
195
172
@@ -205,13 +182,13 @@ public bool ApplyChanges()
205
182
InitializeFetchedKeys ( ) ;
206
183
207
184
foreach ( var currentFetchedKey in currentFetchedKeys ) {
208
- if ( ! removedKeys . ContainsKey ( currentFetchedKey ) ) {
185
+ if ( ! removedKeys . Contains ( currentFetchedKey ) ) {
209
186
FetchedKeys . Add ( currentFetchedKey ) ;
210
187
}
211
188
}
212
189
213
190
foreach ( var addedKey in addedKeys ) {
214
- FetchedKeys . Add ( addedKey . Value ) ;
191
+ FetchedKeys . Add ( addedKey ) ;
215
192
}
216
193
InitializeDifferenceCollections ( ) ;
217
194
Rebind ( ) ;
@@ -226,17 +203,15 @@ public bool ApplyChanges()
226
203
public void CancelChanges ( )
227
204
{
228
205
InitializeDifferenceCollections ( ) ;
229
- unchecked {
230
- _ = Interlocked . Add ( ref version , 1 ) ;
231
- }
206
+ _ = Interlocked . Increment ( ref version ) ;
232
207
Rebind ( ) ;
233
208
}
234
209
235
210
internal void RollbackState ( )
236
211
{
237
- if ( previousState != null ) {
238
- TotalItemCount = previousState . TotalItemCount ;
239
- IsLoaded = previousState . IsLoaded ;
212
+ if ( previousState is { } prev ) {
213
+ TotalItemCount = prev . TotalItemCount ;
214
+ IsLoaded = prev . IsLoaded ;
240
215
var fetchedKeys = FetchedKeys ;
241
216
242
217
InitializeFetchedKeys ( ) ;
@@ -246,35 +221,26 @@ internal void RollbackState()
246
221
FetchedKeys . Add ( fetchedKey ) ;
247
222
}
248
223
249
- foreach ( var addedKey in previousState . AddedKeys ) {
224
+ foreach ( var addedKey in prev . AddedKeys ) {
250
225
if ( fetchedKeys . ContainsKey ( addedKey ) ) {
251
226
FetchedKeys . Remove ( addedKey ) ;
252
227
}
253
- addedKeys . Add ( addedKey , addedKey ) ;
228
+ addedKeys . Add ( addedKey ) ;
254
229
}
255
- foreach ( var removedKey in previousState . RemovedKeys ) {
230
+ foreach ( var removedKey in prev . RemovedKeys ) {
256
231
if ( ! FetchedKeys . ContainsKey ( removedKey ) ) {
257
232
FetchedKeys . Add ( removedKey ) ;
258
233
}
259
- removedKeys . Add ( removedKey , removedKey ) ;
234
+ removedKeys . Add ( removedKey ) ;
260
235
}
261
236
}
262
237
}
263
238
264
239
internal void RemapKeys ( KeyMapping mapping )
265
240
{
266
- var oldAddedKeys = addedKeys ;
267
- var oldRemovedKeys = removedKeys ;
268
- InitializeDifferenceCollections ( ) ;
269
-
270
- foreach ( var oldAddedKey in oldAddedKeys ) {
271
- var newKey = mapping . TryRemapKey ( oldAddedKey . Key ) ;
272
- addedKeys . Add ( newKey , newKey ) ;
273
- }
274
- foreach ( var oldRemovedKey in oldRemovedKeys ) {
275
- var newKey = mapping . TryRemapKey ( oldRemovedKey . Key ) ;
276
- removedKeys . Add ( newKey , newKey ) ;
277
- }
241
+ var remapper = mapping . TryRemapKey ;
242
+ addedKeys = addedKeys . Select ( remapper ) . ToHashSet ( ) ;
243
+ removedKeys = removedKeys . Select ( remapper ) . ToHashSet ( ) ;
278
244
}
279
245
280
246
internal bool ShouldUseForcePrefetch ( Guid ? currentPrefetchOperation )
@@ -299,11 +265,7 @@ internal bool ShouldUseForcePrefetch(Guid? currentPrefetchOperation)
299
265
}
300
266
}
301
267
302
- if ( isDisconnected ) {
303
- return true ;
304
- }
305
-
306
- return false ;
268
+ return isDisconnected ;
307
269
}
308
270
309
271
internal void SetLastManualPrefetchId ( Guid ? prefetchOperationId )
@@ -343,7 +305,7 @@ public IEnumerator<Key> GetEnumerator()
343
305
}
344
306
345
307
var fetchedKey = fetchedKeysEnumerator . Current ;
346
- if ( ! removedKeys . ContainsKey ( fetchedKey ) ) {
308
+ if ( ! removedKeys . Contains ( fetchedKey ) ) {
347
309
yield return fetchedKey ;
348
310
}
349
311
}
@@ -359,17 +321,13 @@ public IEnumerator<Key> GetEnumerator()
359
321
break ;
360
322
}
361
323
362
- var addedKey = addedKeysEnumerator . Current ;
363
- yield return addedKey . Value ;
324
+ yield return addedKeysEnumerator . Current ;
364
325
}
365
326
}
366
327
}
367
328
368
329
/// <inheritdoc/>
369
- IEnumerator IEnumerable . GetEnumerator ( )
370
- {
371
- return GetEnumerator ( ) ;
372
- }
330
+ IEnumerator IEnumerable . GetEnumerator ( ) => GetEnumerator ( ) ;
373
331
374
332
#endregion
375
333
@@ -386,16 +344,14 @@ private void UpdateSyncedState(IEnumerable<Key> keys, long? count)
386
344
public void UpdateCachedState ( IEnumerable < Key > syncronizedKeys , long ? count )
387
345
{
388
346
FetchedKeys . Clear ( ) ;
389
- var becameRemovedOnSever = new HashSet < Key > ( removedKeys . Keys ) ;
347
+ HashSet < Key > becameRemovedOnSever = new ( removedKeys ) ;
390
348
foreach ( var key in syncronizedKeys ) {
391
349
if ( ! addedKeys . Remove ( key ) ) {
392
350
_ = becameRemovedOnSever . Remove ( key ) ;
393
351
}
394
352
FetchedKeys . Add ( key ) ;
395
353
}
396
- foreach ( var removedOnServer in becameRemovedOnSever ) {
397
- _ = removedKeys . Remove ( removedOnServer ) ;
398
- }
354
+ removedKeys . ExceptWith ( becameRemovedOnSever ) ;
399
355
400
356
TotalItemCount = count . HasValue
401
357
? FetchedKeys . Count - removedKeys . Count + AddedItemsCount
@@ -409,15 +365,16 @@ private void EnsureFetchedKeysIsNotNull()
409
365
}
410
366
}
411
367
412
- private void BackupState ( ) => previousState = new BackupedState ( this ) ;
368
+ private void BackupState ( ) =>
369
+ previousState = new ( IsLoaded , TotalItemCount , addedKeys . ToArray ( ) , removedKeys . ToArray ( ) ) ;
413
370
414
371
private void InitializeFetchedKeys ( )
415
372
=> FetchedKeys = new LruCache < Key , Key > ( WellKnown . EntitySetCacheSize , cachedKey => cachedKey ) ;
416
373
417
374
private void InitializeDifferenceCollections ( )
418
375
{
419
- addedKeys = new Dictionary < Key , Key > ( ) ;
420
- removedKeys = new Dictionary < Key , Key > ( ) ;
376
+ addedKeys = new ( ) ;
377
+ removedKeys = new ( ) ;
421
378
}
422
379
423
380
// Constructors
@@ -426,11 +383,7 @@ internal EntitySetState(EntitySetBase entitySet)
426
383
: base ( entitySet . Session )
427
384
{
428
385
InitializeFetchedKeys ( ) ;
429
- InitializeDifferenceCollections ( ) ;
430
- owner = entitySet ;
431
- version = int . MinValue ;
432
386
isDisconnected = entitySet . Session . IsDisconnected ;
433
- lastManualPrefetchId = Guid . Empty ;
434
387
}
435
388
}
436
- }
389
+ }
0 commit comments