diff --git a/Makefile b/Makefile
index cf232d28..de6eb94f 100644
--- a/Makefile
+++ b/Makefile
@@ -37,9 +37,9 @@ OBJS = swad_account.o swad_action.o swad_agenda.o swad_alert.o \
swad_degree_type.o swad_department.o swad_duplicate.o \
swad_enrolment.o swad_exam.o swad_exam_announcement.o \
swad_exam_event.o swad_exam_result.o \
- swad_figure.o swad_file.o swad_file_browser.o swad_file_extension.o \
- swad_file_MIME.o swad_firewall.o swad_follow.o swad_form.o \
- swad_forum.o \
+ swad_figure.o swad_figure_cache.o swad_file.o swad_file_browser.o \
+ swad_file_extension.o swad_file_MIME.o swad_firewall.o swad_follow.o \
+ swad_form.o swad_forum.o \
swad_game.o swad_global.o swad_group.o \
swad_help.o swad_hierarchy.o swad_hierarchy_config.o swad_holiday.o \
swad_HTML.o \
diff --git a/sql/swad.sql b/sql/swad.sql
index d9ee90cf..a3156176 100644
--- a/sql/swad.sql
+++ b/sql/swad.sql
@@ -598,6 +598,16 @@ CREATE TABLE IF NOT EXISTS expanded_folders (
INDEX(FileBrowser,Cod),
INDEX(WorksUsrCod));
--
+-- Table figures: stores cached figures for quick retrieval of figures (i.e. number of students in the platform)
+--
+CREATE TABLE IF NOT EXISTS figures (
+ Figure INT NOT NULL,
+ Scope ENUM('Sys','Cty','Ins','Ctr','Deg','Crs') NOT NULL DEFAULT 'Sys',
+ Cod INT NOT NULL DEFAULT -1,
+ Value INT NOT NULL,
+ LastUpdate TIMESTAMP,
+ UNIQUE INDEX(Figure,Scope,Cod));
+--
-- Table file_browser_last: stores the last click of every user in each file browser zone
--
CREATE TABLE IF NOT EXISTS file_browser_last (
diff --git a/swad_changelog.h b/swad_changelog.h
index c35a39d8..f5954185 100644
--- a/swad_changelog.h
+++ b/swad_changelog.h
@@ -544,10 +544,16 @@ enscript -2 --landscape --color --file-align=2 --highlight --line-numbers -o - *
En OpenSWAD:
ps2pdf source.ps destination.pdf
*/
-#define Log_PLATFORM_VERSION "SWAD 19.207.4 (2020-04-30)"
+#define Log_PLATFORM_VERSION "SWAD 19.208 (2020-05-01)"
#define CSS_FILE "swad19.193.1.css"
#define JS_FILE "swad19.193.1.js"
/*
+ Version 19.208: May 01, 2020 Optimization in table of last prefs on user-course. (300598 lines)
+ 1 change necessary in database:
+CREATE TABLE IF NOT EXISTS figures (Figure INT NOT NULL,Scope ENUM('Sys','Cty','Ins','Ctr','Deg','Crs') NOT NULL DEFAULT 'Sys',Cod INT NOT NULL DEFAULT -1,Value INT NOT NULL,LastUpdate TIMESTAMP,UNIQUE INDEX(Figure,Scope,Cod));
+ If you want to use MyISAM:
+ALTER TABLE figures ENGINE=MyISAM;
+
Version 19.207.4: Apr 30, 2020 Fixed bug in test result, reported by Mancia Anguita López. (300363 lines)
Version 19.207.3: Apr 30, 2020 Fixed bug removing account. (300335 lines)
Version 19.207.2: Apr 30, 2020 Fixed bug creating account, reported by Antonio Becerra. (300334 lines)
diff --git a/swad_database.c b/swad_database.c
index 7df70036..6a4dd937 100644
--- a/swad_database.c
+++ b/swad_database.c
@@ -1317,13 +1317,24 @@ mysql> DESCRIBE expanded_folders;
/***** Table figures *****/
/*
mysql> DESCRIBE figures;
-
++------------+-------------------------------------------+------+-----+-------------------+-----------------------------+
+| Field | Type | Null | Key | Default | Extra |
++------------+-------------------------------------------+------+-----+-------------------+-----------------------------+
+| Figure | int(11) | NO | PRI | NULL | |
+| Scope | enum('Sys','Cty','Ins','Ctr','Deg','Crs') | NO | PRI | Sys | |
+| Cod | int(11) | NO | PRI | -1 | |
+| Value | int(11) | NO | | NULL | |
+| LastUpdate | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
++------------+-------------------------------------------+------+-----+-------------------+-----------------------------+
+5 rows in set (0.01 sec)
*/
DB_CreateTable ("CREATE TABLE IF NOT EXISTS figures ("
- "Name VARCHAR(32) NOT NULL," // Fig_MAX_BYTES_NAME
+ "Figure INT NOT NULL,"
+ "Scope ENUM('Sys','Cty','Ins','Ctr','Deg','Crs') NOT NULL DEFAULT 'Sys',"
+ "Cod INT NOT NULL DEFAULT -1,"
"Value INT NOT NULL,"
- "CalcTime DATETIME NOT NULL,"
- "UNIQUE INDEX(Name))");
+ "LastUpdate TIMESTAMP,"
+ "UNIQUE INDEX(Figure,Scope,Cod))");
/***** Table file_browser_last *****/
/*
diff --git a/swad_figure.c b/swad_figure.c
index b4bef0e0..32490e05 100644
--- a/swad_figure.c
+++ b/swad_figure.c
@@ -65,8 +65,6 @@ extern struct Globals Gbl;
/***************************** Private constants *****************************/
/*****************************************************************************/
-#define Fig_MAX_BYTES_NAME 32
-
/*****************************************************************************/
/******************************* Private types *******************************/
/*****************************************************************************/
@@ -197,7 +195,6 @@ static void Fig_GetAndShowNumUsrsPerMenu (void);
static void Fig_GetAndShowNumUsrsPerTheme (void);
static void Fig_GetAndShowNumUsrsPerSideColumns (void);
unsigned Fig_GetNumUsrsWhoChoseAnOption (const char *SubQuery);
-bool Fig_GetFigureFromCache (const char *Name);
/*****************************************************************************/
/************************** Show use of the platform *************************/
@@ -5675,13 +5672,3 @@ unsigned Fig_GetNumUsrsWhoChoseAnOption (const char *SubQuery)
return NumUsrs;
}
-
-/*****************************************************************************/
-/************** Get number of users who have chosen an option ****************/
-/*****************************************************************************/
-// Return true is figure is valid (if figure is cached and recently calculated)
-
-bool Fig_GetFigureFromCache (const char *Name)
- {
- return Name[0] ? true : false;
- }
diff --git a/swad_figure_cache.c b/swad_figure_cache.c
new file mode 100644
index 00000000..ba8d6bbe
--- /dev/null
+++ b/swad_figure_cache.c
@@ -0,0 +1,123 @@
+// swad_figure_cache.c: figures (global stats) cached in database
+
+/*
+ SWAD (Shared Workspace At a Distance),
+ is a web platform developed at the University of Granada (Spain),
+ and used to support university teaching.
+
+ This file is part of SWAD core.
+ Copyright (C) 1999-2020 Antonio Cañas Vargas
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see .
+*/
+/*****************************************************************************/
+/********************************* Headers ***********************************/
+/*****************************************************************************/
+
+//#define _GNU_SOURCE // For asprintf
+#include // For sscanf
+//#include // For system, getenv, etc.
+//#include // For string functions
+
+#include "swad_database.h"
+#include "swad_figure_cache.h"
+#include "swad_scope.h"
+
+/*****************************************************************************/
+/************** External global variables from others modules ****************/
+/*****************************************************************************/
+
+// extern struct Globals Gbl;
+
+/*****************************************************************************/
+/***************************** Private constants *****************************/
+/*****************************************************************************/
+
+#define FigCch_TIME_CACHE ((time_t)(1UL * 60UL * 60UL)) // Past these seconds, update cached value
+
+/*****************************************************************************/
+/******************************* Private types *******************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/***************************** Private variables *****************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/****************************** Private prototypes ***************************/
+/*****************************************************************************/
+
+/*****************************************************************************/
+/************** Get number of users who have chosen an option ****************/
+/*****************************************************************************/
+
+void FigCch_UpdateFigureIntoCache (FigCch_FigureCached_t Figure,
+ Hie_Level_t Scope,long Cod,
+ unsigned Value)
+ {
+ /***** Trivial check *****/
+ if (Figure == FigCch_UNKNOWN)
+ return;
+
+ /***** Update figure's value in database *****/
+ DB_QueryREPLACE ("can not update cached figure value",
+ "REPLACE INTO figures"
+ " (Figure,Scope,Cod,Value)"
+ " VALUES"
+ " (%u,'%s',%ld,%u)",
+ (unsigned) Figure,Sco_GetDBStrFromScope (Scope),Cod,Value);
+ }
+
+/*****************************************************************************/
+/************** Get number of users who have chosen an option ****************/
+/*****************************************************************************/
+// Return true is figure is found (if figure is cached and recently updated)
+
+bool FigCch_GetFigureFromCache (FigCch_FigureCached_t Figure,
+ Hie_Level_t Scope,long Cod,
+ unsigned *Value)
+ {
+ MYSQL_RES *mysql_res;
+ MYSQL_ROW row;
+ bool Found = false;
+
+ *Value = 0; // Default value when not found
+
+ /***** Trivial check *****/
+ if (Figure == FigCch_UNKNOWN)
+ return Found;
+
+ /***** Get figure's value if cached and recent *****/
+ if (DB_QuerySELECT (&mysql_res,"can not get cached figure value",
+ "SELECT Value"
+ " FROM figures"
+ " WHERE Figure=%u AND Scope='%s' AND Cod=%ld"
+ " AND LastUpdate.
+*/
+/*****************************************************************************/
+/********************************* Headers ***********************************/
+/*****************************************************************************/
+
+#include // For boolean type
+
+#include "swad_hierarchy.h"
+
+/*****************************************************************************/
+/************************** Public types and constants ***********************/
+/*****************************************************************************/
+
+// If numbers change, clean database table figures: "DELETE FROM figures;"
+typedef enum
+ {
+ FigCch_UNKNOWN = 0, // Unknown figure
+ //--------------------------------------------------------------------------
+ FigCch_NUM_STDS_IN_CRSS = 1, // Number of students in courses
+ FigCch_NUM_NETS_IN_CRSS = 2, // Number of non-editing teachers in courses
+ FigCch_NUM_TCHS_IN_CRSS = 3, // Number of teachers in courses
+ FigCch_NUM_USRS_IN_CRSS = 4, // Number of users in courses
+ //--------------------------------------------------------------------------
+ FigCch_NUM_CTYS = 5, // Number of countries
+ FigCch_NUM_INSS = 6, // Number of institutions
+ FigCch_NUM_CTRS = 7, // Number of centres
+ FigCch_NUM_CTRS_WITH_MAP = 8, // Number of centres with map
+ FigCch_NUM_DEGS = 9, // Number of degrees
+ FigCch_NUM_CRSS = 10, // Number of courses
+ } FigCch_FigureCached_t;
+
+/*****************************************************************************/
+/***************************** Public prototypes *****************************/
+/*****************************************************************************/
+
+void FigCch_UpdateFigureIntoCache (FigCch_FigureCached_t Figure,
+ Hie_Level_t Scope,long Cod,
+ unsigned Value);
+bool FigCch_GetFigureFromCache (FigCch_FigureCached_t Figure,
+ Hie_Level_t Scope,long Cod,
+ unsigned *Value);
+
+#endif
diff --git a/swad_system_config.c b/swad_system_config.c
index 9d279f2e..5c9db82d 100644
--- a/swad_system_config.c
+++ b/swad_system_config.c
@@ -36,6 +36,7 @@
#include "swad_config.h"
#include "swad_course.h"
#include "swad_database.h"
+#include "swad_figure_cache.h"
#include "swad_form.h"
#include "swad_help.h"
#include "swad_hierarchy.h"
@@ -130,13 +131,28 @@ static void SysCfg_Configuration (bool PrintView)
/***** Shortcut to the country *****/
SysCfg_Shortcut (PrintView);
- NumCtrsWithMap = Ctr_GetNumCtrsWithMapInSys ();
+ /***** Get number of centres with map *****/
+ if (!FigCch_GetFigureFromCache (FigCch_NUM_CTRS_WITH_MAP,Hie_SYS,-1L,
+ &NumCtrsWithMap))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumCtrsWithMap = Ctr_GetNumCtrsWithMapInSys ();
+ FigCch_UpdateFigureIntoCache (FigCch_NUM_CTRS_WITH_MAP,Hie_SYS,-1L,
+ NumCtrsWithMap);
+ }
+
if (PrintView)
/***** QR code with link to the country *****/
SysCfg_QR ();
else
{
- NumCtrs = Ctr_GetNumCtrsInSys ();
+ /***** Get number of centres *****/
+ if (!FigCch_GetFigureFromCache (FigCch_NUM_CTRS,Hie_SYS,-1L,&NumCtrs))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumCtrs = Ctr_GetNumCtrsInSys ();
+ FigCch_UpdateFigureIntoCache (FigCch_NUM_CTRS,Hie_SYS,-1L,NumCtrs);
+ }
/***** Number of countries,
number of institutions,
@@ -336,6 +352,7 @@ static void SysCfg_QR (void)
static void SysCfg_NumCtys (void)
{
extern const char *Txt_Countries;
+ unsigned NumCtys;
/***** Number of countries ******/
HTM_TR_Begin (NULL);
@@ -347,7 +364,13 @@ static void SysCfg_NumCtys (void)
HTM_TD_Begin ("class=\"LB\"");
Frm_StartFormGoTo (ActSeeCty);
HTM_BUTTON_SUBMIT_Begin (Txt_Countries,"BT_LINK DAT",NULL);
- HTM_Unsigned (Cty_GetNumCtysTotal ());
+ if (!FigCch_GetFigureFromCache (FigCch_NUM_CTYS,Hie_SYS,-1L,&NumCtys))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumCtys = Cty_GetNumCtysTotal ();
+ FigCch_UpdateFigureIntoCache (FigCch_NUM_CTYS,Hie_SYS,-1L,NumCtys);
+ }
+ HTM_Unsigned (NumCtys);
HTM_BUTTON_End ();
Frm_EndForm ();
HTM_TD_End ();
@@ -362,6 +385,7 @@ static void SysCfg_NumCtys (void)
static void SysCfg_NumInss (void)
{
extern const char *Txt_Institutions;
+ unsigned NumInss;
/***** Number of institutions ******/
HTM_TR_Begin (NULL);
@@ -371,7 +395,13 @@ static void SysCfg_NumInss (void)
/* Data */
HTM_TD_Begin ("class=\"DAT LB\"");
- HTM_Unsigned (Ins_GetNumInssTotal ());
+ if (!FigCch_GetFigureFromCache (FigCch_NUM_INSS,Hie_SYS,-1L,&NumInss))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumInss = Ins_GetNumInssTotal ();
+ FigCch_UpdateFigureIntoCache (FigCch_NUM_INSS,Hie_SYS,-1L,NumInss);
+ }
+ HTM_Unsigned (NumInss);
HTM_TD_End ();
HTM_TR_End ();
@@ -384,6 +414,7 @@ static void SysCfg_NumInss (void)
static void SysCfg_NumDegs (void)
{
extern const char *Txt_Degrees;
+ unsigned NumDegs;
/***** Number of degrees *****/
HTM_TR_Begin (NULL);
@@ -393,7 +424,13 @@ static void SysCfg_NumDegs (void)
/* Data */
HTM_TD_Begin ("class=\"DAT LB\"");
- HTM_Unsigned (Deg_GetNumDegsTotal ());
+ if (!FigCch_GetFigureFromCache (FigCch_NUM_DEGS,Hie_SYS,-1L,&NumDegs))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumDegs = Deg_GetNumDegsTotal ();
+ FigCch_UpdateFigureIntoCache (FigCch_NUM_DEGS,Hie_SYS,-1L,NumDegs);
+ }
+ HTM_Unsigned (NumDegs);
HTM_TD_End ();
HTM_TR_End ();
@@ -406,6 +443,7 @@ static void SysCfg_NumDegs (void)
static void SysCfg_NumCrss (void)
{
extern const char *Txt_Courses;
+ unsigned NumCrss;
/***** Number of courses *****/
HTM_TR_Begin (NULL);
@@ -415,7 +453,13 @@ static void SysCfg_NumCrss (void)
/* Data */
HTM_TD_Begin ("class=\"DAT LB\"");
- HTM_Unsigned (Crs_GetNumCrssTotal ());
+ if (!FigCch_GetFigureFromCache (FigCch_NUM_CRSS,Hie_SYS,-1L,&NumCrss))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumCrss = Crs_GetNumCrssTotal ();
+ FigCch_UpdateFigureIntoCache (FigCch_NUM_CRSS,Hie_SYS,-1L,NumCrss);
+ }
+ HTM_Unsigned (NumCrss);
HTM_TD_End ();
HTM_TR_End ();
@@ -429,6 +473,20 @@ static void SysCfg_NumUsrsInCrss (Rol_Role_t Role)
{
extern const char *Txt_Users_in_courses;
extern const char *Txt_ROLES_PLURAL_Abc[Rol_NUM_ROLES][Usr_NUM_SEXS];
+ unsigned NumUsrsInCrss;
+ static FigCch_FigureCached_t Figure[Rol_NUM_ROLES] =
+ {
+ [Rol_UNK ] = FigCch_NUM_USRS_IN_CRSS, // Any users in courses
+ [Rol_GST ] = FigCch_UNKNOWN, // Not applicable
+ [Rol_USR ] = FigCch_UNKNOWN, // Not applicable
+ [Rol_STD ] = FigCch_NUM_STDS_IN_CRSS, // Students
+ [Rol_NET ] = FigCch_NUM_NETS_IN_CRSS, // Non-editing teachers
+ [Rol_TCH ] = FigCch_NUM_TCHS_IN_CRSS, // Teachers
+ [Rol_DEG_ADM] = FigCch_UNKNOWN, // Not applicable
+ [Rol_CTR_ADM] = FigCch_UNKNOWN, // Not applicable
+ [Rol_INS_ADM] = FigCch_UNKNOWN, // Not applicable
+ [Rol_SYS_ADM] = FigCch_UNKNOWN, // Not applicable
+ };
/***** Number of users in courses *****/
HTM_TR_Begin (NULL);
@@ -440,11 +498,19 @@ static void SysCfg_NumUsrsInCrss (Rol_Role_t Role)
/* Data */
HTM_TD_Begin ("class=\"DAT LB\"");
- HTM_Unsigned (Usr_GetNumUsrsInCrss (Hie_SYS,-1L,
- Role == Rol_UNK ? (1 << Rol_STD) |
- (1 << Rol_NET) |
- (1 << Rol_TCH) : // Any user
- (1 << Role)));
+ if (!FigCch_GetFigureFromCache (Figure[Role],Hie_SYS,-1L,
+ &NumUsrsInCrss))
+ {
+ // Not updated recently in cache ==> compute and update it in cache
+ NumUsrsInCrss = Usr_GetNumUsrsInCrss (Hie_SYS,-1L,
+ Role == Rol_UNK ? (1 << Rol_STD) |
+ (1 << Rol_NET) |
+ (1 << Rol_TCH) : // Any user
+ (1 << Role));
+ FigCch_UpdateFigureIntoCache (Figure[Role],Hie_SYS,-1L,
+ NumUsrsInCrss);
+ }
+ HTM_Unsigned (NumUsrsInCrss);
HTM_TD_End ();
HTM_TR_End ();