There was an initialization race related to validFrom when instantiating a new channel cache, between AddToCache and addChannelCache.
A. AddToCache:
1. If any of the mutation's channels are active in the channel cache map, add entry to the cache
2. Acquire the seqLock, and update highCachedSequence
B. addChannelCache:
1. Acquire the seqLock. Add a new entry to the channel cache map, with validFrom = highCachedSequence + 1
In the case where B1 happens between A1 and A2, the validFrom for the new singleChannelCache will be invalid, as the sequence associated with the mutation being processed is greater than validFrom, but won't be in the cache.
To address, addToCache will need to hold a mutex across A1 and A2. It's preferred to not use seqLock for this, as it will introduce contention with changes processing that needs to retrieve highCachedSequence (independent of changes to the channel cache map). Instead, a new 'validFromLock' can be used. This shouldn't introduce significant contention on the caching side, as addToCache is already single-threaded (inside processEntry).
The test logging suggests that doc-1 (seq #1) is being received over DCP as expected (based on sequence buffering messages), but isn't ending up in the cache (based on Cache: GetCachedChanges logging. Suggests a potential race between per-channel cache initialization (triggered by the changes request), and doc-1 arriving over DCP. SG should handle all variations of timing here - need to identify which scenario isn't covered properly.