anchor.diff:  is_transfer_ongoing(#transfer{status = failed}) -> false.
   
   %%-------------------------------------------------------------------
  +%% @doc
  +%% Predicate saying if given transfer is migrating a replica.
  +%% @end
  +%%-------------------------------------------------------------------
  +-spec is_migrating(transfer()) -> boolean().
  +is_migrating(#transfer{invalidate_source_replica = Flag}) -> Flag.
  +
  +%%-------------------------------------------------------------------
  +%% @doc
  +%% Predicate saying if given transfer is only invalidating replica.
  +%% @end
  +%%-------------------------------------------------------------------
  +-spec is_invalidating(transfer()) -> boolean().
  +is_invalidating(#transfer{
  +    invalidate_source_replica = Flag,
  +    target_provider_id = undefined
  +}) ->
  +    Flag;
  +is_invalidating(_) ->
  +    false.
  +
  +%%-------------------------------------------------------------------
   %% @private
   %% @doc
   %% Predicate saying if invalidation within given transfer is ongoing. Returns
  
positive.code: %%-------------------------------------------------------------------
  -spec restart(id()) -> {ok, id()} | {error, term()}.
  restart(TransferId) ->
      TimeSeconds = provider_logic:zone_time_seconds(),
      UpdateFun = fun(Transfer) ->
  
          TransferStatus = case Transfer#transfer.status of
              completed -> completed;
              skipped -> skipped;
              cancelled -> cancelled;
              _ -> scheduled
          end,
  
          InvalidationStatus = case Transfer#transfer.invalidation_status of
              completed -> completed;
              skipped -> skipped;
              cancelled -> cancelled;
              _ -> scheduled
          end,
  
          {ok, Transfer#transfer{
              status = TransferStatus,
              invalidation_status = InvalidationStatus,
              files_to_transfer = 0,
              files_transferred = 0,
              bytes_to_transfer = 0,
              bytes_transferred = 0,
              files_invalidated = 0,
              files_to_invalidate = 0,
              start_time = TimeSeconds,
              last_update = #{},
              min_hist = #{},
              hr_hist = #{},
              dy_hist = #{},
              mth_hist = #{}
          }}
      end,
      case update(TransferId, UpdateFun) of
          {ok, TransferId} ->
  
negative.code:             transfer_controller:on_new_transfer_doc(TransferDoc),
              invalidation_controller:on_new_transfer_doc(TransferDoc),
              {ok, TransferId};
          {error, not_target_provider} ->
              {ok, undefined};
          {error, not_source_provdier} ->
              {ok, undefined};
          Error ->
              ?error_stacktrace("Restarting transfer ~p failed due to ~p", [TransferId, Error]),
              Error
      end.
  
  %%-------------------------------------------------------------------
  %% @private
  %% @doc
  %% This function checks whether calling provider can reset given
  %% transfer (replication, migration or invalidation).
  %% If true, it resets transfer document.
  %% @end
  %%-------------------------------------------------------------------
  -spec maybe_restart_and_update_links(id(), transfer()) -> {ok, id()} | {error, term()}.
  maybe_restart_and_update_links(TransferId, Transfer) ->
      case {is_migrating(Transfer), is_invalidating(Transfer)} of
          {false, false} ->
              % transfer
              maybe_reset_replication_record(TransferId, Transfer);
          {true, true} ->
              % invalidation
              maybe_reset_invalidation_record(TransferId,Transfer);
          {true, false} ->
              % migration
              maybe_reset_migration_record(TransferId, Transfer)
      end.
  
  %%-------------------------------------------------------------------
  %% @private
  %% @doc
  %% This function checks whether calling provider can reset given
  %% replication transfer. If true, it resets transfer document.
  %% @end
  %%-------------------------------------------------------------------
  -spec maybe_reset_replication_record(id(), transfer()) -> {ok, id()} | {error, term()}.
  maybe_reset_replication_record(TransferId, Transfer = #transfer{
      target_provider_id = TargetProviderId
  }) ->
      case oneprovider:get_provider_id() =:= TargetProviderId of
          true ->
              maybe_move_from_past_to_current_links_tree(TransferId, Transfer),
              {ok, Transfer#transfer{
                  status = scheduled,
                  files_to_transfer = 0,
                  files_transferred = 0,
                  failed_files = 0,
                  bytes_to_transfer = 0,
                  bytes_transferred = 0,
                  start_time = provider_logic:zone_time_seconds(),
                  finish_time = 0,
                  last_update = #{},
                  min_hist = #{},
                  hr_hist = #{},
                  dy_hist = #{},
                  mth_hist = #{}
              }};
          false ->
              {error, not_target_provider}
      end.
  
  %%-------------------------------------------------------------------
  %% @private
  %% @doc
  %% This function checks whether calling provider can reset given
  %% invalidation transfer. If true, it resets transfer document.
  %% @end
  %%-------------------------------------------------------------------
  -spec maybe_reset_invalidation_record(id(), transfer()) -> {ok, id()} | {error, term()}.
  maybe_reset_invalidation_record(TransferId, Transfer = #transfer{
      source_provider_id = SourceProviderId
  }) ->
      case oneprovider:get_provider_id() =:= SourceProviderId of
          true ->
              maybe_move_from_past_to_current_links_tree(TransferId, Transfer),
              {ok, Transfer#transfer{
                  invalidation_status = scheduled,
                  files_invalidated = 0,
                  files_to_invalidate = 0,
                  start_time = provider_logic:zone_time_seconds(),
                  finish_time = 0
              }};
          false ->
              {error, not_source_provider}
      end.
  
  %%-------------------------------------------------------------------
  %% @private
  %% @doc
  %% This function checks whether calling provider can reset given
  %% migration transfer. If true, it resets transfer document.
  %% @end
  %%-------------------------------------------------------------------
  -spec maybe_reset_migration_record(id(), transfer()) -> {ok, id()} | {error, term()}.
  maybe_reset_migration_record(TransferId, Transfer = #transfer{
      source_provider_id = SourceProviderId
  }) ->
      case is_transfer_ongoing(Transfer) of
          true ->
              maybe_reset_replication_record(TransferId, Transfer);
          _ ->
              case SourceProviderId =:= oneprovider:get_provider_id() of
                  true ->
                      maybe_move_from_past_to_current_links_tree(TransferId, Transfer),
                      {ok, Transfer#transfer{
                          status = scheduled,
                          invalidation_status = scheduled,
                          files_to_transfer = 0,
                          files_transferred = 0,
                          bytes_to_transfer = 0,
                          bytes_transferred = 0,
                          files_invalidated = 0,
                          files_to_invalidate = 0,
                          start_time = provider_logic:zone_time_seconds(),
                          finish_time = 0,
                          last_update = #{},
                          min_hist = #{},
                          hr_hist = #{},
                          dy_hist = #{},
                          mth_hist = #{}
                      }};
                  false ->
                      {error, not_source_provider}
              end
      end.
  
  %%-------------------------------------------------------------------
  