HashCache.java
net.minecraft.data.HashCache
信息
- 全限定名:net.minecraft.data.HashCache
- 类型:public class
- 包:net.minecraft.data
- 源码路径:src/main/java/net/minecraft/data/HashCache.java
- 起始行号:L35
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L36 - 说明:
TODO
- 类型:
-
HEADER_MARKER- 类型:
String - 修饰符:
private static final - 源码定位:
L37 - 说明:
TODO
- 类型:
-
rootDir- 类型:
Path - 修饰符:
private final - 源码定位:
L38 - 说明:
TODO
- 类型:
-
cacheDir- 类型:
Path - 修饰符:
private final - 源码定位:
L39 - 说明:
TODO
- 类型:
-
versionId- 类型:
String - 修饰符:
private final - 源码定位:
L40 - 说明:
TODO
- 类型:
-
caches- 类型:
Map<String,HashCache.ProviderCache> - 修饰符:
private final - 源码定位:
L41 - 说明:
TODO
- 类型:
-
cachesToWrite- 类型:
Set<String> - 修饰符:
private final - 源码定位:
L42 - 说明:
TODO
- 类型:
-
cachePaths- 类型:
Set<Path> - 修饰符:
private final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
initialCount- 类型:
int - 修饰符:
private final - 源码定位:
L44 - 说明:
TODO
- 类型:
-
writes- 类型:
int - 修饰符:
private - 源码定位:
L45 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.data.HashCache.CacheUpdater- 类型:
class - 修饰符:
private static - 源码定位:
L151 - 说明:
TODO
- 类型:
-
net.minecraft.data.HashCache.ProviderCache- 类型:
record - 修饰符:
private - 源码定位:
L189 - 说明:
TODO
- 类型:
-
net.minecraft.data.HashCache.ProviderCacheBuilder- 类型:
record - 修饰符:
private - 源码定位:
L239 - 说明:
TODO
- 类型:
-
net.minecraft.data.HashCache.UpdateFunction- 类型:
interface - 修饰符:
public - 源码定位:
L254 - 说明:
TODO
- 类型:
-
net.minecraft.data.HashCache.UpdateResult- 类型:
record - 修饰符:
public - 源码定位:
L258 - 说明:
TODO
- 类型:
构造器
public HashCache(Path rootDir, Collection<String> providerIds, WorldVersion version) @ L51
- 构造器名:HashCache
- 源码定位:L51
- 修饰符:public
参数:
- rootDir: Path
- providerIds: Collection
- version: WorldVersion
说明:
TODO
方法
下面的方法块按源码顺序生成。
private Path getProviderCachePath(String provider) @ L47
- 方法名:getProviderCachePath
- 源码定位:L47
- 返回类型:Path
- 修饰符:private
参数:
- provider: String
说明:
TODO
private static HashCache.ProviderCache readCache(Path rootDir, Path providerCachePath) @ L71
- 方法名:readCache
- 源码定位:L71
- 返回类型:HashCache.ProviderCache
- 修饰符:private static
参数:
- rootDir: Path
- providerCachePath: Path
说明:
TODO
public boolean shouldRunInThisVersion(String providerId) @ L83
- 方法名:shouldRunInThisVersion
- 源码定位:L83
- 返回类型:boolean
- 修饰符:public
参数:
- providerId: String
说明:
TODO
public CompletableFuture<HashCache.UpdateResult> generateUpdate(String providerId, HashCache.UpdateFunction function) @ L88
- 方法名:generateUpdate
- 源码定位:L88
- 返回类型:CompletableFuture<HashCache.UpdateResult>
- 修饰符:public
参数:
- providerId: String
- function: HashCache.UpdateFunction
说明:
TODO
public void applyUpdate(HashCache.UpdateResult result) @ L98
- 方法名:applyUpdate
- 源码定位:L98
- 返回类型:void
- 修饰符:public
参数:
- result: HashCache.UpdateResult
说明:
TODO
public void purgeStaleAndWrite() @ L104
- 方法名:purgeStaleAndWrite
- 源码定位:L104
- 返回类型:void
- 修饰符:public
参数:
- 无
说明:
TODO
代码
public class HashCache {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String HEADER_MARKER = "// ";
private final Path rootDir;
private final Path cacheDir;
private final String versionId;
private final Map<String, HashCache.ProviderCache> caches;
private final Set<String> cachesToWrite = new HashSet<>();
private final Set<Path> cachePaths = new HashSet<>();
private final int initialCount;
private int writes;
private Path getProviderCachePath(String provider) {
return this.cacheDir.resolve(Hashing.sha1().hashString(provider, StandardCharsets.UTF_8).toString());
}
public HashCache(Path rootDir, Collection<String> providerIds, WorldVersion version) throws IOException {
this.versionId = version.id();
this.rootDir = rootDir;
this.cacheDir = rootDir.resolve(".cache");
Files.createDirectories(this.cacheDir);
Map<String, HashCache.ProviderCache> loadedCaches = new HashMap<>();
int initialCount = 0;
for (String providerId : providerIds) {
Path providerCachePath = this.getProviderCachePath(providerId);
this.cachePaths.add(providerCachePath);
HashCache.ProviderCache providerCache = readCache(rootDir, providerCachePath);
loadedCaches.put(providerId, providerCache);
initialCount += providerCache.count();
}
this.caches = loadedCaches;
this.initialCount = initialCount;
}
private static HashCache.ProviderCache readCache(Path rootDir, Path providerCachePath) {
if (Files.isReadable(providerCachePath)) {
try {
return HashCache.ProviderCache.load(rootDir, providerCachePath);
} catch (Exception var3) {
LOGGER.warn("Failed to parse cache {}, discarding", providerCachePath, var3);
}
}
return new HashCache.ProviderCache("unknown", ImmutableMap.of());
}
public boolean shouldRunInThisVersion(String providerId) {
HashCache.ProviderCache result = this.caches.get(providerId);
return result == null || !result.version.equals(this.versionId);
}
public CompletableFuture<HashCache.UpdateResult> generateUpdate(String providerId, HashCache.UpdateFunction function) {
HashCache.ProviderCache existingCache = this.caches.get(providerId);
if (existingCache == null) {
throw new IllegalStateException("Provider not registered: " + providerId);
} else {
HashCache.CacheUpdater output = new HashCache.CacheUpdater(providerId, this.versionId, existingCache);
return function.update(output).thenApply(unused -> output.close());
}
}
public void applyUpdate(HashCache.UpdateResult result) {
this.caches.put(result.providerId(), result.cache());
this.cachesToWrite.add(result.providerId());
this.writes = this.writes + result.writes();
}
public void purgeStaleAndWrite() throws IOException {
final Set<Path> allowedFiles = new HashSet<>();
this.caches.forEach((providerId, cache) -> {
if (this.cachesToWrite.contains(providerId)) {
Path cachePath = this.getProviderCachePath(providerId);
cache.save(this.rootDir, cachePath, DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(ZonedDateTime.now()) + "\t" + providerId);
}
allowedFiles.addAll(cache.data().keySet());
});
final MutableInt found = new MutableInt();
final MutableInt removed = new MutableInt();
Files.walkFileTree(this.rootDir, new SimpleFileVisitor<Path>() {
{
Objects.requireNonNull(HashCache.this);
}
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
if (HashCache.this.cachePaths.contains(file)) {
return FileVisitResult.CONTINUE;
} else {
found.increment();
if (allowedFiles.contains(file)) {
return FileVisitResult.CONTINUE;
} else {
try {
Files.delete(file);
} catch (IOException var4) {
HashCache.LOGGER.warn("Failed to delete file {}", file, var4);
}
removed.increment();
return FileVisitResult.CONTINUE;
}
}
}
});
LOGGER.info(
"Caching: total files: {}, old count: {}, new count: {}, removed stale: {}, written: {}",
found,
this.initialCount,
allowedFiles.size(),
removed,
this.writes
);
}
private static class CacheUpdater implements CachedOutput {
private final String provider;
private final HashCache.ProviderCache oldCache;
private final HashCache.ProviderCacheBuilder newCache;
private final AtomicInteger writes = new AtomicInteger();
private volatile boolean closed;
private CacheUpdater(String provider, String newVersionId, HashCache.ProviderCache oldCache) {
this.provider = provider;
this.oldCache = oldCache;
this.newCache = new HashCache.ProviderCacheBuilder(newVersionId);
}
private boolean shouldWrite(Path path, HashCode hash) {
return !Objects.equals(this.oldCache.get(path), hash) || !Files.exists(path);
}
@Override
public void writeIfNeeded(Path path, byte[] input, HashCode hash) throws IOException {
if (this.closed) {
throw new IllegalStateException("Cannot write to cache as it has already been closed");
} else {
if (this.shouldWrite(path, hash)) {
this.writes.incrementAndGet();
Files.createDirectories(path.getParent());
Files.write(path, input);
}
this.newCache.put(path, hash);
}
}
public HashCache.UpdateResult close() {
this.closed = true;
return new HashCache.UpdateResult(this.provider, this.newCache.build(), this.writes.get());
}
}
private record ProviderCache(String version, ImmutableMap<Path, HashCode> data) {
public @Nullable HashCode get(Path path) {
return this.data.get(path);
}
public int count() {
return this.data.size();
}
public static HashCache.ProviderCache load(Path rootDir, Path cacheFile) throws IOException {
HashCache.ProviderCache var7;
try (BufferedReader reader = Files.newBufferedReader(cacheFile, StandardCharsets.UTF_8)) {
String header = reader.readLine();
if (!header.startsWith("// ")) {
throw new IllegalStateException("Missing cache file header");
}
String[] headerFields = header.substring("// ".length()).split("\t", 2);
String savedVersionId = headerFields[0];
Builder<Path, HashCode> result = ImmutableMap.builder();
reader.lines().forEach(s -> {
int i = s.indexOf(32);
result.put(rootDir.resolve(s.substring(i + 1)), HashCode.fromString(s.substring(0, i)));
});
var7 = new HashCache.ProviderCache(savedVersionId, result.build());
}
return var7;
}
public void save(Path rootDir, Path cacheFile, String extraHeaderInfo) {
try (BufferedWriter output = Files.newBufferedWriter(cacheFile, StandardCharsets.UTF_8)) {
output.write("// ");
output.write(this.version);
output.write(9);
output.write(extraHeaderInfo);
output.newLine();
for (Entry<Path, HashCode> e : this.data.entrySet()) {
output.write(e.getValue().toString());
output.write(32);
output.write(rootDir.relativize(e.getKey()).toString());
output.newLine();
}
} catch (IOException var9) {
HashCache.LOGGER.warn("Unable write cachefile {}: {}", cacheFile, var9);
}
}
}
private record ProviderCacheBuilder(String version, ConcurrentMap<Path, HashCode> data) {
ProviderCacheBuilder(String version) {
this(version, new ConcurrentHashMap<>());
}
public void put(Path path, HashCode hash) {
this.data.put(path, hash);
}
public HashCache.ProviderCache build() {
return new HashCache.ProviderCache(this.version, ImmutableMap.copyOf(this.data));
}
}
@FunctionalInterface
public interface UpdateFunction {
CompletableFuture<?> update(CachedOutput output);
}
public record UpdateResult(String providerId, HashCache.ProviderCache cache, int writes) {
}
}引用的其他类
- WorldVersion
- 引用位置:
参数
- 引用位置: