Prevent a crash in RelationCounterField when clearing state.

Review Request #9591 - Created Feb. 5, 2018 and submitted

Christian Hammond

RelationCounterField keeps state around in weak references, and
attempts to delete entries from that state when instances go away. On
occasion, we'd see a crash from within weakref about a dictionary
being modified during iteration, and this happened while we were simply
gathering the keys and values into a list.

Most likely, this was happening due to two threads altering the states
at the same time. In order to prevent this, we now have a _state_lock
that's used whenever something wants to modify the state dictionaries,
allowing only one to make a modification at a time.

There's also a change to how state is reset. Instead of copying the
entire set of keys and values out of the dictionary and then changing
the dictionary inside the iteration, we now iterate without copying and
store the keys to delete in a list. We then separately iterate through
those and delete from the dictionary, saving the amount of data that
must be copied around.

Unit tests pass.

This is a really difficult thing to write a test for, so we're going to
settle for seeing whether we continue to get errors in production.

Christian Hammond
David Trowbridge
  1. Ship It!
Christian Hammond
Review request changed

Status: Closed (submitted)

Change Summary:

Pushed to release-1.0.x (85e855f)