Tracking multiple instance for a given model PK in RelationCounterField.

Review Request #9607 — Created Feb. 9, 2018 and submitted


RelationCounterField used to track multiple in-memory instances for a
model on an end of a relation (of a given model type and primary key),
but that wasn't covered in unit tests and wasn't really explicitly
supported. Djblets 1.0 ended up removing that support in an effort to
redo how state was tracked, in order to fix other issues.

This change introduces explicit support for tracking multiple instances.
When updating values for an end of a relation, the field now performs
the update on one of the tracked instances (a "main" instance, which is
only "main" for that particular operation) and then synchronizes the
values to the other instances, ensuring they're all in sync without
requiring additional database operations.

To do this, the state tracking had to change just a bit. We previously
had a dictionary mapping a key (model_cls + instance primary key + field
name to an InstanceState object. Now it maps those to another
dictionary that maps Python object IDs for model instances to an
InstanceState. Callers then simply needed to perform updates on that
"main" instance and synchronize the values to the others.

Unit tests have been added to ensure that this does not regress. I've
made copies of most of the unit tests, adding multi-instance variants
so that we can easily catch if a future code change impacts the
synchronization or query counts for multi-instance tracking.

Unit tests pass in Djblets, Review Board, and Splat (which previously
regressed due to no longer having any multi-instance support).

  1. Ship It!
Review request changed

Status: Closed (submitted)

Change Summary:

Pushed to master (aa11741)