-
-
Notifications
You must be signed in to change notification settings - Fork 882
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Schematic caching system for suggestions #2542
base: master
Are you sure you want to change the base?
Conversation
- Resolve first batch of review comments - Renamed Schematic to SchematicPath - Removed custom hashCode() and equals() implementations - Added unit-test to make sure it behaves as expected
Co-authored-by: Octavia Togami <[email protected]>
cf27d60
to
ff6393e
Compare
private static final java.util.regex.Pattern SAFE_FILENAME_REGEX = java.util.regex.Pattern.compile("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+\\.[A-Za-z0-9]+$"); | ||
|
||
private boolean checkFilename(String filename) { | ||
return filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+\\.[A-Za-z0-9]+$"); | ||
return SAFE_FILENAME_REGEX.matcher(filename).matches(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This set of characters doesn't make sense, it's not safe for windows (contains ?
, *
, doesn't ban COM and others), and POSIX will generally take anything. It also excludes extended Unicode characters for some reason, despite those being perfectly fine.
Can we just drop checking this aside from "you must have an extension", i.e. ^.+\..+$
?
public static Optional<RecursiveDirectoryWatcher> create(Path root) throws IOException { | ||
try { | ||
WatchService watchService = root.getFileSystem().newWatchService(); | ||
return Optional.of(new RecursiveDirectoryWatcher(root, watchService)); | ||
} catch (UnsupportedOperationException ignored) { | ||
return Optional.empty(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not bother with the Optional
path here. We're not currently dealing with non-default Path
providers, and I don't expect to any time soon. Quote from the Javadocs of newWatchService
:
This exception is not thrown by FileSystems created by the default provider.
So, let's remove the Optional
and just throw.
public static Optional<RecursiveDirectoryWatcher> create(Path root) throws IOException { | |
try { | |
WatchService watchService = root.getFileSystem().newWatchService(); | |
return Optional.of(new RecursiveDirectoryWatcher(root, watchService)); | |
} catch (UnsupportedOperationException ignored) { | |
return Optional.empty(); | |
} | |
} | |
public static RecursiveDirectoryWatcher create(Path root) throws IOException { | |
WatchService watchService; | |
try { | |
watchService = root.getFileSystem().newWatchService(); | |
} catch (UnsupportedOperationException e) { | |
throw new IllegalArgumentException("Root must support file watching", new RecursiveDirectoryWatcher(root, watchService)); | |
} | |
return new RecursiveDirectoryWatcher(root, watchService); | |
} |
private void createFallbackBackend() { | ||
LOGGER.warn("Failed to initialize file-monitoring based schematics backend. Falling back to polling."); | ||
backend = PollingSchematicsBackend.create(schematicsDir); | ||
} | ||
|
||
private void setupBackend() { | ||
try { | ||
var fileWatcherBackend = FileWatcherSchematicsBackend.create(schematicsDir); | ||
if (fileWatcherBackend.isPresent()) { | ||
backend = fileWatcherBackend.get(); | ||
} else { | ||
createFallbackBackend(); | ||
} | ||
} catch (IOException e) { | ||
createFallbackBackend(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming that my Optional
-removing suggestion is accepted, let's clean this up too:
private void createFallbackBackend() { | |
LOGGER.warn("Failed to initialize file-monitoring based schematics backend. Falling back to polling."); | |
backend = PollingSchematicsBackend.create(schematicsDir); | |
} | |
private void setupBackend() { | |
try { | |
var fileWatcherBackend = FileWatcherSchematicsBackend.create(schematicsDir); | |
if (fileWatcherBackend.isPresent()) { | |
backend = fileWatcherBackend.get(); | |
} else { | |
createFallbackBackend(); | |
} | |
} catch (IOException e) { | |
createFallbackBackend(); | |
} | |
} | |
private void setupBackend() { | |
try { | |
backend = FileWatcherSchematicsBackend.create(schematicsDir); | |
} catch (IOException e) { | |
LOGGER.warn("Failed to initialize file-monitoring based schematics backend. Falling back to polling.", e); | |
backend = PollingSchematicsBackend.create(schematicsDir); | |
} | |
} |
setupBackend(); | ||
} catch (IOException e) { | ||
LOGGER.warn("Failed to create schematics directory", e); | ||
backend = new DummySchematicsBackend(); //fallback to dummy backend |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment isn't needed. It's obvious.
backend = new DummySchematicsBackend(); //fallback to dummy backend | |
backend = new DummySchematicsBackend(); |
schematicsDir = worldEdit.getWorkingDirectoryPath(worldEdit.getConfiguration().saveDir); | ||
Files.createDirectories(schematicsDir); | ||
schematicsDir = schematicsDir.toRealPath(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not set this twice.
schematicsDir = worldEdit.getWorkingDirectoryPath(worldEdit.getConfiguration().saveDir); | |
Files.createDirectories(schematicsDir); | |
schematicsDir = schematicsDir.toRealPath(); | |
Path schematicsDirByConfig = worldEdit.getWorkingDirectoryPath(worldEdit.getConfiguration().saveDir); | |
Files.createDirectories(schematicsDirByConfig); | |
schematicsDir = schematicsDirByConfig.toRealPath(); |
/** | ||
* A backend that never lists any files. | ||
*/ | ||
public class DummySchematicsBackend implements SchematicsBackend { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this backend should throw instead. We're using it as the driving force behind //schem list
now, so if it fails, people shouldn't just get an empty list out, they should get an error. Or possibly, we shouldn't have this at all and should crash out if we have an error setting up.
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); | ||
private final Set<Path> schematics = new HashSet<>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we not using a Sets.newConcurrentHashSet()
? It would work much better since it doesn't need to lock the whole set.
Path schematicRoot = WorldEdit.getInstance().getSchematicsManager().getRoot(); | ||
|
||
this.eventConsumer = eventConsumer; | ||
watchThread = new Thread(() -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just in case, we should check for an existing watchThread
and kill it or throw. Killing requires us to have a means of communicating to it.
} | ||
LOGGER.debug("RecursiveDirectoryWatcher::EventConsumer exited"); | ||
}); | ||
watchThread.setName("RecursiveDirectoryWatcher"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the very least we should identify ourselves fully. Perhaps we should also use a global counter.
watchThread.setName("RecursiveDirectoryWatcher"); | |
watchThread.setName("WorldEdit-RecursiveDirectoryWatcher"); |
This is a continuation of #2212, as the PR is abandoned by its original author