mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 02:25:30 +00:00
+caching layer for sorted alms
This commit is contained in:
@@ -2,6 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
|
||||||
@@ -17,6 +18,52 @@ const (
|
|||||||
TEMPLATE_ALMANACH = "/almanach/"
|
TEMPLATE_ALMANACH = "/almanach/"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Simple in-memory cache for sorted entries
|
||||||
|
var (
|
||||||
|
sortedEntriesCache struct {
|
||||||
|
sync.RWMutex
|
||||||
|
entries []*dbmodels.Entry
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// InvalidateSortedEntriesCache clears the cached sorted entries list
|
||||||
|
func InvalidateSortedEntriesCache() {
|
||||||
|
sortedEntriesCache.Lock()
|
||||||
|
defer sortedEntriesCache.Unlock()
|
||||||
|
sortedEntriesCache.entries = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getSortedEntries returns cached sorted entries or loads and caches them
|
||||||
|
func getSortedEntries(app core.App) ([]*dbmodels.Entry, error) {
|
||||||
|
// Try to read from cache first
|
||||||
|
sortedEntriesCache.RLock()
|
||||||
|
if sortedEntriesCache.entries != nil {
|
||||||
|
cached := sortedEntriesCache.entries
|
||||||
|
sortedEntriesCache.RUnlock()
|
||||||
|
return cached, nil
|
||||||
|
}
|
||||||
|
sortedEntriesCache.RUnlock()
|
||||||
|
|
||||||
|
// Cache miss - load and sort
|
||||||
|
sortedEntriesCache.Lock()
|
||||||
|
defer sortedEntriesCache.Unlock()
|
||||||
|
|
||||||
|
// Double-check after acquiring write lock
|
||||||
|
if sortedEntriesCache.entries != nil {
|
||||||
|
return sortedEntriesCache.entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
entries := []*dbmodels.Entry{}
|
||||||
|
if err := app.RecordQuery(dbmodels.ENTRIES_TABLE).All(&entries); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
dbmodels.Sort_Entries_Title_Year(entries)
|
||||||
|
sortedEntriesCache.entries = entries
|
||||||
|
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rp := &AlmanachPage{
|
rp := &AlmanachPage{
|
||||||
StaticPage: pagemodels.StaticPage{
|
StaticPage: pagemodels.StaticPage{
|
||||||
@@ -197,14 +244,14 @@ func NewAlmanachResult(app core.App, id string, params BeitraegeFilterParameters
|
|||||||
}
|
}
|
||||||
|
|
||||||
func entryNeighborsByPreferredTitle(app core.App, entryID string) (*dbmodels.Entry, *dbmodels.Entry, error) {
|
func entryNeighborsByPreferredTitle(app core.App, entryID string) (*dbmodels.Entry, *dbmodels.Entry, error) {
|
||||||
entries := []*dbmodels.Entry{}
|
entries, err := getSortedEntries(app)
|
||||||
if err := app.RecordQuery(dbmodels.ENTRIES_TABLE).All(&entries); err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if len(entries) == 0 {
|
if len(entries) == 0 {
|
||||||
return nil, nil, nil
|
return nil, nil, nil
|
||||||
}
|
}
|
||||||
dbmodels.Sort_Entries_Title_Year(entries)
|
|
||||||
for index, item := range entries {
|
for index, item := range entries {
|
||||||
if item.Id != entryID {
|
if item.Id != entryID {
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -190,6 +190,9 @@ func (p *AlmanachEditPage) POSTSave(engine *templating.Engine, app core.App) Han
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate sorted entries cache since entry was modified
|
||||||
|
InvalidateSortedEntriesCache()
|
||||||
|
|
||||||
// Check if fields that affect contents changed
|
// Check if fields that affect contents changed
|
||||||
contentsNeedUpdate := entry.PreferredTitle() != oldPreferredTitle ||
|
contentsNeedUpdate := entry.PreferredTitle() != oldPreferredTitle ||
|
||||||
entry.Year() != oldYear ||
|
entry.Year() != oldYear ||
|
||||||
@@ -290,6 +293,9 @@ func (p *AlmanachEditPage) POSTDelete(engine *templating.Engine, app core.App) H
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate sorted entries cache since entry was deleted
|
||||||
|
InvalidateSortedEntriesCache()
|
||||||
|
|
||||||
// Delete from FTS5 index asynchronously
|
// Delete from FTS5 index asynchronously
|
||||||
go func(appInstance core.App, entryID string) {
|
go func(appInstance core.App, entryID string) {
|
||||||
if err := dbmodels.DeleteFTS5Entry(appInstance, entryID); err != nil {
|
if err := dbmodels.DeleteFTS5Entry(appInstance, entryID); err != nil {
|
||||||
|
|||||||
@@ -146,6 +146,9 @@ func (p *AlmanachNewPage) POSTSave(engine *templating.Engine, app core.App) Hand
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate sorted entries cache since new entry was created
|
||||||
|
InvalidateSortedEntriesCache()
|
||||||
|
|
||||||
// Update FTS5 index asynchronously
|
// Update FTS5 index asynchronously
|
||||||
go func(appInstance core.App, entryID string) {
|
go func(appInstance core.App, entryID string) {
|
||||||
freshEntry, err := dbmodels.Entries_ID(appInstance, entryID)
|
freshEntry, err := dbmodels.Entries_ID(appInstance, entryID)
|
||||||
|
|||||||
Reference in New Issue
Block a user