/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <odr_compilation_log.h>

#include <errno.h>

#include <fstream>
#include <ios>
#include <iosfwd>
#include <istream>
#include <ostream>
#include <streambuf>
#include <string>
#include <vector>

#include "android-base/logging.h"
#include "base/os.h"

#include "odrefresh/odrefresh.h"
#include "odr_metrics.h"

namespace art {
namespace odrefresh {

std::istream& operator>>(std::istream& is, OdrCompilationLogEntry& entry) {
  // Block I/O related exceptions
  auto saved_exceptions = is.exceptions();
  is.exceptions(std::ios_base::iostate {});

  // Write log entry. NB update OdrCompilationLog::kLogVersion if changing the format here.
  is >> entry.apex_version >> std::ws;
  is >> entry.last_update_millis >> std::ws;
  is >> entry.trigger >> std::ws;
  is >> entry.when >> std::ws;
  is >> entry.exit_code >> std::ws;

  // Restore I/O related exceptions
  is.exceptions(saved_exceptions);
  return is;
}

std::ostream& operator<<(std::ostream& os, const OdrCompilationLogEntry& entry) {
  static const char kSpace = ' ';

  // Block I/O related exceptions
  auto saved_exceptions = os.exceptions();
  os.exceptions(std::ios_base::iostate {});

  os << entry.apex_version << kSpace;
  os << entry.last_update_millis << kSpace;
  os << entry.trigger << kSpace;
  os << entry.when << kSpace;
  os << entry.exit_code << std::endl;

  // Restore I/O related exceptions
  os.exceptions(saved_exceptions);
  return os;
}

bool operator==(const OdrCompilationLogEntry& lhs, const OdrCompilationLogEntry& rhs) {
  return lhs.apex_version == rhs.apex_version && lhs.last_update_millis == rhs.last_update_millis &&
         lhs.trigger == rhs.trigger && lhs.when == rhs.when && lhs.exit_code == rhs.exit_code;
}

bool operator!=(const OdrCompilationLogEntry& lhs, const OdrCompilationLogEntry& rhs) {
  return !(lhs == rhs);
}

OdrCompilationLog::OdrCompilationLog(const char* compilation_log_path)
    : log_path_(compilation_log_path) {
  if (log_path_ != nullptr && OS::FileExists(log_path_)) {
    if (!Read()) {
      PLOG(ERROR) << "Failed to read compilation log: " << log_path_;
    }
  }
}

OdrCompilationLog::~OdrCompilationLog() {
  if (log_path_ != nullptr && !Write()) {
    PLOG(ERROR) << "Failed to write compilation log: " << log_path_;
  }
}

bool OdrCompilationLog::Read() {
  std::ifstream ifs(log_path_);
  if (!ifs.good()) {
    return false;
  }

  std::string log_version;
  ifs >> log_version >> std::ws;
  if (log_version != kLogVersion) {
    return false;
  }

  while (!ifs.eof()) {
    OdrCompilationLogEntry entry;
    ifs >> entry;
    if (ifs.fail()) {
      entries_.clear();
      return false;
    }
    entries_.push_back(entry);
  }

  return true;
}

bool OdrCompilationLog::Write() const {
  std::ofstream ofs(log_path_, std::ofstream::trunc);
  if (!ofs.good()) {
    return false;
  }

  ofs << kLogVersion << std::endl;
  for (const auto& entry : entries_) {
    ofs << entry;
    if (ofs.fail()) {
      return false;
    }
  }

  return true;
}

void OdrCompilationLog::Truncate() {
  if (entries_.size() < kMaxLoggedEntries) {
    return;
  }

  size_t excess = entries_.size() - kMaxLoggedEntries;
  entries_.erase(entries_.begin(), entries_.begin() + excess);
}

size_t OdrCompilationLog::NumberOfEntries() const {
  return entries_.size();
}

const OdrCompilationLogEntry* OdrCompilationLog::Peek(size_t index) const {
  if (index >= entries_.size()) {
    return nullptr;
  }
  return &entries_[index];
}

void OdrCompilationLog::Log(int64_t apex_version,
                            int64_t last_update_millis,
                            OdrMetrics::Trigger trigger,
                            ExitCode compilation_result) {
  time_t now;
  time(&now);
  Log(apex_version, last_update_millis, trigger, now, compilation_result);
}

void OdrCompilationLog::Log(int64_t apex_version,
                            int64_t last_update_millis,
                            OdrMetrics::Trigger trigger,
                            time_t when,
                            ExitCode compilation_result) {
  entries_.push_back(OdrCompilationLogEntry{apex_version,
                                            last_update_millis,
                                            static_cast<int32_t>(trigger),
                                            when,
                                            static_cast<int32_t>(compilation_result)});
  Truncate();
}

bool OdrCompilationLog::ShouldAttemptCompile(OdrMetrics::Trigger trigger, time_t now) const {
  if (entries_.size() == 0) {
    // We have no history, try to compile.
    return true;
  }

  // The backoff time is for avoiding too many failed attempts. It should not be applied if the last
  // compilation was successful.
  if (entries_.back().exit_code == ExitCode::kCompilationSuccess) {
    return true;
  }

  if (trigger == OdrMetrics::Trigger::kApexVersionMismatch ||
      trigger == OdrMetrics::Trigger::kDexFilesChanged) {
    // Things have changed since the last run.
    return true;
  }

  // Compute the backoff time based on the number of consecutive failures.
  //
  // Wait 12 hrs * pow(2, consecutive_failures) since the last compilation attempt.
  static const int kSecondsPerDay = 86'400;
  time_t backoff = kSecondsPerDay / 2;
  for (auto it = entries_.crbegin(); it != entries_.crend(); ++it, backoff *= 2) {
    if (it->exit_code == ExitCode::kCompilationSuccess) {
      break;
    }
  }

  if (now == 0) {
    time(&now);
  }

  const time_t last_attempt = entries_.back().when;
  const time_t threshold = last_attempt + backoff;
  return now >= threshold;
}

}  // namespace odrefresh
}  // namespace art
