Added cached site repository
This commit is contained in:
@@ -0,0 +1,290 @@
|
|||||||
|
package cachedrepo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"quay/app/models"
|
||||||
|
"quay/app/repository"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CachedSiteRepository struct {
|
||||||
|
inner repository.SiteRepository
|
||||||
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
sites map[string]*models.Site // id -> site
|
||||||
|
siteList []models.Site // cached ListSites result
|
||||||
|
siteListValid bool
|
||||||
|
|
||||||
|
forwardRules map[string]*models.ForwardRule // id -> rule
|
||||||
|
customHeaders map[string]*models.CustomHeaders // id -> custom headers
|
||||||
|
headers map[string]*models.Header // id -> header
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCachedSiteRepository(inner repository.SiteRepository) *CachedSiteRepository {
|
||||||
|
return &CachedSiteRepository{
|
||||||
|
inner: inner,
|
||||||
|
sites: make(map[string]*models.Site),
|
||||||
|
forwardRules: make(map[string]*models.ForwardRule),
|
||||||
|
customHeaders: make(map[string]*models.CustomHeaders),
|
||||||
|
headers: make(map[string]*models.Header),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ repository.SiteRepository = (*CachedSiteRepository)(nil)
|
||||||
|
|
||||||
|
// Sites
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) GetSite(id string) (*models.Site, error) {
|
||||||
|
c.mu.RLock()
|
||||||
|
if s, ok := c.sites[id]; ok {
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
c.mu.RUnlock()
|
||||||
|
|
||||||
|
s, err := c.inner.GetSite(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.sites[id] = s
|
||||||
|
c.mu.Unlock()
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) ListSites() ([]models.Site, error) {
|
||||||
|
c.mu.RLock()
|
||||||
|
if c.siteListValid {
|
||||||
|
cp := make([]models.Site, len(c.siteList))
|
||||||
|
copy(cp, c.siteList)
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return cp, nil
|
||||||
|
}
|
||||||
|
c.mu.RUnlock()
|
||||||
|
|
||||||
|
sites, err := c.inner.ListSites()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.siteList = sites
|
||||||
|
c.siteListValid = true
|
||||||
|
for i := range sites {
|
||||||
|
s := sites[i]
|
||||||
|
c.sites[s.ID] = &s
|
||||||
|
}
|
||||||
|
c.mu.Unlock()
|
||||||
|
return sites, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) CreateSite(s *models.Site) error {
|
||||||
|
if err := c.inner.CreateSite(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.sites[s.ID] = s
|
||||||
|
c.siteListValid = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) UpdateSite(s *models.Site) error {
|
||||||
|
if err := c.inner.UpdateSite(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.sites[s.ID] = s
|
||||||
|
c.siteListValid = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) DeleteSite(id string) error {
|
||||||
|
if err := c.inner.DeleteSite(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.sites, id)
|
||||||
|
c.siteListValid = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward Rules
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) GetForwardRule(id string) (*models.ForwardRule, error) {
|
||||||
|
c.mu.RLock()
|
||||||
|
if fr, ok := c.forwardRules[id]; ok {
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return fr, nil
|
||||||
|
}
|
||||||
|
c.mu.RUnlock()
|
||||||
|
|
||||||
|
fr, err := c.inner.GetForwardRule(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.forwardRules[id] = fr
|
||||||
|
c.mu.Unlock()
|
||||||
|
return fr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) CreateForwardRule(siteID string, fr *models.ForwardRule) error {
|
||||||
|
if err := c.inner.CreateForwardRule(siteID, fr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.forwardRules[fr.ID] = fr
|
||||||
|
delete(c.sites, siteID) // site's embedded rules are now stale
|
||||||
|
c.siteListValid = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) UpdateForwardRule(fr *models.ForwardRule) error {
|
||||||
|
if err := c.inner.UpdateForwardRule(fr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.forwardRules[fr.ID] = fr
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) DeleteForwardRule(id string) error {
|
||||||
|
if err := c.inner.DeleteForwardRule(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.forwardRules, id)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom Headers
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) GetCustomHeaders(id string) (*models.CustomHeaders, error) {
|
||||||
|
c.mu.RLock()
|
||||||
|
if ch, ok := c.customHeaders[id]; ok {
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return ch, nil
|
||||||
|
}
|
||||||
|
c.mu.RUnlock()
|
||||||
|
|
||||||
|
ch, err := c.inner.GetCustomHeaders(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.customHeaders[id] = ch
|
||||||
|
c.mu.Unlock()
|
||||||
|
return ch, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) CreateCustomHeaders(siteID string, ch *models.CustomHeaders) error {
|
||||||
|
if err := c.inner.CreateCustomHeaders(siteID, ch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.customHeaders[ch.ID] = ch
|
||||||
|
delete(c.sites, siteID)
|
||||||
|
c.siteListValid = false
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) UpdateCustomHeaders(ch *models.CustomHeaders) error {
|
||||||
|
if err := c.inner.UpdateCustomHeaders(ch); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.customHeaders[ch.ID] = ch
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) DeleteCustomHeaders(id string) error {
|
||||||
|
if err := c.inner.DeleteCustomHeaders(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.customHeaders, id)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) GetHeader(id string) (*models.Header, error) {
|
||||||
|
c.mu.RLock()
|
||||||
|
if h, ok := c.headers[id]; ok {
|
||||||
|
c.mu.RUnlock()
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
c.mu.RUnlock()
|
||||||
|
|
||||||
|
h, err := c.inner.GetHeader(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
c.mu.Lock()
|
||||||
|
c.headers[id] = h
|
||||||
|
c.mu.Unlock()
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) CreateHeader(customHeaderID string, h *models.Header) error {
|
||||||
|
if err := c.inner.CreateHeader(customHeaderID, h); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.headers[h.ID] = h
|
||||||
|
delete(c.customHeaders, customHeaderID)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) UpdateHeader(h *models.Header) error {
|
||||||
|
if err := c.inner.UpdateHeader(h); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
c.headers[h.ID] = h
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedSiteRepository) DeleteHeader(id string) error {
|
||||||
|
if err := c.inner.DeleteHeader(id); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.mu.Lock()
|
||||||
|
delete(c.headers, id)
|
||||||
|
c.mu.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invalidate explicitly evicts all cached data
|
||||||
|
func (c *CachedSiteRepository) Invalidate() {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
c.sites = make(map[string]*models.Site)
|
||||||
|
c.siteList = nil
|
||||||
|
c.siteListValid = false
|
||||||
|
c.forwardRules = make(map[string]*models.ForwardRule)
|
||||||
|
c.customHeaders = make(map[string]*models.CustomHeaders)
|
||||||
|
c.headers = make(map[string]*models.Header)
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvalidateSite evicts a single site and marks the list stale.
|
||||||
|
func (c *CachedSiteRepository) InvalidateSite(id string) {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
delete(c.sites, id)
|
||||||
|
c.siteListValid = false
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"log"
|
"log"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"quay/app/cachedrepo"
|
||||||
"quay/app/handlers"
|
"quay/app/handlers"
|
||||||
"quay/internal/config"
|
"quay/internal/config"
|
||||||
"quay/internal/database"
|
"quay/internal/database"
|
||||||
@@ -13,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, db *sql.DB) {
|
func Register(app *fiber.App, cfg *config.Config, envCfg *envconfig.EnvConfig, db *sql.DB) {
|
||||||
siteRepository := database.NewSQLiteSiteRepository(db)
|
siteRepository := cachedrepo.NewCachedSiteRepository(database.NewSQLiteSiteRepository(db))
|
||||||
|
|
||||||
updateSiteHandler := handlers.NewUpdateSiteHandler(cfg, envCfg)
|
updateSiteHandler := handlers.NewUpdateSiteHandler(cfg, envCfg)
|
||||||
siteHandler := handlers.NewSiteHandler(siteRepository)
|
siteHandler := handlers.NewSiteHandler(siteRepository)
|
||||||
|
|||||||
Reference in New Issue
Block a user