#include "Counters.hpp"
#include "Util.hpp"
+#include "hashutil.hpp"
+
+using nonstd::string_view;
Context::Context()
: actual_cwd(Util::get_actual_cwd()),
apparent_cwd(Util::get_apparent_cwd(actual_cwd))
{
}
+
+void
+Context::set_manifest_name(const struct digest& name)
+{
+ m_manifest_name = name;
+ set_path_and_stats_file(
+ name, ".manifest", m_manifest_path, m_manifest_stats_file);
+}
+
+void
+Context::set_result_name(const struct digest& name)
+{
+ m_result_name = name;
+ set_path_and_stats_file(name, ".result", m_result_path, m_result_stats_file);
+}
+
+const std::string&
+Context::stats_file() const
+{
+ if (m_result_stats_file.empty()) {
+ // An empty m_result_stats_file means that set_result_name hasn't been
+ // called yet, so we just choose one of stats files in the 16
+ // subdirectories.
+ m_result_stats_file = fmt::format(
+ "{}/{:x}/stats", config.cache_dir(), hash_from_int(getpid()) % 16);
+ }
+ return m_result_stats_file;
+}
+
+void
+Context::set_path_and_stats_file(const struct digest& name,
+ string_view suffix,
+ std::string& path_var,
+ std::string& stats_file_var)
+{
+ char name_string[DIGEST_STRING_BUFFER_SIZE];
+ digest_as_string(&name, name_string);
+ path_var = Util::get_path_in_cache(
+ config.cache_dir(), config.cache_dir_levels(), name_string, suffix);
+ stats_file_var =
+ fmt::format("{}/{}/stats", config.cache_dir(), name_string[0]);
+}
#include "hash.hpp"
#include "third_party/nonstd/optional.hpp"
+#include "third_party/nonstd/string_view.hpp"
#include <string>
#include <unordered_map>
// Name (represented as a struct digest) of the file containing the cached
// result.
- nonstd::optional<struct digest> result_name;
+ const struct digest& result_name() const;
// Full path to the file containing the result
// (cachedir/a/b/cdef[...]-size.result).
- std::string result_path;
+ const std::string& result_path() const;
// Full path to the file containing the manifest
// (cachedir/a/b/cdef[...]-size.manifest).
- std::string manifest_path;
+ const std::string& manifest_path() const;
// Time of compilation. Used to see if include files have changed after
// compilation.
// The name of the cpp stderr file.
std::string cpp_stderr;
+ // Name (represented as a struct digest) of the file containing the manifest
+ // for the cached result.
+ const struct digest& manifest_name() const;
+
// The stats file to use for the manifest.
- std::string manifest_stats_file;
+ const std::string& manifest_stats_file() const;
// Compiler guessing is currently only based on the compiler name, so nothing
// should hard-depend on it if possible.
// Full path to the statistics file in the subdirectory where the cached
// result belongs (<cache_dir>/<x>/stats).
- std::string stats_file;
+ const std::string& stats_file() const;
// Statistics which get written into the `stats_file` upon exit.
Counters counter_updates;
+
+ void set_manifest_name(const struct digest& name);
+ void set_result_name(const struct digest& name);
+
+private:
+ nonstd::optional<struct digest> m_manifest_name;
+ std::string m_manifest_path;
+ std::string m_manifest_stats_file;
+
+ nonstd::optional<struct digest> m_result_name;
+ std::string m_result_path;
+ mutable std::string m_result_stats_file;
+
+ void set_path_and_stats_file(const struct digest& name,
+ nonstd::string_view suffix,
+ std::string& path_var,
+ std::string& stats_file_var);
};
+
+inline const struct digest&
+Context::manifest_name() const
+{
+ return *m_manifest_name;
+}
+
+inline const std::string&
+Context::manifest_path() const
+{
+ assert(m_manifest_name); // set_manifest_name must have been called
+ return m_manifest_path;
+}
+
+inline const std::string&
+Context::manifest_stats_file() const
+{
+ assert(m_manifest_name); // set_manifest_name must have been called
+ return m_manifest_stats_file;
+}
+
+inline const struct digest&
+Context::result_name() const
+{
+ return *m_result_name;
+}
+
+inline const std::string&
+Context::result_path() const
+{
+ assert(m_result_name); // set_result_name must have been called
+ return m_result_path;
+}
return;
}
- auto old_st = Stat::stat(ctx.manifest_path);
+ auto old_st = Stat::stat(ctx.manifest_path());
// See comment in get_file_hash_index for why saving of timestamps is forced
// for precompiled headers.
|| ctx.args_info.output_is_precompiled_header;
MTR_BEGIN("manifest", "manifest_put");
- cc_log("Adding result name to %s", ctx.manifest_path.c_str());
+ cc_log("Adding result name to %s", ctx.manifest_path().c_str());
if (!manifest_put(ctx.config,
- ctx.manifest_path,
- *ctx.result_name,
+ ctx.manifest_path(),
+ ctx.result_name(),
ctx.included_files,
ctx.time_of_compilation,
save_timestamp)) {
- cc_log("Failed to add result name to %s", ctx.manifest_path.c_str());
+ cc_log("Failed to add result name to %s", ctx.manifest_path().c_str());
} else {
- auto st = Stat::stat(ctx.manifest_path, Stat::OnError::log);
+ auto st = Stat::stat(ctx.manifest_path(), Stat::OnError::log);
int64_t size_delta = st.size_on_disk() - old_st.size_on_disk();
int nof_files_delta = !old_st && st ? 1 : 0;
- if (ctx.stats_file == ctx.manifest_stats_file) {
+ if (ctx.stats_file() == ctx.manifest_stats_file()) {
stats_update_size(ctx.counter_updates, size_delta, nof_files_delta);
} else {
Counters counters;
stats_update_size(counters, size_delta, nof_files_delta);
- stats_flush_to_file(ctx.config, ctx.manifest_stats_file, counters);
+ stats_flush_to_file(ctx.config, ctx.manifest_stats_file(), counters);
}
}
MTR_END("manifest", "manifest_put");
}
-static void
-update_cached_result_globals(Context& ctx, struct digest* result_name)
-{
- char result_name_string[DIGEST_STRING_BUFFER_SIZE];
- digest_as_string(result_name, result_name_string);
- ctx.result_name = *result_name;
- ctx.result_path = Util::get_path_in_cache(ctx.config.cache_dir(),
- ctx.config.cache_dir_levels(),
- result_name_string,
- ".result");
- ctx.stats_file =
- fmt::format("{}/{}/stats", ctx.config.cache_dir(), result_name_string[0]);
-}
-
static bool
create_cachedir_tag(nonstd::string_view dir)
{
if (!result_name) {
failed(STATS_ERROR);
}
- update_cached_result_globals(ctx, result_name);
+ ctx.set_result_name(*result_name);
}
bool produce_dep_file = ctx.args_info.generating_dependencies
result_file_map.emplace(FileType::dwarf_object, ctx.args_info.output_dwo);
}
- auto orig_dest_stat = Stat::stat(ctx.result_path);
- result_put(ctx, ctx.result_path, result_file_map);
+ auto orig_dest_stat = Stat::stat(ctx.result_path());
+ result_put(ctx, ctx.result_path(), result_file_map);
- cc_log("Stored in cache: %s", ctx.result_path.c_str());
+ cc_log("Stored in cache: %s", ctx.result_path().c_str());
- auto new_dest_stat = Stat::stat(ctx.result_path, Stat::OnError::log);
+ auto new_dest_stat = Stat::stat(ctx.result_path(), Stat::OnError::log);
if (!new_dest_stat) {
failed(STATS_ERROR);
}
// be done almost anywhere, but we might as well do it near the end as we
// save the stat call if we exit early.
{
- std::string first_level_dir(Util::dir_name(ctx.stats_file));
+ std::string first_level_dir(Util::dir_name(ctx.stats_file()));
if (!create_cachedir_tag(first_level_dir)) {
cc_log("Failed to create %s/CACHEDIR.TAG (%s)",
first_level_dir.c_str(),
return nullptr;
}
- char manifest_name_string[DIGEST_STRING_BUFFER_SIZE];
- hash_result_as_string(hash, manifest_name_string);
- ctx.manifest_path = Util::get_path_in_cache(ctx.config.cache_dir(),
- ctx.config.cache_dir_levels(),
- manifest_name_string,
- ".manifest");
- ctx.manifest_stats_file = fmt::format(
- "{}/{}/stats", ctx.config.cache_dir(), manifest_name_string[0]);
+ struct digest manifest_name;
+ hash_result_as_bytes(hash, &manifest_name);
+ ctx.set_manifest_name(manifest_name);
- cc_log("Looking for result name in %s", ctx.manifest_path.c_str());
+ cc_log("Looking for result name in %s", ctx.manifest_path().c_str());
MTR_BEGIN("manifest", "manifest_get");
- result_name = manifest_get(ctx, ctx.manifest_path);
+ result_name = manifest_get(ctx, ctx.manifest_path());
MTR_END("manifest", "manifest_get");
if (result_name) {
cc_log("Got result name from manifest");
if (ctx.args_info.generating_diagnostics) {
result_file_map.emplace(FileType::diagnostic, ctx.args_info.output_dia);
}
- bool ok = result_get(ctx, ctx.result_path, result_file_map);
+ bool ok = result_get(ctx, ctx.result_path(), result_file_map);
if (!ok) {
cc_log("Failed to get result from cache");
tmp_unlink(tmp_stderr);
calculate_result_name(ctx, args_to_hash, dummy_args, direct_hash, true);
MTR_END("hash", "direct_hash");
if (result_name) {
- update_cached_result_globals(ctx, result_name);
+ ctx.set_result_name(*result_name);
// If we can return from cache at this point then do so.
auto result = from_cache(ctx, FROMCACHE_DIRECT_MODE);
if (!result_name) {
fatal("internal error: calculate_result_name returned NULL for cpp");
}
- update_cached_result_globals(ctx, result_name);
+ ctx.set_result_name(*result_name);
if (result_name_from_manifest
&& !digests_equal(result_name_from_manifest, result_name)) {
cc_log("Hash from manifest doesn't match preprocessor output");
cc_log("Likely reason: different CCACHE_BASEDIRs used");
cc_log("Removing manifest as a safety measure");
- x_unlink(ctx.manifest_path.c_str());
+ x_unlink(ctx.manifest_path().c_str());
put_result_in_manifest = true;
}