anchor.diff:                            andalso (length(SafePresent) >= S#state.blobk)) of
                           true ->
                               Update = {BlobName, filter},
  -                            collect_updates(S, Rest, [Update | Updates]);
  +                            collect(S, Rest, {[Update | Updates], NewSBL});
                           false ->
                               % Blacklist filtering is not needed, or
                               % it's not yet safe.
  -                            collect_updates(S, Rest, Updates)
  +                            collect(S, Rest, {Updates, NewSBL})
                       end;
                   [{_, _P, R, {update, NewUrls}}] ->
                       AccUpdates = add_blob_update(S, BlobName, R, NewUrls, Updates),
  -                    collect_updates(S, Rest, AccUpdates)
  +                    collect(S, Rest, {AccUpdates, NewSBL})
               end
       end.
   
  
positive.code: %% ===================================================================
  %% tag updates
  
  -spec update_tag(state(), object_name(), non_neg_integer()) -> 'ok'.
  update_tag(_S, _T, 0) ->
      ok;
  update_tag(S, T, Retries) ->
      case catch ddfs_master:tag_operation(gc_get, T, ?GET_TAG_TIMEOUT) of
          {{missing, deleted}, false} ->
              ok;
          {'EXIT', {timeout, _}} ->
              update_tag(S, T, Retries - 1);
          {TagId, TagUrls, TagReplicas} ->
              update_tag_body(S, T, TagId, TagUrls, TagReplicas);
          _E ->
              ok
      end.
  
  % RR2) Update tags that contain blobs that were re-replicated, and/or
  %      re-replicate tags that don't have enough replicas.
  
  -spec update_tag_body(state(), tagname(), tagid(), [[url()]], [node()])
                       -> 'ok'.
  update_tag_body(S, Tag, Id, TagUrls, TagReplicas) ->
      % Collect the blobs that need updating, and compute their new
      % replica locations.
      Updates = collect_updates(S, TagUrls),
      UsableTagReplicas = find_usable(S#state.blacklist, TagReplicas),
      case {Updates, length(UsableTagReplicas)} of
          {[], NumTagReps} when NumTagReps >= S#state.tagk ->
              % There are no blob updates, and there are the requisite
              % number of tag replicas; tag doesn't need update.
              ok;
          _ ->
              % In all other cases, send the tag an update.
              Msg = {gc_rr_update, Updates, S#state.blacklist, Id},
              error_logger:info_report({"Updating tag", Msg}),
              ddfs_master:tag_notify(Msg, Tag)
      end.
  
  -spec collect_updates(state(), [[url()]]) -> [blob_update()].
  collect_updates(S, BlobSets) ->
      collect_updates(S, BlobSets, []).
  collect_updates(_S, [], Updates) ->
      Updates;
  collect_updates(S, [[]|Rest], Updates) ->
      collect_updates(S, Rest, Updates);
  collect_updates(S, [BlobSet|Rest], Updates) ->
      {[BlobName|_], Nodes} = lists:unzip([ddfs_url(Url) || Url <- BlobSet]),
      case BlobName of
          ignore ->
              collect_updates(S, Rest, Updates);
          _ ->
              case ets:lookup(gc_blobs, BlobName) of
                  [] ->
                      % New blob added after GC/RR started.
                      collect_updates(S, Rest, Updates);
                  [{_, P, _R, noupdate}] ->
                      % Check whether blacklist filtering is needed,
                      % provided we have enough replicas present.  Since
  
negative.code:           pending_nodes     = gb_sets:empty() :: gb_set(),                % gc
            rr_next           = undefined       :: 'undefined' | rr_next(), % rr_blobs
            rr_pid            = undefined       :: 'undefined' | pid(),     % rr_blobs
            safe_blacklist    = gb_sets:empty() :: gb_set(),                % rr_tags
  
            % static state
            tags              = []      :: [object_name()],
  