Introduce survey and question cache
This commit is contained in:
parent
02a232b1fa
commit
ab88195607
10
api.go
10
api.go
@ -28,6 +28,16 @@ func declareAPIRoutes(router *gin.Engine) {
|
|||||||
apiAdminRoutes := router.Group("/api")
|
apiAdminRoutes := router.Group("/api")
|
||||||
apiAdminRoutes.Use(authMiddleware(adminRestricted))
|
apiAdminRoutes.Use(authMiddleware(adminRestricted))
|
||||||
|
|
||||||
|
apiAdminRoutes.DELETE("/cache", func(c *gin.Context) {
|
||||||
|
_surveys_cache_mutex.Lock()
|
||||||
|
_surveys_cache = map[int64]*Survey{}
|
||||||
|
_surveys_cache_mutex.Unlock()
|
||||||
|
|
||||||
|
_questions_cache_mutex.Lock()
|
||||||
|
_questions_cache = map[int64]*Question{}
|
||||||
|
_questions_cache_mutex.Unlock()
|
||||||
|
})
|
||||||
|
|
||||||
declareAPIAdminAsksRoutes(apiAdminRoutes)
|
declareAPIAdminAsksRoutes(apiAdminRoutes)
|
||||||
declareAPIAuthGradesRoutes(apiAdminRoutes)
|
declareAPIAuthGradesRoutes(apiAdminRoutes)
|
||||||
declareAPIAdminHelpRoutes(apiAdminRoutes)
|
declareAPIAdminHelpRoutes(apiAdminRoutes)
|
||||||
|
37
questions.go
37
questions.go
@ -4,12 +4,18 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/russross/blackfriday/v2"
|
"github.com/russross/blackfriday/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_questions_cache = map[int64]*Question{}
|
||||||
|
_questions_cache_mutex = sync.RWMutex{}
|
||||||
|
)
|
||||||
|
|
||||||
func declareAPIAuthQuestionsRoutes(router *gin.RouterGroup) {
|
func declareAPIAuthQuestionsRoutes(router *gin.RouterGroup) {
|
||||||
router.GET("/questions", func(c *gin.Context) {
|
router.GET("/questions", func(c *gin.Context) {
|
||||||
var s *Survey
|
var s *Survey
|
||||||
@ -252,16 +258,38 @@ func (s *Survey) GetQuestions() (questions []*Question, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getQuestion(id int) (q *Question, err error) {
|
func getQuestion(id int) (q *Question, err error) {
|
||||||
|
_questions_cache_mutex.RLock()
|
||||||
|
question, ok := _questions_cache[int64(id)]
|
||||||
|
_questions_cache_mutex.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return question, nil
|
||||||
|
}
|
||||||
|
|
||||||
q = new(Question)
|
q = new(Question)
|
||||||
err = DBQueryRow("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_question=?", id).Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind)
|
err = DBQueryRow("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_question=?", id).Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind)
|
||||||
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
||||||
|
|
||||||
|
_questions_cache_mutex.Lock()
|
||||||
|
_questions_cache[int64(id)] = q
|
||||||
|
_questions_cache_mutex.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Survey) GetQuestion(id int) (q *Question, err error) {
|
func (s *Survey) GetQuestion(id int) (q *Question, err error) {
|
||||||
|
_questions_cache_mutex.RLock()
|
||||||
|
question, ok := _questions_cache[int64(id)]
|
||||||
|
_questions_cache_mutex.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return question, nil
|
||||||
|
}
|
||||||
|
|
||||||
q = new(Question)
|
q = new(Question)
|
||||||
err = DBQueryRow("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_question=? AND id_survey=?", id, s.Id).Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind)
|
err = DBQueryRow("SELECT id_question, id_survey, title, description, placeholder, kind FROM survey_quests WHERE id_question=? AND id_survey=?", id, s.Id).Scan(&q.Id, &q.IdSurvey, &q.Title, &q.DescriptionRaw, &q.Placeholder, &q.Kind)
|
||||||
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
q.Description = string(blackfriday.Run([]byte(q.DescriptionRaw)))
|
||||||
|
|
||||||
|
_questions_cache_mutex.Lock()
|
||||||
|
_questions_cache[int64(id)] = q
|
||||||
|
_questions_cache_mutex.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,6 +311,9 @@ func (q *Question) Update() (*Question, error) {
|
|||||||
if _, err := DBExec("UPDATE survey_quests SET id_survey = ?, title = ?, description = ?, placeholder = ?, kind = ? WHERE id_question = ?", q.IdSurvey, q.Title, q.DescriptionRaw, q.Placeholder, q.Kind, q.Id); err != nil {
|
if _, err := DBExec("UPDATE survey_quests SET id_survey = ?, title = ?, description = ?, placeholder = ?, kind = ? WHERE id_question = ?", q.IdSurvey, q.Title, q.DescriptionRaw, q.Placeholder, q.Kind, q.Id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
_questions_cache_mutex.Lock()
|
||||||
|
_questions_cache[q.Id] = q
|
||||||
|
_questions_cache_mutex.Unlock()
|
||||||
return q, err
|
return q, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -293,6 +324,9 @@ func (q *Question) Delete() (int64, error) {
|
|||||||
} else if nb, err := res.RowsAffected(); err != nil {
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else {
|
} else {
|
||||||
|
_questions_cache_mutex.Lock()
|
||||||
|
delete(_questions_cache, q.Id)
|
||||||
|
_questions_cache_mutex.Unlock()
|
||||||
return nb, err
|
return nb, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,6 +337,9 @@ func ClearQuestions() (int64, error) {
|
|||||||
} else if nb, err := res.RowsAffected(); err != nil {
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else {
|
} else {
|
||||||
|
_questions_cache_mutex.Lock()
|
||||||
|
_questions_cache = map[int64]*Question{}
|
||||||
|
_questions_cache_mutex.Unlock()
|
||||||
return nb, err
|
return nb, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
38
surveys.go
38
surveys.go
@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@ -13,6 +14,9 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
_score_cache = map[int64]map[int64]*float64{}
|
_score_cache = map[int64]map[int64]*float64{}
|
||||||
|
_score_cache_mutex = sync.RWMutex{}
|
||||||
|
_surveys_cache = map[int64]*Survey{}
|
||||||
|
_surveys_cache_mutex = sync.RWMutex{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func declareAPISurveysRoutes(router *gin.RouterGroup) {
|
func declareAPISurveysRoutes(router *gin.RouterGroup) {
|
||||||
@ -228,8 +232,19 @@ func getSurveys(cnd string, param ...interface{}) (surveys []*Survey, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getSurvey(id int) (s *Survey, err error) {
|
func getSurvey(id int) (s *Survey, err error) {
|
||||||
|
_surveys_cache_mutex.RLock()
|
||||||
|
survey, ok := _surveys_cache[int64(id)]
|
||||||
|
_surveys_cache_mutex.RUnlock()
|
||||||
|
if ok {
|
||||||
|
return survey, nil
|
||||||
|
}
|
||||||
|
|
||||||
s = new(Survey)
|
s = new(Survey)
|
||||||
err = DBQueryRow("SELECT id_survey, title, promo, grp, shown, direct, corrected, start_availability, end_availability FROM surveys WHERE id_survey=?", id).Scan(&s.Id, &s.Title, &s.Promo, &s.Group, &s.Shown, &s.Direct, &s.Corrected, &s.StartAvailability, &s.EndAvailability)
|
err = DBQueryRow("SELECT id_survey, title, promo, grp, shown, direct, corrected, start_availability, end_availability FROM surveys WHERE id_survey=?", id).Scan(&s.Id, &s.Title, &s.Promo, &s.Group, &s.Shown, &s.Direct, &s.Corrected, &s.StartAvailability, &s.EndAvailability)
|
||||||
|
|
||||||
|
_surveys_cache_mutex.Lock()
|
||||||
|
_surveys_cache[int64(id)] = s
|
||||||
|
_surveys_cache_mutex.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,17 +259,29 @@ func NewSurvey(title string, promo uint, group string, shown bool, direct *int64
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s Survey) GetScore(u *User) (score *float64, err error) {
|
func (s Survey) GetScore(u *User) (score *float64, err error) {
|
||||||
|
_score_cache_mutex.RLock()
|
||||||
if _, ok := _score_cache[u.Id]; !ok {
|
if _, ok := _score_cache[u.Id]; !ok {
|
||||||
|
_score_cache_mutex.RUnlock()
|
||||||
|
_score_cache_mutex.Lock()
|
||||||
_score_cache[u.Id] = map[int64]*float64{}
|
_score_cache[u.Id] = map[int64]*float64{}
|
||||||
|
_score_cache_mutex.Unlock()
|
||||||
|
_score_cache_mutex.RLock()
|
||||||
}
|
}
|
||||||
if v, ok := _score_cache[u.Id][s.Id]; ok {
|
|
||||||
|
v, ok := _score_cache[u.Id][s.Id]
|
||||||
|
_score_cache_mutex.RUnlock()
|
||||||
|
|
||||||
|
if ok {
|
||||||
score = v
|
score = v
|
||||||
} else {
|
} else {
|
||||||
err = DBQueryRow("SELECT SUM(score)/COUNT(*) FROM student_scores WHERE id_survey=? AND id_user=?", s.Id, u.Id).Scan(&score)
|
err = DBQueryRow("SELECT SUM(score)/COUNT(*) FROM student_scores WHERE id_survey=? AND id_user=?", s.Id, u.Id).Scan(&score)
|
||||||
if score != nil {
|
if score != nil {
|
||||||
*score = *score / 5.0
|
*score = *score / 5.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_score_cache_mutex.Lock()
|
||||||
_score_cache[u.Id][s.Id] = score
|
_score_cache[u.Id][s.Id] = score
|
||||||
|
_score_cache_mutex.Unlock()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -288,6 +315,9 @@ func (s *Survey) Update() (*Survey, error) {
|
|||||||
if _, err := DBExec("UPDATE surveys SET title = ?, promo = ?, grp = ?, shown = ?, direct = ?, corrected = ?, start_availability = ?, end_availability = ? WHERE id_survey = ?", s.Title, s.Promo, s.Group, s.Shown, s.Direct, s.Corrected, s.StartAvailability, s.EndAvailability, s.Id); err != nil {
|
if _, err := DBExec("UPDATE surveys SET title = ?, promo = ?, grp = ?, shown = ?, direct = ?, corrected = ?, start_availability = ?, end_availability = ? WHERE id_survey = ?", s.Title, s.Promo, s.Group, s.Shown, s.Direct, s.Corrected, s.StartAvailability, s.EndAvailability, s.Id); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
|
_surveys_cache_mutex.Lock()
|
||||||
|
_surveys_cache[s.Id] = s
|
||||||
|
_surveys_cache_mutex.Unlock()
|
||||||
return s, err
|
return s, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,6 +328,9 @@ func (s Survey) Delete() (int64, error) {
|
|||||||
} else if nb, err := res.RowsAffected(); err != nil {
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else {
|
} else {
|
||||||
|
_surveys_cache_mutex.Lock()
|
||||||
|
delete(_surveys_cache, s.Id)
|
||||||
|
_surveys_cache_mutex.Unlock()
|
||||||
return nb, err
|
return nb, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,6 +341,9 @@ func ClearSurveys() (int64, error) {
|
|||||||
} else if nb, err := res.RowsAffected(); err != nil {
|
} else if nb, err := res.RowsAffected(); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else {
|
} else {
|
||||||
|
_surveys_cache_mutex.Lock()
|
||||||
|
_surveys_cache = map[int64]*Survey{}
|
||||||
|
_surveys_cache_mutex.Unlock()
|
||||||
return nb, err
|
return nb, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,6 +347,14 @@
|
|||||||
>
|
>
|
||||||
<i class="bi bi-plus"></i>
|
<i class="bi bi-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm btn-outline-danger"
|
||||||
|
on:click={() => { fetch('api/cache', {method: 'DELETE'}) } }
|
||||||
|
title="Vider les caches"
|
||||||
|
>
|
||||||
|
<i class="bi bi-bandaid-fill"></i>
|
||||||
|
</button>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
Reference in New Issue
Block a user