@@ -127,32 +127,30 @@ private bool DetachAndReattachReadCacheChain(ref Key key, ref OperationStackCont
127
127
goto Success ;
128
128
129
129
// Traverse from highestRcAddress to the splice point, invalidating any record matching the key.
130
- for ( bool found = false ; /* tested in loop */ ; /* incremented in loop */ )
130
+ for ( bool foundKey = false ; /* tested in loop */ ; /* incremented in loop */ )
131
131
{
132
132
var physicalAddress = readcache . GetPhysicalAddress ( AbsoluteAddress ( lowestRcAddress ) ) ;
133
133
ref RecordInfo recordInfo = ref readcache . GetInfo ( physicalAddress ) ;
134
- if ( ! found && ! recordInfo . Invalid && comparer . Equals ( ref key , ref readcache . GetKey ( physicalAddress ) ) )
134
+ if ( ! foundKey && ! recordInfo . Invalid && comparer . Equals ( ref key , ref readcache . GetKey ( physicalAddress ) ) )
135
135
{
136
- found = true ;
136
+ foundKey = true ;
137
137
recordInfo . SetInvalidAtomic ( ) ; // Atomic needed due to other threads (e.g. ReadCacheEvict) possibly being in this chain before we detached it.
138
138
}
139
139
140
140
// See if we're at the last entry in the readcache prefix.
141
141
if ( ! IsReadCache ( recordInfo . PreviousAddress ) || AbsoluteAddress ( recordInfo . PreviousAddress ) < readcache . HeadAddress )
142
142
{
143
143
// Splice the new recordInfo into the local chain. Use atomic due to other threads (e.g. ReadCacheEvict) possibly being in this
144
- // before we detached it, and setting the record to Invalid (no other thread will be updating anything else in the chain, though).
144
+ // before we detached it, and setting the record to Invalid (no other thread will be updating anything else in the chain, though;
145
+ // we own the chain by virtue of the CAS above, and nobody else can change recordInfo.PreviousAddress).
145
146
while ( ! recordInfo . TryUpdateAddress ( recordInfo . PreviousAddress , newLogicalAddress ) )
146
147
Thread . Yield ( ) ;
147
148
148
- // Now try to CAS the chain into the HashBucketEntry. If it fails, give up; we lose those readcache records.
149
- // Trying to handle conflicts would require evaluating whether other threads had inserted keys in our chain, and it's too rare to worry about.
150
- if ( stackCtx . hei . TryCAS ( highestRcAddress ) )
151
- {
152
- // If we go below readcache.HeadAddress ReadCacheEvict may race past us, so make sure the lowest address is still in range.
153
- while ( lowestRcAddress < readcache . HeadAddress )
154
- lowestRcAddress = ReadCacheEvictChain ( readcache . HeadAddress , ref stackCtx . hei ) ;
155
- }
149
+ // Now try to CAS the chain into the HashBucketEntry. Ignore the result; if it fails, we just lose these readcache records.
150
+ // Conflict handling would require evaluating whether other threads had inserted keys in our chain, and it's too rare to worry about.
151
+ // We have ensured all records in this readcache prefix chain are >= readcache.HeadAddress, so even if readcache.HeadAddress changes,
152
+ // ReadCacheEvict will not be called for any records in this readcache prefix chain until we return from here and release the epoch.
153
+ stackCtx . hei . TryCAS ( highestRcAddress ) ;
156
154
goto Success ;
157
155
}
158
156
lowestRcAddress = recordInfo . PreviousAddress ;
@@ -347,14 +345,13 @@ internal void ReadCacheEvict(long rcLogicalAddress, long rcToLogicalAddress)
347
345
}
348
346
}
349
347
350
- private long ReadCacheEvictChain ( long rcToLogicalAddress , ref HashEntryInfo hei )
348
+ private void ReadCacheEvictChain ( long rcToLogicalAddress , ref HashEntryInfo hei )
351
349
{
352
350
// Traverse the chain of readcache entries for this key, looking "ahead" to .PreviousAddress to see if it is less than readcache.HeadAddress.
353
351
// nextPhysicalAddress remains Constants.kInvalidAddress if hei.Address is < HeadAddress; othrwise, it is the lowest-address readcache record
354
352
// remaining following this eviction, and its .PreviousAddress is updated to each lower record in turn until we hit a non-readcache record.
355
353
long nextPhysicalAddress = Constants . kInvalidAddress ;
356
354
HashBucketEntry entry = new ( ) { word = hei . entry . word } ;
357
- long lowestAddress = entry . Address ;
358
355
while ( entry . ReadCache )
359
356
{
360
357
var la = entry . AbsoluteAddress ;
@@ -393,10 +390,8 @@ private long ReadCacheEvictChain(long rcToLogicalAddress, ref HashEntryInfo hei)
393
390
ri . PreviousAddress = Constants . kTempInvalidAddress ; // The record is no longer in the chain
394
391
else
395
392
hei . SetToCurrent ( ) ;
396
- lowestAddress = entry . Address ;
397
393
entry . word = hei . entry . word ;
398
394
}
399
- return lowestAddress ;
400
395
}
401
396
}
402
397
}
0 commit comments