reparent method

void reparent(
  1. List<ResourceScopeImpl> newEdges
)

Moves this scope under newEdges. Its current resources are counted in the ancestors it gains and released from the ones it loses; an ancestor it keeps (the system scope, usually) keeps counting them once. This is how go-libp2p's SetPeer and SetProtocol juggle resources. Throws, and changes nothing, if a gained ancestor's limit would be exceeded.

Implementation

void reparent(List<ResourceScopeImpl> newEdges) {
  // A scope that is done holds nothing and refers to nothing; moving it
  // would only take references that are never dropped. (A stream whose
  // remote peer reset it is done before the protocol is set.)
  if (_isDone) return;
  if (_owner != null) {
    throw StateError('$name: a span cannot be reparented');
  }
  final oldAncestors = _ancestors.toSet();
  final newAncestors = _closure(newEdges);
  final gained = newAncestors.where((a) => !oldAncestors.contains(a)).toList();
  final lost = oldAncestors.where((a) => !newAncestors.contains(a)).toList();
  final st = stat;

  final reserved = <ResourceScopeImpl>[];
  for (final scope in gained) {
    final err = scope._isDone ? network_errors.ResourceScopeClosedException() : scope._resources.reserveStat(st);
    if (err != null) {
      for (final r in reserved) {
        r._releaseResourcesForChild(st);
      }
      throw _wrapError(err);
    }
    reserved.add(scope);
  }
  for (final scope in lost) {
    scope._releaseResourcesForChild(st);
  }

  for (final e in edges) {
    if (!newEdges.contains(e)) e.decRef();
  }
  for (final e in newEdges) {
    if (!edges.contains(e)) e.incRef();
  }
  edges = List.of(newEdges);
}