private BackfillInfo getBackfillInfoForSave(FinishTimeInfo finishTimeInfo, String appType,
        long applicableFinishTime) {
      BackfillInfo info = null;
      if (finishTimeInfo != null && !finishTimeInfo._appFinishTimesMap.isEmpty()) {
        Map.Entry<Long, Integer> lowestTsEntry = finishTimeInfo._appFinishTimesMap.firstEntry();
        long backfillTsToBeStored = lowestTsEntry.getKey();
        // If the first entry is the last entry as well and it will be removed at the end of this cycle,
        // this means that all the jobs upto the current max finish time have been stored. So store the max finish time
        // instead (only if max finish time > finish time for this app).
        if (finishTimeInfo._appFinishTimesMap.size() == 1 && lowestTsEntry.getValue() == 1 &&
            lowestTsEntry.getKey() == applicableFinishTime && backfillTsToBeStored < finishTimeInfo._maxFinishTime) {
          backfillTsToBeStored = finishTimeInfo._maxFinishTime;
        }
        if (finishTimeInfo._lastBackfillTsSaved != backfillTsToBeStored) {
          // Get hold of the record to update, if available, otherwise create a new one.
          info = BackfillInfo.find.byId(appType);
          if (info == null) {
            info = new BackfillInfo();
          }
          info.appType = appType;
          info.backfillTs = backfillTsToBeStored;
        }
      }

      return info;
    }
Get applicable finish time used while storing in app finish times map. This would typically be the app finish
time for apps fetched from RM. But for backfill jobs, if finish time could not be determined at the time of
fetching jobs for backfill, we will use the backfill ts fetched from backfill_info table instead (0 will be used
if an entry in backfill_info table could not be found as well).

@return applicable finish time.
app/com/linkedin/drelephant/ElephantRunner.java