| ... | ... | @@ -8,6 +8,7 @@ const mem = @import("mem.zig"); |
| 8 | 8 | const fmt = @import("fmt.zig"); |
| 9 | 9 | const Allocator = mem.Allocator; |
| 10 | 10 | const os = @import("os.zig"); |
| 11 | const time = @import("time.zig"); |
| 11 | 12 | |
| 12 | 13 | const base64_encoder = fs.base64_encoder; |
| 13 | 14 | const base64_decoder = fs.base64_decoder; |
| ... | ... | @@ -198,7 +199,10 @@ pub const CacheHash = struct { |
| 198 | 199 | |
| 199 | 200 | cache_hash_file.stat = actual_stat; |
| 200 | 201 | |
| 201 | | // TODO: check for problematic timestamp |
| 202 | if (is_problematic_timestamp(cache_hash_file.stat.mtime)) { |
| 203 | cache_hash_file.stat.mtime = 0; |
| 204 | cache_hash_file.stat.inode = 0; |
| 205 | } |
| 202 | 206 | |
| 203 | 207 | var actual_digest: [BIN_DIGEST_LEN]u8 = undefined; |
| 204 | 208 | try hash_file(self.alloc, &actual_digest, &this_file); |
| ... | ... | @@ -252,7 +256,10 @@ pub const CacheHash = struct { |
| 252 | 256 | |
| 253 | 257 | cache_hash_file.stat = try this_file.stat(); |
| 254 | 258 | |
| 255 | | // TODO: check for problematic timestamp |
| 259 | if (is_problematic_timestamp(cache_hash_file.stat.mtime)) { |
| 260 | cache_hash_file.stat.mtime = 0; |
| 261 | cache_hash_file.stat.inode = 0; |
| 262 | } |
| 256 | 263 | |
| 257 | 264 | try hash_file(self.alloc, &cache_hash_file.bin_digest, &this_file); |
| 258 | 265 | self.blake3.update(&cache_hash_file.bin_digest); |
| ... | ... | @@ -317,6 +324,16 @@ fn hash_file(alloc: *Allocator, bin_digest: []u8, handle: *const fs.File) !void |
| 317 | 324 | blake3.final(bin_digest); |
| 318 | 325 | } |
| 319 | 326 | |
| 327 | /// If the wall clock time, rounded to the same precision as the |
| 328 | /// mtime, is equal to the mtime, then we cannot rely on this mtime |
| 329 | /// yet. We will instead save an mtime value that indicates the hash |
| 330 | /// must be unconditionally computed. |
| 331 | fn is_problematic_timestamp(file_mtime_ns: i64) bool { |
| 332 | const now_ms = time.milliTimestamp(); |
| 333 | const file_mtime_ms = @divFloor(file_mtime_ns, time.millisecond); |
| 334 | return now_ms == file_mtime_ms; |
| 335 | } |
| 336 | |
| 320 | 337 | test "cache file and then recall it" { |
| 321 | 338 | const cwd = fs.cwd(); |
| 322 | 339 | |
| ... | ... | @@ -360,3 +377,13 @@ test "cache file and then recall it" { |
| 360 | 377 | try cwd.deleteTree(temp_manifest_dir); |
| 361 | 378 | try cwd.deleteFile(temp_file); |
| 362 | 379 | } |
| 380 | |
| 381 | test "give problematic timestamp" { |
| 382 | const now_ns = @intCast(i64, time.milliTimestamp() * time.millisecond); |
| 383 | debug.assert(is_problematic_timestamp(now_ns)); |
| 384 | } |
| 385 | |
| 386 | test "give nonproblematic timestamp" { |
| 387 | const now_ns = @intCast(i64, time.milliTimestamp() * time.millisecond) - 1000; |
| 388 | debug.assert(!is_problematic_timestamp(now_ns)); |
| 389 | } |