Provider assignment per JSON-root graph for mj sync push.
Two modes, fixed when the pool is built. A pool never mixes them.
host (atomic push, the default): every graph uses the host provider, inside the
push transaction. Nothing commits until the push commits. The host has ONE transaction
stack, so graphs must run one at a time: obtain throws if a second graph asks for the
host while another graph still holds it. The caller releases a graph with drainBatch.
independent (an entity directory using isolated transactions): each graph gets its own instance from
CreateIndependentInstance() (shared pool, own transaction stack), so sibling graphs can
run in parallel. A root and its nested relatedEntities share one instance, so every DB op
in that graph uses the same connection. Each Save() commits on its own, so this mode is
NOT atomic: onGraphSettled reports which graphs left committed rows behind.
If CreateIndependentInstance fails, obtain throws. It never falls back to the host,
because mixing the host connection with graph instances is a deadlock (child FK waits on
an uncommitted parent). The caller decides the mode up front (see probeIndependentInstances).
Drain (independent mode): a graph is released at the end of a batch when (a) it will not
appear at a later level, or (b) its TransactionDepth is 0 (Save already committed, so a fresh
instance at the next level is safe). Graphs with leftover depth stay live until their last
level. Peak live independent instances is therefore bounded by the batch size, plus any
still-open leftover-depth graphs.
Provider assignment per JSON-root graph for
mj sync push.Two modes, fixed when the pool is built. A pool never mixes them.
host(atomic push, the default): every graph uses the host provider, inside the push transaction. Nothing commits until the push commits. The host has ONE transaction stack, so graphs must run one at a time:obtainthrows if a second graph asks for the host while another graph still holds it. The caller releases a graph withdrainBatch.independent(an entity directory using isolated transactions): each graph gets its own instance fromCreateIndependentInstance()(shared pool, own transaction stack), so sibling graphs can run in parallel. A root and its nested relatedEntities share one instance, so every DB op in that graph uses the same connection. EachSave()commits on its own, so this mode is NOT atomic:onGraphSettledreports which graphs left committed rows behind. IfCreateIndependentInstancefails,obtainthrows. It never falls back to the host, because mixing the host connection with graph instances is a deadlock (child FK waits on an uncommitted parent). The caller decides the mode up front (seeprobeIndependentInstances).Drain (independent mode): a graph is released at the end of a batch when (a) it will not appear at a later level, or (b) its TransactionDepth is 0 (Save already committed, so a fresh instance at the next level is safe). Graphs with leftover depth stay live until their last level. Peak live independent instances is therefore bounded by the batch size, plus any still-open leftover-depth graphs.