mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-12-29 12:37:40 +01:00
Make separated flat-file read/writes atomic (#2860)
This has become an issue as a result of removing the global per user/group/track IO locks in 478fddc486
This commit is contained in:
parent
d12be01ecd
commit
35f5944d7b
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package me.lucko.luckperms.common.storage.implementation.file;
|
package me.lucko.luckperms.common.storage.implementation.file;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
import me.lucko.luckperms.common.bulkupdate.BulkUpdate;
|
||||||
@ -35,6 +36,7 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
|||||||
import me.lucko.luckperms.common.storage.implementation.file.loader.ConfigurateLoader;
|
import me.lucko.luckperms.common.storage.implementation.file.loader.ConfigurateLoader;
|
||||||
import me.lucko.luckperms.common.storage.implementation.file.watcher.FileWatcher;
|
import me.lucko.luckperms.common.storage.implementation.file.watcher.FileWatcher;
|
||||||
import me.lucko.luckperms.common.storage.misc.NodeEntry;
|
import me.lucko.luckperms.common.storage.misc.NodeEntry;
|
||||||
|
import me.lucko.luckperms.common.util.CaffeineFactory;
|
||||||
import me.lucko.luckperms.common.util.Iterators;
|
import me.lucko.luckperms.common.util.Iterators;
|
||||||
import me.lucko.luckperms.common.util.MoreFiles;
|
import me.lucko.luckperms.common.util.MoreFiles;
|
||||||
import me.lucko.luckperms.common.util.Uuids;
|
import me.lucko.luckperms.common.util.Uuids;
|
||||||
@ -53,6 +55,8 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -75,6 +79,8 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage {
|
|||||||
private FileWatcher.WatchedLocation watcher;
|
private FileWatcher.WatchedLocation watcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final LoadingCache<Path, ReentrantLock> ioLocks;
|
||||||
|
|
||||||
public SeparatedConfigurateStorage(LuckPermsPlugin plugin, String implementationName, ConfigurateLoader loader, String fileExtension, String dataFolderName) {
|
public SeparatedConfigurateStorage(LuckPermsPlugin plugin, String implementationName, ConfigurateLoader loader, String fileExtension, String dataFolderName) {
|
||||||
super(plugin, implementationName, loader, dataFolderName);
|
super(plugin, implementationName, loader, dataFolderName);
|
||||||
this.fileExtension = fileExtension;
|
this.fileExtension = fileExtension;
|
||||||
@ -89,6 +95,10 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage {
|
|||||||
fileGroups.put(StorageLocation.GROUPS, this.groups);
|
fileGroups.put(StorageLocation.GROUPS, this.groups);
|
||||||
fileGroups.put(StorageLocation.TRACKS, this.tracks);
|
fileGroups.put(StorageLocation.TRACKS, this.tracks);
|
||||||
this.fileGroups = ImmutableMap.copyOf(fileGroups);
|
this.fileGroups = ImmutableMap.copyOf(fileGroups);
|
||||||
|
|
||||||
|
this.ioLocks = CaffeineFactory.newBuilder()
|
||||||
|
.expireAfterAccess(10, TimeUnit.MINUTES)
|
||||||
|
.build(key -> new ReentrantLock());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -99,11 +109,17 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ConfigurationNode readFile(Path file) throws IOException {
|
private ConfigurationNode readFile(Path file) throws IOException {
|
||||||
|
ReentrantLock lock = Objects.requireNonNull(this.ioLocks.get(file));
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
if (!Files.exists(file)) {
|
if (!Files.exists(file)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.loader.loader(file).load();
|
return this.loader.loader(file).load();
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -114,12 +130,18 @@ public class SeparatedConfigurateStorage extends AbstractConfigurateStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void saveFile(Path file, ConfigurationNode node) throws IOException {
|
private void saveFile(Path file, ConfigurationNode node) throws IOException {
|
||||||
|
ReentrantLock lock = Objects.requireNonNull(this.ioLocks.get(file));
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
if (node == null) {
|
if (node == null) {
|
||||||
Files.deleteIfExists(file);
|
Files.deleteIfExists(file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loader.loader(file).save(node);
|
this.loader.loader(file).save(node);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path getDirectory(StorageLocation location) {
|
private Path getDirectory(StorageLocation location) {
|
||||||
|
Loading…
Reference in New Issue
Block a user