]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Allow for 64-bit values in statistics counters
authorJoel Rosdahl <joel@rosdahl.net>
Sat, 5 Sep 2020 14:55:39 +0000 (16:55 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Sat, 5 Sep 2020 14:55:39 +0000 (16:55 +0200)
This is primaily done to avoid overflowing timestamp values in 2038.

12 files changed:
src/Config.hpp
src/Counters.cpp
src/Counters.hpp
src/Util.cpp
src/Util.hpp
src/ccache.cpp
src/cleanup.cpp
src/cleanup.hpp
src/stats.cpp
src/stats.hpp
test/run
test/suites/base.bash

index 008d4ca08402ab22bde35a88f27e62dc7dbf8966..cb009d19971cfe24adbf944eeb58f5c5de4f9248 100644 (file)
@@ -62,7 +62,7 @@ public:
   bool keep_comments_cpp() const;
   double limit_multiple() const;
   const std::string& log_file() const;
-  uint32_t max_files() const;
+  uint64_t max_files() const;
   uint64_t max_size() const;
   const std::string& path() const;
   bool pch_external_checksum() const;
@@ -86,7 +86,7 @@ public:
   void set_ignore_options(const std::string& value);
   void set_inode_cache(bool value);
   void set_limit_multiple(double value);
-  void set_max_files(uint32_t value);
+  void set_max_files(uint64_t value);
   void set_max_size(uint64_t value);
   void set_run_second_cpp(bool value);
 
@@ -152,7 +152,7 @@ private:
   bool m_keep_comments_cpp = false;
   double m_limit_multiple = 0.8;
   std::string m_log_file = "";
-  uint32_t m_max_files = 0;
+  uint64_t m_max_files = 0;
   uint64_t m_max_size = 5ULL * 1000 * 1000 * 1000;
   std::string m_path = "";
   bool m_pch_external_checksum = false;
@@ -318,7 +318,7 @@ Config::log_file() const
   return m_log_file;
 }
 
-inline uint32_t
+inline uint64_t
 Config::max_files() const
 {
   return m_max_files;
@@ -460,7 +460,7 @@ Config::set_limit_multiple(double value)
 }
 
 inline void
-Config::set_max_files(uint32_t value)
+Config::set_max_files(uint64_t value)
 {
   m_max_files = value;
 }
index 262b562701c3936f795c947bc215ba3d2d4f1298..a680fd773575c1cf25db90d8c3f1837e3fca5602 100644 (file)
@@ -27,7 +27,7 @@ Counters::Counters() : m_counters(static_cast<size_t>(Statistic::END))
 }
 
 // clang-format off
-unsigned&
+uint64_t&
 Counters::operator[](Statistic index)
 // clang-format on
 {
@@ -39,7 +39,7 @@ Counters::operator[](Statistic index)
 }
 
 // clang-format off
-unsigned
+uint64_t
 Counters::operator[](Statistic index) const
 // clang-format on
 {
index b72d83a50445b5660d648fef192cb3e3dc08d219..cdd6c151501b5feff9ddcfb889d550163e503ca9 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010-2019 Joel Rosdahl and other contributors
+// Copyright (C) 2010-2020 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
 
 enum class Statistic;
 
-// A simple wrapper around a vector of integers
-// used for the statistics counters.
+// A simple wrapper around a vector of integers used for the statistics
+// counters.
 class Counters
 {
 public:
   Counters();
 
-  unsigned& operator[](Statistic index);
-  unsigned operator[](Statistic index) const;
+  uint64_t& operator[](Statistic index);
+  uint64_t operator[](Statistic index) const;
 
   size_t size() const;
 
@@ -40,5 +40,5 @@ public:
   bool all_zero() const;
 
 private:
-  std::vector<unsigned> m_counters;
+  std::vector<uint64_t> m_counters;
 };
index 24d88c0e3f215db31758a7d00287df845d5ae974..e646aa81c7bb418f7ae614621022a6031c3f9016 100644 (file)
@@ -938,7 +938,7 @@ normalize_absolute_path(string_view path)
 #endif
 }
 
