Skip to content

Commit

Permalink
Cache last update time and do no db queries for that
Browse files Browse the repository at this point in the history
  • Loading branch information
PM84 committed May 10, 2024
1 parent a80d7b6 commit 1205b01
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 159 deletions.
150 changes: 68 additions & 82 deletions classes/helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,7 @@ public function set_tool_config(object|int $pageorid, string $name, string $valu

// Lastupdated timestamp hast to be reset in cache.
$this->clear_caches($page->id);
$this->notify_data_changed($page, 'settings');
}

/**
Expand Down Expand Up @@ -1135,8 +1136,8 @@ public function store_answer(
$this->clear_caches($pageid);
$this->get_answers($table, $pageid, $answercolumn);
$this->get_answers_grouped($table, ['pageid' => $pageid], $answercolumn);
$this->get_page_last_update_time($pageid, true);
$this->get_page_last_update_time($pageid, false);
$this->notify_data_changed($this->get_page($pageid), 'answers', true);
$this->notify_data_changed($this->get_page($pageid), 'answers', false);
return $answerids;
}

Expand All @@ -1161,6 +1162,7 @@ public function delete_all_answers(string $table, int $pageid): bool {
$params = ['pageid' => $pageid];
$return = $DB->delete_records($table, $params);
$this->clear_caches($pageid);
$this->notify_data_changed($this->get_page($pageid), 'answers');
return $return;
}

Expand Down Expand Up @@ -1197,6 +1199,7 @@ public function delete_single_answer(string $table, int $pageid, int $answerid):
$params = ['pageid' => $pageid, 'id' => $answerid];
$return = $DB->delete_records($table, $params);
$this->clear_caches($pageid);
$this->notify_data_changed($this->get_page($pageid), 'answers');
return $return;
}

Expand Down Expand Up @@ -1235,6 +1238,7 @@ public function delete_answers_of_user(string $table, int $pageid, int $userid):
$params = ['pageid' => $pageid, $toolhelper->get_answer_userid_column() => $userid];
$return = $DB->delete_records($table, $params);
$this->clear_caches($pageid);
$this->notify_data_changed($page, 'answers');
return $return;
}

Expand Down Expand Up @@ -1324,112 +1328,101 @@ public function get_answers_grouped(string $table, array $params, string $answer
}

/**
* Get the lastupdated timestamp.
* Notify, that data changed. This sets a new timestamp to the cache.
* Clients then knew, there is someting new, and they have to update this.
*
* @param int|object $pageorid
* @param object $page
* @param string $identifier
* @param bool $ignoreanswers
* @return mixed
* @return void
*/
public function get_page_last_update_time(int|object $pageorid, bool $ignoreanswers = false): string|int {
global $USER;

$page = $pageorid;
if (!is_object($page)) {
$page = $this->get_page($page);
}

if (empty($page)) {
return 0;
}

// We only want to deliver results if the teacher allowed to view it.
$instance = self::get_instance_by_pageid($page->id);
$cm = self::get_cm_by_instance($instance);
if (
empty($this->get_tool_config($page->id, 'showonteacherpermission'))
&& !has_capability('mod/mootimeter:moderator', \context_module::instance($cm->id))
) {
return 0;
}
public function notify_data_changed(object $page, string $identifier = '', bool $ignoreanswers = false): void {

$settingslastupdated = $this->get_lastupdate_tool_settings($page);
$answerslastupdated = $this->get_lastupdate_answers($page, $ignoreanswers);

return $settingslastupdated + $answerslastupdated;
$cache = \cache::make('mod_mootimeter', 'lastupdated');
$cachekey = 'lastupdate_' . $identifier . '_' . (int) $ignoreanswers . '_' . $page->id;
\local_debugger\performance\debugger::print_debug_backtrace('test', 'data changed_' . $identifier, time());
$cache->set($cachekey, time());
}

/**
* Get the last updated timestamp of the answers.
* Get the recent data changed timestamp
*
* @param object $page
* @param string $identifier
* @param bool $ignoreanswers
* @return int
* @throws coding_exception
*/
public function get_lastupdate_answers(object $page, bool $ignoreanswers = false): int {
$classname = "\mootimetertool_" . $page->tool . "\\" . $page->tool;
if (!class_exists($classname)) {
return "Class '" . $page->tool . "' is missing in tool " . $page->tool;
}

$toolhelper = new $classname();
if (!method_exists($toolhelper, 'get_last_update_time')) {
return "Method 'get_last_update_time' is missing in tools helper class " . $page->tool;
}
public function get_data_changed(object $page, string $identifier = '', bool $ignoreanswers = false): int {

$cache = \cache::make('mod_mootimeter', 'lastupdated');
$cachekey = 'lastupdate_answers_' . (int) $ignoreanswers . '_' . $page->id;
$answerslastupdated = $cache->get($cachekey);

if (empty($answerslastupdated)) {
$answerslastupdated = $toolhelper->get_last_update_time($page->id, $ignoreanswers);
$cache->set($cachekey, $answerslastupdated);
}
$cachekey = 'lastupdate_' . $identifier . '_' . (int) $ignoreanswers . '_' . $page->id;
\local_debugger\performance\debugger::print_debug_backtrace('test', 'get data changed_' . $identifier, $cache->get($cachekey));

return $answerslastupdated;
return (int) $cache->get($cachekey);
}

/**
* Get the most recent timestamp of tool settings.
* Get the lastupdated timestamp.
*
* @param object $page
* @return int
* @throws coding_exception
* @param int|object $pageorid
* @param bool $ignoreanswers
* @return mixed
*/
public function get_lastupdate_tool_settings(object $page): int {
global $DB;
public function get_page_last_update_time(
int|object $pageorid,
string $identifier = '',
bool $ignoreanswers = false
): string|int {

$cache = \cache::make('mod_mootimeter', 'lastupdated');
$cachekey = 'lastupdate_settings_' . $page->id;
$mostrecenttimesettings = $cache->get($cachekey);

if (empty($mostrecenttimesettings)) {
// Make the settings change test in the global helper class. Because its everywhere the same.
// It's important, that the default value is NOT null, but 0 instead. Otherwise GREATEST will return null anyway.
$sql = 'SELECT MAX(timemodified) as time FROM {mootimeter_tool_settings} WHERE pageid = :pageid';
$record = $DB->get_record_sql($sql, ['pageid' => $page->id]);

$mostrecenttimesettings = 0;
if (!empty($record)) {
$mostrecenttimesettings = $record->time;
}
if (!in_array($identifier, ['settings', 'answers', ''])) {
throw new moodle_exception(
'generalexceptionmessage',
'error',
'',
get_string("cacheidentifiernotallowed", "mootimeter") . " => " . $identifier
);
}

if (is_object($pageorid)) {
$page = $pageorid;
} else {
$page = $this->get_page($pageorid);
}

$mostrecenttimesettings = max($page->timemodified, $page->timecreated, $mostrecenttimesettings);
$cache->set($cachekey, $mostrecenttimesettings);
// We only want to deliver results if the teacher allowed to view it.
$instance = self::get_instance_by_pageid($page->id);
$cm = self::get_cm_by_instance($instance);
if (
empty($this->get_tool_config($page->id, 'showonteacherpermission'))
&& !has_capability('mod/mootimeter:moderator', \context_module::instance($cm->id))
) {
return 0;
}

if (empty($identifier)) {
$lastupdatesettings = (int) $this->get_data_changed($page, 'settings');
$lastupdateanswers = (int) $this->get_data_changed($page, 'answers', $ignoreanswers);
return max($lastupdatesettings, $lastupdateanswers);
}

return $mostrecenttimesettings;

return (int) $this->get_data_changed($page, $identifier, $ignoreanswers);
}

/**
* Get the teacherpermission to view state.
*
* @param object $page
* @param object|bool $page
* @return int
* @throws dml_exception
* @throws coding_exception
*/
public function get_teacherpermission_to_view(object $page): int {
public function get_teacherpermission_to_view(object|bool $page): int {

// On empty page, there are no permissions needed. This is normally the case, if a new page is added.
if (empty($page)) {
return 0;
}

$instance = self::get_instance_by_pageid($page->id);
$cm = self::get_cm_by_instance($instance);
Expand All @@ -1456,13 +1449,6 @@ public function clear_caches(int $pageid): void {
$cache = \cache::make('mod_mootimeter', 'answers');
$cache->delete('answers_' . $pageid);
$cache->delete('cnt_' . $pageid);

$cache = \cache::make('mod_mootimeter', 'lastupdated');
$cache->delete('lastupdate_settings_' . $pageid);
// Lastupdate timestamp with answers.
$cache->delete('lastupdate_answers_0_' . $pageid);
// Lastupdate timestamp without answers.
$cache->delete('lastupdate_answers_1_' . $pageid);
}

/**
Expand Down
6 changes: 3 additions & 3 deletions classes/local/pagelist.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public function get_pagelist_params(int $cmid, int $pageidselected, object $data
'tooltip' => mb_strimwidth($helper::get_tool_config($pagerow, 'question'), 0, 40, '...'),
];

$pageupdatedat = $helper->get_lastupdate_tool_settings($pagerow);
$pageupdatedat = $helper->get_page_last_update_time($temppages['pageid'], 'settings');
$maxtimecreated = max($maxtimecreated, $pageupdatedat);

$pagenumber++;
Expand All @@ -111,9 +111,9 @@ public function get_pagelist_params(int $cmid, int $pageidselected, object $data
// We have to distinguish from which page the request comes.
// We differentiate between the standard content page (question page) and other pages (eg. results and overview page).
if (empty($dataset->r) && empty($dataset->o)) {
$temppages['dataset']['contentchangedat'] = $helper->get_page_last_update_time($temppages['pageid'], true);
$temppages['dataset']['contentchangedat'] = $helper->get_page_last_update_time($temppages['pageid'], '', true);
} else {
$temppages['dataset']['contentchangedat'] = $helper->get_page_last_update_time($temppages['pageid']);
$temppages['dataset']['contentchangedat'] = $helper->get_page_last_update_time($temppages['pageid'], '');
}
\mod_mootimeter\local\mootimeterstate::add_mootimeterstate('contentchangedat', $temppages['dataset']['contentchangedat']);

Expand Down
9 changes: 0 additions & 9 deletions classes/toolhelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,6 @@ public function get_answer_userid_column(): ?string {
*/
abstract public function insert_answer(object $page, $answer);

/**
* Get the timestamp of the last answer.
*
* @param int|object $pageorid
* @param bool $ignoreanswers
* @return int
*/
abstract public function get_last_update_time(int|object $pageorid, bool $ignoreanswers = false);

/**
* Delete Page
*
Expand Down
1 change: 1 addition & 0 deletions lang/de/mootimeter.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
$string['anonymousmode'] = 'Anonymer Modus';
$string['anonymousmode_desc'] = ' - Dieses Setting kann nicht verändert werden, sobald Antworten existieren';
$string['cachedef_answers'] = 'Enthält die Antworten für die Seiten.';
$string['cacheidentifiernotallowed'] = 'Der verwendete Cache Identifier ist hier nicht zulässig.';
$string['cannotview'] = 'Sie haben keine Berechtigung, auf diese Seite zuzugreifen!';
$string['createnewpagesettings'] = 'Neue Seiteneinstellungen';
$string['default_new_page_visibility'] = 'Neue Seiten standardmäßig sichtbar';
Expand Down
1 change: 1 addition & 0 deletions lang/en/mootimeter.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
$string['anonymousmode'] = 'If checked, teachers can not view voters names.';
$string['anonymousmode_desc'] = 'This setting can not be changed when answers exist!';
$string['cachedef_answers'] = 'Contains the pages answers.';
$string['cacheidentifiernotallowed'] = 'The used cache identifier is not allowed here.';
$string['cannotview'] = 'You are not allowed to access this page!';
$string['createnewpagesettings'] = 'New page settings';
$string['default_new_page_visibility'] = 'New pages visible by default';
Expand Down
36 changes: 1 addition & 35 deletions tools/quiz/classes/quiz.php
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ public function get_result_params_chartjs(int|object $pageorid): array {
'labels' => json_encode($labels),
'values' => json_encode($values),
'question' => self::get_tool_config($page, 'question'),
'lastupdated' => $this->get_page_last_update_time($page->id),
'lastupdated' => $this->get_page_last_update_time($page->id, ''),
'teacherpermissiontoview' => $this->get_teacherpermission_to_view($page),
];

Expand Down Expand Up @@ -827,40 +827,6 @@ public function delete_answers_tool(object $page, array $conditions): void {
$this->clear_caches($page->id);
}

/**
* Get the lastupdated timestamp.
*
* @param int|object $pageorid
* @param bool $ignoreanswers
* @return int
*/
public function get_last_update_time(int|object $pageorid, bool $ignoreanswers = false): int {
global $DB;

$page = $pageorid;
if (!is_object($page)) {
$page = $this->get_page($page);
}

$mostrecenttimeanswer = 0;
if (!$ignoreanswers) {
// It's important, that the default value is NOT null, but 0 instead. Otherwise GREATEST will return null anyway.
$sql = 'SELECT SUM(GREATEST(timecreated, timemodified)) as time FROM '
. '{' . $this->get_answer_table() . '} WHERE pageid = :pageid';
$queryresultanswer = $DB->get_field_sql($sql, ['pageid' => $page->id]);
$mostrecenttimeanswer = !is_null($queryresultanswer) ? $queryresultanswer : 0;
}

// It's important, that the default value is NOT null, but 0 instead. Otherwise GREATEST will return null anyway.
$mostrecenttimeoptions = 0;
$sql = 'SELECT SUM(GREATEST(timecreated, timemodified)) as time FROM '
. '{' . $this->get_answer_option_table() . '} WHERE pageid = :pageid';
$queryresultoptions = $DB->get_field_sql($sql, ['pageid' => $page->id]);
$mostrecenttimeoptions = !is_null($queryresultoptions) ? $queryresultoptions : 0;

return $mostrecenttimeanswer + $mostrecenttimeoptions;
}

/**
* Get array of counted values for each answer/ option.
* @param int $pageid
Expand Down
2 changes: 1 addition & 1 deletion tools/wordcloud/classes/external/get_answers.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ public static function execute(int $pageid, int $lastupdated): array {
require_capability('mod/mootimeter:view', $cmcontext);

$wordcloud = new wordcloud();
$lastupdatednew = $wordcloud->get_page_last_update_time($pageid);
$lastupdatednew = $wordcloud->get_page_last_update_time($pageid, 'answers');

$answerlist = $wordcloud->get_answerlist_wordcloud($pageid);

Expand Down
29 changes: 0 additions & 29 deletions tools/wordcloud/classes/wordcloud.php
Original file line number Diff line number Diff line change
Expand Up @@ -420,35 +420,6 @@ public function get_col_settings_tool_params(object $page, array $params = []) {
return $returnparams;
}

/**
* Get the lastupdated timestamp.
*
* @param int|object $pageorid
* @param bool $ignoreanswers
* @return int
*/
public function get_last_update_time(int|object $pageorid, bool $ignoreanswers = false): int {
global $DB;

$page = $pageorid;
if (!is_object($page)) {
$page = $this->get_page($page);
}

$instance = self::get_instance_by_pageid($page->id);
$cm = self::get_cm_by_instance($instance);

$mostrecenttimeanswer = 0;
if (!$ignoreanswers) {
$sql = 'SELECT SUM(GREATEST(timecreated, timemodified)) as time FROM '
. '{' . self::ANSWER_TABLE . '} WHERE pageid = :pageid';
$queryresult = $DB->get_field_sql($sql, ['pageid' => $page->id]);
$mostrecenttimeanswer = !is_null($queryresult) ? $queryresult : 0;
}

return $mostrecenttimeanswer;
}

/**
* Delete all DB entries related to a specific page.
* @param object $page
Expand Down

0 comments on commit 1205b01

Please sign in to comment.