+caching layer for sorted alms

This commit is contained in:
Simon Martens
2026-01-12 20:22:00 +01:00
parent bcf7d1847d
commit 9dd1fcd8ce
3 changed files with 59 additions and 3 deletions

View File

@@ -2,6 +2,7 @@ package controllers
import (
"sort"
"sync"
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
"github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels"
@@ -17,6 +18,52 @@ const (
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() {
rp := &AlmanachPage{
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) {
entries := []*dbmodels.Entry{}
if err := app.RecordQuery(dbmodels.ENTRIES_TABLE).All(&entries); err != nil {
entries, err := getSortedEntries(app)
if err != nil {
return nil, nil, err
}
if len(entries) == 0 {
return nil, nil, nil
}
dbmodels.Sort_Entries_Title_Year(entries)
for index, item := range entries {
if item.Id != entryID {
continue

View File

@@ -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
contentsNeedUpdate := entry.PreferredTitle() != oldPreferredTitle ||
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
go func(appInstance core.App, entryID string) {
if err := dbmodels.DeleteFTS5Entry(appInstance, entryID); err != nil {

View File

@@ -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
go func(appInstance core.App, entryID string) {
freshEntry, err := dbmodels.Entries_ID(appInstance, entryID)