]>
Commit | Line | Data |
---|---|---|
de637952 | 1 | // Copyright (C) 2020-2023 Joel Rosdahl and other contributors |
213d9883 OL |
2 | // |
3 | // See doc/AUTHORS.adoc for a complete list of contributors. | |
4 | // | |
5 | // This program is free software; you can redistribute it and/or modify it | |
6 | // under the terms of the GNU General Public License as published by the Free | |
7 | // Software Foundation; either version 3 of the License, or (at your option) | |
8 | // any later version. | |
9 | // | |
10 | // This program is distributed in the hope that it will be useful, but WITHOUT | |
11 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | // more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License along with | |
16 | // this program; if not, write to the Free Software Foundation, Inc., 51 | |
17 | // Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | ||
19 | #pragma once | |
20 | ||
0e4e4b63 | 21 | #include <Hash.hpp> |
38ab9d38 | 22 | #include <hashutil.hpp> |
3b6c2a5a | 23 | #include <util/Duration.hpp> |
54cbb06a | 24 | #include <util/Fd.hpp> |
de637952 | 25 | #include <util/TimePoint.hpp> |
3b6c2a5a | 26 | |
ca9ec9cf | 27 | #include <cstdint> |
55043100 | 28 | #include <functional> |
a179db20 | 29 | #include <optional> |
2354adc2 | 30 | #include <string> |
cd4e26df | 31 | #include <utility> |
213d9883 OL |
32 | |
33 | class Config; | |
34 | class Context; | |
213d9883 OL |
35 | |
36 | class InodeCache | |
37 | { | |
38 | public: | |
561be208 JR |
39 | // Specifies in which mode a file was hashed since the hash result does not |
40 | // only depend on the actual content but also on operations that were | |
41 | // performed that affect the return value. For example, source code files are | |
42 | // normally scanned for macros while binary files are not. | |
213d9883 | 43 | enum class ContentType { |
561be208 JR |
44 | // The file was not scanned for temporal macros. |
45 | raw = 0, | |
46 | // The file was checked for temporal macros (see check_for_temporal_macros | |
47 | // in hashutil). | |
48 | checked_for_temporal_macros = 1, | |
213d9883 OL |
49 | }; |
50 | ||
3b6c2a5a JR |
51 | // `min_age` specifies how old a file must be to be put in the cache. The |
52 | // reason for this is that there is a race condition that consists of these | |
53 | // events: | |
54 | // | |
55 | // 1. A file is written with content C1, size S and timestamp (ctime/mtime) T. | |
56 | // 2. Ccache hashes the file content and asks the inode cache to store the | |
c77a6558 | 57 | // digest with a hash of S and T (and some other data) as the key. |
3b6c2a5a JR |
58 | // 3. The file is quickly thereafter written with content C2 without changing |
59 | // size S and timestamp T. The timestamp is not updated since the file | |
60 | // writes are made within a time interval smaller than the granularity of | |
61 | // the clock used for file system timestamps. At the time of writing, a | |
62 | // common granularity on a Linux system is 0.004 s (250 Hz). | |
63 | // 4. The inode cache is asked for the file digest and the inode cache | |
64 | // delivers a digest of C1 even though the file's content is C2. | |
65 | // | |
66 | // To avoid the race condition, the inode cache only caches inodes whose | |
67 | // timestamp was updated more than `min_age` ago. The default value is a | |
68 | // conservative 2 seconds since not all file systems have subsecond | |
69 | // resolution. | |
70 | InodeCache(const Config& config, util::Duration min_age = util::Duration(2)); | |
213d9883 OL |
71 | ~InodeCache(); |
72 | ||
5edcc6c3 JR |
73 | // Return whether it's possible to use the inode cache on the filesystem |
74 | // associated with `fd`. | |
75 | static bool available(int fd); | |
76 | ||
213d9883 | 77 | // Get saved hash digest and return value from a previous call to |
561be208 | 78 | // do_hash_file() in hashutil.cpp. |
cd4e26df JR |
79 | std::optional<std::pair<HashSourceCodeResult, Hash::Digest>> |
80 | get(const std::string& path, ContentType type); | |
213d9883 | 81 | |
561be208 JR |
82 | // Put hash digest and return value from a successful call to do_hash_file() |
83 | // in hashutil.cpp. | |
213d9883 OL |
84 | // |
85 | // Returns true if values could be stored in the cache, false otherwise. | |
2292fef1 | 86 | bool put(const std::string& path, |
213d9883 | 87 | ContentType type, |
0e4e4b63 | 88 | const Hash::Digest& file_digest, |
38ab9d38 | 89 | HashSourceCodeResult return_value); |
213d9883 OL |
90 | |
91 | // Unmaps the current cache and removes the mapped file from disk. | |
92 | // | |
93 | // Returns true on success, false otherwise. | |
94 | bool drop(); | |
95 | ||
96 | // Returns name of the persistent file. | |
97 | std::string get_file(); | |
98 | ||
99 | // Returns total number of cache hits. | |
100 | // | |
101 | // Counters are incremented in debug mode only. | |
102 | int64_t get_hits(); | |
103 | ||
104 | // Returns total number of cache misses. | |
105 | // | |
106 | // Counters are incremented in debug mode only. | |
107 | int64_t get_misses(); | |
108 | ||
109 | // Returns total number of errors. | |
110 | // | |
111 | // Currently only lock errors will be counted, since the counter is not | |
112 | // accessible before the file has been successfully mapped into memory. | |
113 | // | |
114 | // Counters are incremented in debug mode only. | |
115 | int64_t get_errors(); | |
116 | ||
117 | private: | |
118 | struct Bucket; | |
119 | struct Entry; | |
120 | struct Key; | |
121 | struct SharedRegion; | |
55043100 | 122 | using BucketHandler = std::function<void(Bucket* bucket)>; |
213d9883 OL |
123 | |
124 | bool mmap_file(const std::string& inode_cache_file); | |
0e4e4b63 JR |
125 | |
126 | bool | |
127 | hash_inode(const std::string& path, ContentType type, Hash::Digest& digest); | |
128 | ||
129 | bool with_bucket(const Hash::Digest& key_digest, | |
55043100 | 130 | const BucketHandler& bucket_handler); |
0e4e4b63 | 131 | |
17f00366 | 132 | static bool create_new_file(const std::string& filename); |
0e4e4b63 | 133 | |
213d9883 OL |
134 | bool initialize(); |
135 | ||
136 | const Config& m_config; | |
3b6c2a5a | 137 | util::Duration m_min_age; |
54cbb06a | 138 | util::Fd m_fd; |
77bf7bc3 JR |
139 | struct SharedRegion* m_sr = nullptr; |
140 | bool m_failed = false; | |
95e63758 | 141 | const pid_t m_self_pid; |
de637952 | 142 | util::TimePoint m_last_fs_space_check; |
213d9883 | 143 | }; |