gc method
Removes entities not reachable from any operation root nor from one of
the retained entity keys (extra roots: SlingClient.gc passes the
entities live scopes read). Returns the removed keys. No scope reads a
removed entity, so the client rebuilds nothing; onChange still
reports the removed entities' fields (a persistence layer drops them).
Implementation
@override
Set<String> gc({Iterable<String> retain = const []}) {
final live = <String>{};
void mark(Object? node) {
if (node is Ref) {
if (live.add(node.key)) mark(_entities[node.key]);
} else if (node is Map) {
node.values.forEach(mark);
} else if (node is List) {
node.forEach(mark);
}
}
for (final key in [..._entities.keys.where(isRootKey), ...retain]) {
final entity = _entities[key];
if (entity != null && live.add(key)) mark(entity);
}
final dead = _entities.keys.where((k) => !live.contains(k)).toSet();
final touched = <String>{};
for (final key in dead) {
final removed = _entities.remove(key)!;
_depKeys.remove(key);
// No live reader: the list keys are not reported (see [Cache.gc]).
_listDepKeys.remove(key);
_markRemoved(key);
for (final field in removed.keys) {
final dep = depKey(key, field);
_fetchedAt.remove(dep);
touched.add(dep);
}
}
_emit(touched);
return dead;
}