-uint32_t
+uint64_t
 parse_duration(const std::string& duration)
 {
   unsigned factor = 0;
index f833656830e5f4ab8da9fa110214b9cdb15dec28..9d3f42f02e7295b7f0fbe76478a9a75af1816ded 100644 (file)
@@ -312,9 +312,9 @@ bool matches_dir_prefix_or_file(nonstd::string_view dir_prefix_or_file,
 // On Windows: Backslashes are replaced with forward slashes.
 std::string normalize_absolute_path(nonstd::string_view path);
 
-// Parse `duration`, an unsigned 32-bit integer with d (days) or s (seconds)
-// suffix, into seconds. Throws `Error` on error.
-uint32_t parse_duration(const std::string& duration);
+// Parse `duration`, an unsigned integer with d (days) or s (seconds) suffix,
+// into seconds. Throws `Error` on error.
+uint64_t parse_duration(const std::string& duration);
 
 // Parse a string into a signed integer.
 //
index 01bfcd5ddb9a2dc582cfc2ab57ec7ae7f168fe02..8e84d1c63364aecc4a671cca4871d9969fd3715b 100644 (file)
@@ -1725,7 +1725,7 @@ create_initial_config_file(Config& config)
     return;
   }
 
-  unsigned max_files;
+  uint64_t max_files;
   uint64_t max_size;
   std::string stats_dir = fmt::format("{}/0", config.cache_dir());
   if (Stat::stat(stats_dir)) {
index 0401d39fa42058f6d6db24d81b5952a5d9558ab7..9301108d0d4e63c7f28737b8620f3d43820261cc 100644 (file)
@@ -39,7 +39,7 @@ static void
 delete_file(const std::string& path,
             uint64_t size,
             uint64_t* cache_size,
-            uint32_t* files_in_cache)
+            uint64_t* files_in_cache)
 {
   bool deleted = Util::unlink_safe(path, Util::UnlinkLog::ignore_failure);
   if (!deleted && errno != ENOENT && errno != ESTALE) {
@@ -57,7 +57,7 @@ delete_file(const std::string& path,
 void
 clean_old(const Context& ctx,
           const Util::ProgressReceiver& progress_receiver,
-          time_t max_age)
+          uint64_t max_age)
 {
   Util::for_each_level_1_subdir(
     ctx.config.cache_dir(),
@@ -72,8 +72,8 @@ clean_old(const Context& ctx,
 void
 clean_up_dir(const std::string& subdir,
              uint64_t max_size,
-             uint32_t max_files,
-             time_t max_age,
+             uint64_t max_files,
+             uint64_t max_age,
              const Util::ProgressReceiver& progress_receiver)
 {
   log("Cleaning up cache directory {}", subdir);
@@ -83,7 +83,7 @@ clean_up_dir(const std::string& subdir,
     subdir, [&](double progress) { progress_receiver(progress / 3); }, files);
 
   uint64_t cache_size = 0;
-  uint32_t files_in_cache = 0;
+  uint64_t files_in_cache = 0;
   time_t current_time = time(nullptr);
 
   for (size_t i = 0; i < files.size();
@@ -129,7 +129,9 @@ clean_up_dir(const std::string& subdir,
 
     if ((max_size == 0 || cache_size <= max_size)
         && (max_files == 0 || files_in_cache <= max_files)
-        && (max_age == 0 || file->lstat().mtime() > (current_time - max_age))) {
+        && (max_age == 0
+            || file->lstat().mtime()
+                 > (current_time - static_cast<int64_t>(max_age)))) {
       break;
     }
 
index 750bcd47ceed2f866e5be5accbaaf467d1c7dbbc..053eb53e086661d8edb640199dc812acb1fbffba 100644 (file)
@@ -29,12 +29,12 @@ class Context;
 
 void clean_old(const Context& ctx,
                const Util::ProgressReceiver& progress_receiver,
-               time_t max_age);
+               uint64_t max_age);
 
 void clean_up_dir(const std::string& subdir,
                   uint64_t max_size,
-                  uint32_t max_files,
-                  time_t max_age,
+                  uint64_t max_files,
+                  uint64_t max_age,
                   const Util::ProgressReceiver& progress_receiver);
 
 void clean_up_all(const Config& config,
index ae211e600bba72bc0ed80f0878768417a21d6cee..8b8a5a1ef2e56abb42064f07547910b9eef787dd 100644 (file)
@@ -157,7 +157,7 @@ parse_stats(Counters& counters, const std::string& buf)
   const char* p = buf.c_str();
   while (true) {
     char* p2;
-    long val = strtol(p, &p2, 10);
+    unsigned long long val = std::strtoull(p, &p2, 10);
     if (p2 == p) {
       break;
     }
@@ -188,18 +188,18 @@ stats_write(const std::string& path, const Counters& counters)
 static double
 stats_hit_rate(const Counters& counters)
 {
-  unsigned direct = counters[Statistic::direct_cache_hit];
-  unsigned preprocessed = counters[Statistic::preprocessed_cache_hit];
-  unsigned hit = direct + preprocessed;
-  unsigned miss = counters[Statistic::cache_miss];
-  unsigned total = hit + miss;
+  uint64_t direct = counters[Statistic::direct_cache_hit];
+  uint64_t preprocessed = counters[Statistic::preprocessed_cache_hit];
+  uint64_t hit = direct + preprocessed;
+  uint64_t miss = counters[Statistic::cache_miss];
+  uint64_t total = hit + miss;
   return total > 0 ? (100.0 * hit) / total : 0.0;
 }
 
 static void
 stats_collect(const Config& config, Counters& counters, time_t* last_updated)
 {
-  unsigned zero_timestamp = 0;
+  uint64_t zero_timestamp = 0;
 
   *last_updated = 0;
 
@@ -319,7 +319,7 @@ stats_flush_to_file(const Config& config,
     double factor = config.limit_multiple() / 16;
     uint64_t max_size = round(config.max_size() * factor);
     uint32_t max_files = round(config.max_files() * factor);
-    uint32_t max_age = 0;
+    time_t max_age = 0;
     clean_up_dir(
       subdir, max_size, max_files, max_age, [](double /*progress*/) {});
   }
@@ -453,7 +453,7 @@ stats_zero(const Context& ctx)
 // Get the per-directory limits.
 void
 stats_get_obsolete_limits(const std::string& dir,
-                          unsigned* maxfiles,
+                          uint64_t* maxfiles,
                           uint64_t* maxsize)
 {
   assert(maxfiles);
@@ -463,13 +463,12 @@ stats_get_obsolete_limits(const std::string& dir,
   std::string sname = dir + "/stats";
   stats_read(sname, counters);
   *maxfiles = counters[Statistic::obsolete_max_files];
-  *maxsize =
-    static_cast<uint64_t>(counters[Statistic::obsolete_max_size]) * 1024;
+  *maxsize = counters[Statistic::obsolete_max_size] * 1024;
 }
 
 // Set the per-directory sizes.
 void
-stats_set_sizes(const std::string& dir, unsigned num_files, uint64_t total_size)
+stats_set_sizes(const std::string& dir, uint64_t num_files, uint64_t total_size)
 {
   Counters counters;
   std::string statsfile = dir + "/stats";
@@ -484,7 +483,7 @@ stats_set_sizes(const std::string& dir, unsigned num_files, uint64_t total_size)
 
 // Count directory cleanup run.
 void
-stats_add_cleanup(const std::string& dir, unsigned count)
+stats_add_cleanup(const std::string& dir, uint64_t count)
 {
   Counters counters;
   std::string statsfile = dir + "/stats";
index 4561dace7c7dc0292a9375d6995993138b0a84a5..a7a13c117fd62649c7b1897cd4770d9333d92f80 100644 (file)
@@ -77,11 +77,11 @@ void stats_print(const Config& config);
 
 void stats_update_size(Counters& counters, int64_t size, int files);
 void stats_get_obsolete_limits(const std::string& dir,
-                               unsigned* maxfiles,
+                               uint64_t* maxfiles,
                                uint64_t* maxsize);
 void stats_set_sizes(const std::string& dir,
-                     unsigned num_files,
+                     uint64_t num_files,
                      uint64_t total_size);
-void stats_add_cleanup(const std::string& dir, unsigned count);
+void stats_add_cleanup(const std::string& dir, uint64_t count);
 void stats_read(const std::string& path, Counters& counters);
 void stats_write(const std::string& path, const Counters& counters);
index e0e9e3af339f6d519ec50a899c5236b10a12d896..aaf92d80249cfdba3711409d61e2ea9b38d62a88 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -148,7 +148,7 @@ objdump_grep_cmd() {
 expect_stat() {
     local stat="$1"
     local expected_value="$2"
-    local value="$(echo $($CCACHE -s | fgrep "$stat" | cut -c34-))"
+    local value="$(echo $($CCACHE -s | fgrep "$stat" | cut -c33-))"
 
     if [ "$expected_value" != "$value" ]; then
         test_failed "Expected \"$stat\" to be $expected_value, actual $value"
index 2090e36571066d25cdb85cb3edf0836649bbec39..65cba561d90925093c42b6576824bf32cccacfe7 100644 (file)
@@ -376,6 +376,18 @@ base_tests() {
     expect_contains "$stats_file" 101
     expect_newer_than "$stats_file" "$CCACHE_DIR/timestamp_reference"
 
+    # -------------------------------------------------------------------------
+    TEST "stats file with large counter values"
+
+    mkdir -p "$CCACHE_DIR/4/"
+    stats_file="$CCACHE_DIR/4/stats"
+
+    echo "0 0 0 0 1234567890123456789" >"$stats_file"
+
+    expect_stat 'cache miss' 1234567890123456789
+    $CCACHE_COMPILE -c test1.c
+    expect_stat 'cache miss' 1234567890123456790
+
     # -------------------------------------------------------------------------
     TEST "CCACHE_RECACHE"