diff --git a/classes/page_group.php b/classes/page_group.php
index 6d658e3..79438b1 100644
--- a/classes/page_group.php
+++ b/classes/page_group.php
@@ -144,7 +144,7 @@ protected function update_cache() {
* @param profile $profile The profile to pull the information from.
* @param int|null $month The month to record the profile under, or null to use the current month.
*/
- public static function record_fuzzy_counts(profile $profile, ?int $month = null) {
+ public static function record_fuzzy_counts(profile $profile, ?int $month = null, $retry = true) {
// Do this only if both auto profiling and fuzzy counting is set.
if (!get_config('tool_excimer', 'enable_auto') ||
!get_config('tool_excimer', 'enable_fuzzy_count')) {
@@ -183,7 +183,17 @@ public static function record_fuzzy_counts(profile $profile, ?int $month = null)
$pagegroup->set('fuzzydurationsum', $fuzzydurationsum);
if ($existing != $pagegroup->to_record()) {
- $pagegroup->save();
+ try {
+ $pagegroup->save();
+ } catch (\dml_exception $e) {
+ // We have a minor loss in data with concurrent updates that can cause duplicate rows.
+ // When creating new page groups we can catch unique key errors and then retry an update.
+ // Updates are harder to detect, but will only occur when fuzzycount is low, so can ignore.
+ if (!$pagegroupexisted && $retry) {
+ // One retry should be enough to resolve unique key errors.
+ self::record_fuzzy_counts($profile, $month, false);
+ }
+ }
}
}
diff --git a/db/install.xml b/db/install.xml
index 6718108..7a9398b 100755
--- a/db/install.xml
+++ b/db/install.xml
@@ -70,6 +70,9 @@
+
+
+
diff --git a/db/upgrade.php b/db/upgrade.php
index 90b081a..b6210c4 100644
--- a/db/upgrade.php
+++ b/db/upgrade.php
@@ -490,5 +490,55 @@ function xmldb_tool_excimer_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2024050700, 'tool', 'excimer');
}
+ if ($oldversion < 2024082300) {
+
+ // Find all non-unique page groups and remove duplicates.
+ $sql = "
+ SELECT id, name, month, fuzzycount
+ FROM {tool_excimer_page_groups} pg
+ WHERE (pg.name, pg.month) IN (
+ SELECT name, month
+ FROM {tool_excimer_page_groups}
+ GROUP BY name, month
+ HAVING COUNT(*) > 1
+ )
+ ORDER BY name, month, fuzzycount DESC
+ ";
+ $duplicates = $DB->get_records_sql($sql);
+
+ if (!empty($duplicates)) {
+ $previouskey = '';
+ $removeids = [];
+
+ // Duplicates are ordered, so only keep the first occurence.
+ foreach ($duplicates as $row) {
+ $key = $row->name . '_' . $row->month;
+ if ($key === $previouskey) {
+ $removeids[] = $row->id;
+ } else {
+ $previouskey = $key;
+ }
+ }
+
+ // Remove the duplicate rows.
+ if (!empty($removeids)) {
+ $removeids = implode(',', $removeids);
+ $DB->delete_records_select('tool_excimer_page_groups', "id IN ($removeids)");
+ }
+ }
+
+ // Define index pagegroup (unique) to be added to tool_excimer_page_groups.
+ $table = new xmldb_table('tool_excimer_page_groups');
+ $index = new xmldb_index('pagegroup', XMLDB_INDEX_UNIQUE, ['name', 'month']);
+
+ // Conditionally launch add index pagegroup.
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Excimer savepoint reached.
+ upgrade_plugin_savepoint(true, 2024082300, 'tool', 'excimer');
+ }
+
return true;
}
diff --git a/version.php b/version.php
index ec97d7c..6e9869a 100644
--- a/version.php
+++ b/version.php
@@ -25,8 +25,8 @@
defined('MOODLE_INTERNAL') || die();
-$plugin->version = 2024052400;
-$plugin->release = 2024052400;
+$plugin->version = 2024082300;
+$plugin->release = 2024082300;
$plugin->requires = 2017051500; // Moodle 3.3 for Totara support.
$plugin->supported = [35, 401]; // Supports Moodle 3.5 or later.
// TODO $plugin->incompatible = ; // Available as of Moodle 3.9.0 or later.