mirror of
https://github.com/sbrl/Pepperminty-Wiki.git
synced 2024-11-22 16:33:00 +00:00
Add parser output caching layer
This commit is contained in:
parent
d51c3f163f
commit
2974966c07
4 changed files with 70 additions and 13 deletions
|
@ -13,6 +13,11 @@ This file holds the changelog for Pepperminty Wiki. This is the master list of t
|
||||||
- All alternative formats for this action are advertised in via a `<link rel="alternate" />` in the `<head>` now
|
- All alternative formats for this action are advertised in via a `<link rel="alternate" />` in the `<head>` now
|
||||||
- Added `count` and `offset` GET parameters to `recent-changes` action.
|
- Added `count` and `offset` GET parameters to `recent-changes` action.
|
||||||
- Added new `find_revisionid_timestamp()` function to `feature-recent-changes` module.
|
- Added new `find_revisionid_timestamp()` function to `feature-recent-changes` module.
|
||||||
|
- Added new parser output caching system!
|
||||||
|
- 2 new settings have been added: `parser_cache` and `parser_cache_min_size`
|
||||||
|
- Uses a hash of the content, the _Pepperminty Wiki_ version, and the parser name as the cache id - so it should never serve stale content (unless you're actively working on particular areas of _Pepperminty Wiki_'s codebase of course)
|
||||||
|
- Useful for longer pages
|
||||||
|
- `parser_cache_min_size` may need tuning for your specific installation (lower it if you regularly use features that are slow to parse; raise if it's the opposite)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Completely reworked the README to refactor out the documentation to its [own static site](https://starbeamrainbowlabs.com/labs/peppermint/_docpress/)
|
- Completely reworked the README to refactor out the documentation to its [own static site](https://starbeamrainbowlabs.com/labs/peppermint/_docpress/)
|
||||||
|
|
|
@ -41,6 +41,8 @@ $guiConfig = <<<'GUICONFIG'
|
||||||
"anonedits": { "type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false },
|
"anonedits": { "type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false },
|
||||||
"maxpagesize": { "type": "number", "description": "The maximum page size in characters.", "default": 135000 },
|
"maxpagesize": { "type": "number", "description": "The maximum page size in characters.", "default": 135000 },
|
||||||
"parser": { "type": "text", "description": "The parser to use when rendering pages. Defaults to an extended version of parsedown (http://parsedown.org/)", "default": "parsedown" },
|
"parser": { "type": "text", "description": "The parser to use when rendering pages. Defaults to an extended version of parsedown (http://parsedown.org/)", "default": "parsedown" },
|
||||||
|
"parser_cache": { "type": "checkbox", "description": "Whether parser output should be cached to speed things up. The cache directory is <code>._cache</code> in the data directory - delete it if you experience issues (unlikely).", "default": true },
|
||||||
|
"parser_cache_min_size": { "type": "number", "description": "The minimum size a source string must be (in bytes) before it's considered eligible for caching.", "default": 1024 },
|
||||||
"interwiki_index_location": { "type": "text", "description": "The location to find the interwiki wiki definition file, which contains a list of wikis along with their names, prefixes, and root urls. May be a URL, or simply a file path - as it's passed to file_get_contents(). If left blank, interwiki link parsing is disabled.", "default": null },
|
"interwiki_index_location": { "type": "text", "description": "The location to find the interwiki wiki definition file, which contains a list of wikis along with their names, prefixes, and root urls. May be a URL, or simply a file path - as it's passed to file_get_contents(). If left blank, interwiki link parsing is disabled.", "default": null },
|
||||||
"clean_raw_html": { "type": "checkbox", "description": "Whether page sources should be cleaned of HTML before rendering. It is STRONGLY recommended that you keep this option turned on.", "default": true},
|
"clean_raw_html": { "type": "checkbox", "description": "Whether page sources should be cleaned of HTML before rendering. It is STRONGLY recommended that you keep this option turned on.", "default": true},
|
||||||
"enable_math_rendering": { "type": "checkbox", "description": "Whether to enable client side rendering of mathematical expressions with MathJax (https://www.mathjax.org/). Math expressions should be enclosed inside of dollar signs ($). Turn off if you don't use it.", "default": true},
|
"enable_math_rendering": { "type": "checkbox", "description": "Whether to enable client side rendering of mathematical expressions with MathJax (https://www.mathjax.org/). Math expressions should be enclosed inside of dollar signs ($). Turn off if you don't use it.", "default": true},
|
||||||
|
@ -411,7 +413,7 @@ if($settings->sessionprefix == "auto")
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
/** The version of Pepperminty Wiki currently running. */
|
/** The version of Pepperminty Wiki currently running. */
|
||||||
$version = "v0.18-dev";
|
$version = "v0.18-dev";
|
||||||
$commit = "c120902cda82e3efcd32d071ad8993c06fdc79ac";
|
$commit = "d51c3f163fbaeed63e8b0109e684a810d2a4604a";
|
||||||
/// Environment ///
|
/// Environment ///
|
||||||
/** Holds information about the current request environment. */
|
/** Holds information about the current request environment. */
|
||||||
$env = new stdClass();
|
$env = new stdClass();
|
||||||
|
@ -2145,10 +2147,15 @@ function add_parser($name, $parser_code)
|
||||||
* The specified parser may (though it's unlikely) render it to other things.
|
* The specified parser may (though it's unlikely) render it to other things.
|
||||||
* @package core
|
* @package core
|
||||||
* @param string $source The source to render.
|
* @param string $source The source to render.
|
||||||
|
* @param string $use_cache Whether to use the on-disk cache. Has no effect if parser caching is disabled in peppermint.json, or the source string is too small.
|
||||||
* @return string The source rendered to HTML.
|
* @return string The source rendered to HTML.
|
||||||
*/
|
*/
|
||||||
function parse_page_source($source) {
|
function parse_page_source($source, $use_cache = true) {
|
||||||
global $settings, $parsers;
|
global $settings, $paths, $parsers, $version;
|
||||||
|
$start_time = microtime(true);
|
||||||
|
|
||||||
|
if(!$settings->parser_cache || strlen($source) < $settings->parser_cache_min_size) $use_cache = false;
|
||||||
|
|
||||||
if(!isset($parsers[$settings->parser]))
|
if(!isset($parsers[$settings->parser]))
|
||||||
exit(page_renderer::render_main("Parsing error - $settings->sitename", "<p>Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact <a href='mailto:" . hide_email($settings->admindetails_email) . "'>" . $settings->admindetails_name . "</a>, your $settings->sitename Administrator."));
|
exit(page_renderer::render_main("Parsing error - $settings->sitename", "<p>Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact <a href='mailto:" . hide_email($settings->admindetails_email) . "'>" . $settings->admindetails_name . "</a>, your $settings->sitename Administrator."));
|
||||||
|
|
||||||
|
@ -2156,7 +2163,26 @@ function parse_page_source($source) {
|
||||||
if($settings->clean_raw_html)
|
if($settings->clean_raw_html)
|
||||||
$source = htmlentities($source, ENT_QUOTES | ENT_HTML5);
|
$source = htmlentities($source, ENT_QUOTES | ENT_HTML5);
|
||||||
*/
|
*/
|
||||||
return $parsers[$settings->parser]($source);
|
|
||||||
|
$cache_id = str_replace(["+","/"], ["-","_"], base64_encode(hash("sha256", "$version|$settings->parser|$source", true)));
|
||||||
|
$cache_file = "{$paths->cache_directory}/{$cache_id}.html";
|
||||||
|
|
||||||
|
$result = null;
|
||||||
|
if($use_cache && file_exists($cache_file)) {
|
||||||
|
$result = file_get_contents($cache_file);
|
||||||
|
$result .= "\n<!-- cache: hit, id: $cache_id, took: " . round((microtime(true) - $start_time)*1000, 5) . "ms -->\n";
|
||||||
|
}
|
||||||
|
if($result == null) {
|
||||||
|
$result = $parsers[$settings->parser]($source);
|
||||||
|
// If we should use the cache and we failed to write to it, warn the admin.
|
||||||
|
// It's not terribible if we can't write to the cache directory (so we shouldn't stop dead & refuse service), but it's still of concern.
|
||||||
|
if($use_cache && !file_put_contents($cache_file, $result))
|
||||||
|
error_log("[Pepperminty Wiki] Warning: Failed to write to cache file $cache_file.");
|
||||||
|
|
||||||
|
$result .= "\n<!-- cache: " . ($use_cache ? "miss" : "n/a") . ", id: $cache_id, took: " . round((microtime(true) - $start_time)*1000, 5) . "ms -->\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to
|
// Function to
|
||||||
|
|
30
core.php
30
core.php
|
@ -1744,10 +1744,15 @@ function add_parser($name, $parser_code)
|
||||||
* The specified parser may (though it's unlikely) render it to other things.
|
* The specified parser may (though it's unlikely) render it to other things.
|
||||||
* @package core
|
* @package core
|
||||||
* @param string $source The source to render.
|
* @param string $source The source to render.
|
||||||
|
* @param string $use_cache Whether to use the on-disk cache. Has no effect if parser caching is disabled in peppermint.json, or the source string is too small.
|
||||||
* @return string The source rendered to HTML.
|
* @return string The source rendered to HTML.
|
||||||
*/
|
*/
|
||||||
function parse_page_source($source) {
|
function parse_page_source($source, $use_cache = true) {
|
||||||
global $settings, $parsers;
|
global $settings, $paths, $parsers, $version;
|
||||||
|
$start_time = microtime(true);
|
||||||
|
|
||||||
|
if(!$settings->parser_cache || strlen($source) < $settings->parser_cache_min_size) $use_cache = false;
|
||||||
|
|
||||||
if(!isset($parsers[$settings->parser]))
|
if(!isset($parsers[$settings->parser]))
|
||||||
exit(page_renderer::render_main("Parsing error - $settings->sitename", "<p>Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact <a href='mailto:" . hide_email($settings->admindetails_email) . "'>" . $settings->admindetails_name . "</a>, your $settings->sitename Administrator."));
|
exit(page_renderer::render_main("Parsing error - $settings->sitename", "<p>Parsing some page source data failed. This is most likely because $settings->sitename has the parser setting set incorrectly. Please contact <a href='mailto:" . hide_email($settings->admindetails_email) . "'>" . $settings->admindetails_name . "</a>, your $settings->sitename Administrator."));
|
||||||
|
|
||||||
|
@ -1755,7 +1760,26 @@ function parse_page_source($source) {
|
||||||
if($settings->clean_raw_html)
|
if($settings->clean_raw_html)
|
||||||
$source = htmlentities($source, ENT_QUOTES | ENT_HTML5);
|
$source = htmlentities($source, ENT_QUOTES | ENT_HTML5);
|
||||||
*/
|
*/
|
||||||
return $parsers[$settings->parser]($source);
|
|
||||||
|
$cache_id = str_replace(["+","/"], ["-","_"], base64_encode(hash("sha256", "$version|$settings->parser|$source", true)));
|
||||||
|
$cache_file = "{$paths->cache_directory}/{$cache_id}.html";
|
||||||
|
|
||||||
|
$result = null;
|
||||||
|
if($use_cache && file_exists($cache_file)) {
|
||||||
|
$result = file_get_contents($cache_file);
|
||||||
|
$result .= "\n<!-- cache: hit, id: $cache_id, took: " . round((microtime(true) - $start_time)*1000, 5) . "ms -->\n";
|
||||||
|
}
|
||||||
|
if($result == null) {
|
||||||
|
$result = $parsers[$settings->parser]($source);
|
||||||
|
// If we should use the cache and we failed to write to it, warn the admin.
|
||||||
|
// It's not terribible if we can't write to the cache directory (so we shouldn't stop dead & refuse service), but it's still of concern.
|
||||||
|
if($use_cache && !file_put_contents($cache_file, $result))
|
||||||
|
error_log("[Pepperminty Wiki] Warning: Failed to write to cache file $cache_file.");
|
||||||
|
|
||||||
|
$result .= "\n<!-- cache: " . ($use_cache ? "miss" : "n/a") . ", id: $cache_id, took: " . round((microtime(true) - $start_time)*1000, 5) . "ms -->\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to
|
// Function to
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
"anonedits": { "type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false },
|
"anonedits": { "type": "checkbox", "description": "Whether users who aren't logged in are allowed to edit your wiki.", "default": false },
|
||||||
"maxpagesize": { "type": "number", "description": "The maximum page size in characters.", "default": 135000 },
|
"maxpagesize": { "type": "number", "description": "The maximum page size in characters.", "default": 135000 },
|
||||||
"parser": { "type": "text", "description": "The parser to use when rendering pages. Defaults to an extended version of parsedown (http://parsedown.org/)", "default": "parsedown" },
|
"parser": { "type": "text", "description": "The parser to use when rendering pages. Defaults to an extended version of parsedown (http://parsedown.org/)", "default": "parsedown" },
|
||||||
|
"parser_cache": { "type": "checkbox", "description": "Whether parser output should be cached to speed things up. The cache directory is <code>._cache</code> in the data directory - delete it if you experience issues (unlikely).", "default": true },
|
||||||
|
"parser_cache_min_size": { "type": "number", "description": "The minimum size a source string must be (in bytes) before it's considered eligible for caching.", "default": 1024 },
|
||||||
"interwiki_index_location": { "type": "text", "description": "The location to find the interwiki wiki definition file, which contains a list of wikis along with their names, prefixes, and root urls. May be a URL, or simply a file path - as it's passed to file_get_contents(). If left blank, interwiki link parsing is disabled.", "default": null },
|
"interwiki_index_location": { "type": "text", "description": "The location to find the interwiki wiki definition file, which contains a list of wikis along with their names, prefixes, and root urls. May be a URL, or simply a file path - as it's passed to file_get_contents(). If left blank, interwiki link parsing is disabled.", "default": null },
|
||||||
"clean_raw_html": { "type": "checkbox", "description": "Whether page sources should be cleaned of HTML before rendering. It is STRONGLY recommended that you keep this option turned on.", "default": true},
|
"clean_raw_html": { "type": "checkbox", "description": "Whether page sources should be cleaned of HTML before rendering. It is STRONGLY recommended that you keep this option turned on.", "default": true},
|
||||||
"enable_math_rendering": { "type": "checkbox", "description": "Whether to enable client side rendering of mathematical expressions with MathJax (https://www.mathjax.org/). Math expressions should be enclosed inside of dollar signs ($). Turn off if you don't use it.", "default": true},
|
"enable_math_rendering": { "type": "checkbox", "description": "Whether to enable client side rendering of mathematical expressions with MathJax (https://www.mathjax.org/). Math expressions should be enclosed inside of dollar signs ($). Turn off if you don't use it.", "default": true},
|
||||||
|
|
Loading…
Reference in a new issue