Various issues related to sessions synchronization during refresh are caused by the design.
Currently, the only way to update the config.system.sessions collection is by refresh method which is run in a separate thread on the primary.
Secondary does not write to the collection instead it sends sessions to the primary which adds it to a logical sessions cache and eventually writes to the collection.
However the secondary closes the cursors associated with sessions not existing in the sessions collection.
This scenario is possible if secondary and primary refreshes are out of synch. i.e.
1) secondary adds new sessions and opens cursors
2) secondary refresh updates primary logical session cache
3) if secondary rins a refresh now the newly opened sessions will be considered "deleted" because the primary has not yet refreshed
The following sequence of events is an example of this scenario
- Primary is unavailable for writes (say it's fsyncLocked).
- Client creates a session on a secondary and establishes a cursor without fully iterating it.
- The session cache refresh logic kicks in
- The secondary sends a refreshSessionsInternal command to the primary (from here) with the sessions it believes are active, which includes this new one.
- The primary receives the command, inserts the new session into its cache ('_activeSessions', here), but does not actually write it to system.sessions.
- The secondary then attempts to find which sessions it has open cursors for which have actually been timed out, so that it can kill them. To do this, it issues a query to the system.sessions collection on the primary. This collection will not actually have this new session, since it's fsyncLocked, and further the session refresh logic hasn't kicked in yet.
The problem shows manifestation is the "CursorNotFound" error on the GetMore command when running on the secondary.
The fix makes the secondary write to the primary so its always in sync and therefore can avoid "false negatives" checks for sessions existence.