Class ConfigFileStore
java.lang.Object
org.frontcache.io.ConfigFileStore
Reads, hashes, backs up and atomically replaces a config file under FRONTCACHE_HOME/conf.
Separate from
FrontCacheIOServlet because every step in here has a way of being silently
wrong, and none of them is about HTTP.-
Method Summary
Modifier and TypeMethodDescriptionstatic StringCopies the current file aside as<name>.backup-<yyyyMMdd_HHmmss>, the namingbackup-indexalready uses for the Lucene index.static StringLowercase hex SHA-256 of the normalized text - thebaseHashthe console sends.static StringMakes submitted text safe to compare and to write.static StringreadOnDisk(File file) The file's current content, or "" when it does not exist yet.static voidReplaces the file's content atomically.
-
Method Details
-
normalize
Makes submitted text safe to compare and to write.CRLF is the one that bites
HTML form submission normalizes a textarea's line breaks to CRLF. Every config file in this project is LF, so without this the very first Save - even with no edit at all - rewrites every line ending in the file:git diffon a version-controlled FRONTCACHE_HOME shows the whole file changed, and the next content hash fails to match text the console itself just posted.The trailing newline is deliberately left alone
Tempting to add one - conf/bots.conf on the e2e standalone node ends without it - and wrong: a browser does not add a trailing newline to a textarea's value, so adding one here would make "save the file unchanged" change the file. Saving must not alter a byte the operator did not alter, both because that is the promise the button makes and because it is what lets the e2e suite assert an exact round trip. -
hash
-
readOnDisk
The file's current content, or "" when it does not exist yet. Deliberately NOTFCConfig.getConfigInputStream: that falls back to the classpath, and what a write has to be compared against is the file on disk it is about to replace. Comparing against a bundled default would let a concurrent edit through.- Throws:
IOException
-
backup
Copies the current file aside as<name>.backup-<yyyyMMdd_HHmmss>, the namingbackup-indexalready uses for the Lucene index.- Returns:
- the backup's file name, or null when there was no file to back up
- Throws:
IOException
-
write
Replaces the file's content atomically.Why not just write the file
A plain write leaves a window in which the file on disk is truncated, and something reads config files at unpredictable moments - a concurrentget-*-config, a concurrent reload, the node's own startup. A truncated conf/guard-rules.conf is a node with no guard rules, which is an outage that lasts until someone reloads it again. The temp file is created in the same directory as the target on purpose:ATOMIC_MOVEacross filesystems throws, and /tmp on a container is routinely a different one.- Throws:
IOException
-