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