blob: 0094bb8ea6ab43afe017eb7506c8084da74dbea6 [file] [log] [blame]
// Copyright 2018 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cache.h"
#include "autolock_timer.h"
#include "base/path.h"
#include "glog/logging.h"
namespace devtools_goma {
namespace modulemap {
// static
Cache* Cache::instance_;
// static
void Cache::Init(size_t cache_size) {
CHECK(instance_ == nullptr)
<< "modulemap::Cache has already been initialized?";
instance_ = new Cache(cache_size);
}
// static
void Cache::Quit() {
CHECK(instance_ != nullptr) << "modulemap::Cache was not initialized?";
delete instance_;
instance_ = nullptr;
}
size_t Cache::size() const {
AUTO_SHARED_LOCK(lock, &mu_);
return cache_.size();
}
bool Cache::AddModuleMapFileAndDependents(const std::string& module_map_file,
const std::string& cwd,
std::set<std::string>* include_files,
FileStatCache* file_stat_cache) {
// first, find from cache. If found, check all FileStat.
// If nothing is changed, we just use it.
std::string abs_module_map_path =
file::JoinPathRespectAbsolute(cwd, module_map_file);
CacheKey key(cwd, std::move(abs_module_map_path));
bool cache_hit = false;
std::vector<CollectedModuleMapFile> cached_item;
{
AUTO_SHARED_LOCK(lock, &mu_);
auto it = cache_.find(key);
if (it != cache_.end()) {
// Need to copy in order to access outside of lock.s
cache_hit = true;
cached_item = it->second;
}
}
if (cache_hit) {
bool ok = true;
// If cache_hit, check FileStat.
for (const auto& cf : cached_item) {
FileStat fs = file_stat_cache->Get(cf.abs_path);
if (!fs.IsValid() || fs.CanBeNewerThan(cf.file_stat)) {
// a file is deleted or changed.
ok = false;
break;
}
}
if (ok) {
// All dependent files aren't changed.
for (const auto& cf : cached_item) {
include_files->insert(cf.rel_path);
}
cache_hit_.Add(1);
return true;
}
}
cache_miss_.Add(1);
// If cache is not found or invalidated, we just run the processor, and keep
// the result.
Processor processor(cwd, file_stat_cache);
if (!processor.AddModuleMapFile(module_map_file)) {
return false;
}
for (const auto& cf : processor.collected_module_map_files()) {
include_files->insert(cf.rel_path);
}
for (const auto& cf : processor.collected_module_map_files()) {
if (cf.file_stat.CanBeStale()) {
// Do not cache if stat can be stale.
return true;
}
}
{
AUTO_EXCLUSIVE_LOCK(lock, &mu_);
cache_.emplace_back(
std::move(key),
std::move(*processor.mutable_collected_module_map_files()));
// Remove oldest entries.
while (cache_.size() > max_cache_entries_) {
cache_.pop_front();
cache_evicted_.Add(1);
}
}
return true;
}
} // namespace modulemap
} // namespace devtools_goma