✨ 使用服务器来计算元数据 #2
@ -93,7 +93,7 @@ func AnalyzeAttachment(file models.Attachment) error {
|
|||||||
if linked && err != nil {
|
if linked && err != nil {
|
||||||
return fmt.Errorf("unable to link file record: %v", err)
|
return fmt.Errorf("unable to link file record: %v", err)
|
||||||
} else if !linked {
|
} else if !linked {
|
||||||
metadataCache[file.ID] = file
|
metadataCache.Store(file.ID, file)
|
||||||
if err := tx.Save(&file).Error; err != nil {
|
if err := tx.Save(&file).Error; err != nil {
|
||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return fmt.Errorf("unable to save file record: %v", err)
|
return fmt.Errorf("unable to save file record: %v", err)
|
||||||
|
@ -6,21 +6,23 @@ import (
|
|||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/paperclip/pkg/internal/database"
|
"git.solsynth.dev/hydrogen/paperclip/pkg/internal/database"
|
||||||
|
|
||||||
"git.solsynth.dev/hydrogen/paperclip/pkg/internal/models"
|
"git.solsynth.dev/hydrogen/paperclip/pkg/internal/models"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const metadataCacheLimit = 512
|
const metadataCacheLimit = 512
|
||||||
|
|
||||||
var metadataCache = make(map[uint]models.Attachment)
|
var metadataCache sync.Map
|
||||||
|
|
||||||
func GetAttachmentByID(id uint) (models.Attachment, error) {
|
func GetAttachmentByID(id uint) (models.Attachment, error) {
|
||||||
if val, ok := metadataCache[id]; ok {
|
if val, ok := metadataCache.Load(id); ok {
|
||||||
return val, nil
|
return val.(models.Attachment), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachment models.Attachment
|
var attachment models.Attachment
|
||||||
@ -29,10 +31,8 @@ func GetAttachmentByID(id uint) (models.Attachment, error) {
|
|||||||
}).Preload("Account").First(&attachment).Error; err != nil {
|
}).Preload("Account").First(&attachment).Error; err != nil {
|
||||||
return attachment, err
|
return attachment, err
|
||||||
} else {
|
} else {
|
||||||
if len(metadataCache) > metadataCacheLimit {
|
MaintainAttachmentCache()
|
||||||
clear(metadataCache)
|
metadataCache.Store(id, attachment)
|
||||||
}
|
|
||||||
metadataCache[id] = attachment
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachment, nil
|
return attachment, nil
|
||||||
@ -80,10 +80,8 @@ func NewAttachmentMetadata(tx *gorm.DB, user *models.Account, file *multipart.Fi
|
|||||||
if err := tx.Save(&attachment).Error; err != nil {
|
if err := tx.Save(&attachment).Error; err != nil {
|
||||||
return attachment, fmt.Errorf("failed to save attachment record: %v", err)
|
return attachment, fmt.Errorf("failed to save attachment record: %v", err)
|
||||||
} else {
|
} else {
|
||||||
if len(metadataCache) > metadataCacheLimit {
|
MaintainAttachmentCache()
|
||||||
clear(metadataCache)
|
metadataCache.Store(attachment.ID, attachment)
|
||||||
}
|
|
||||||
metadataCache[attachment.ID] = attachment
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return attachment, nil
|
return attachment, nil
|
||||||
@ -108,8 +106,8 @@ func TryLinkAttachment(tx *gorm.DB, og models.Attachment, hash string) (bool, er
|
|||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
metadataCache[prev.ID] = prev
|
metadataCache.Store(prev.ID, prev)
|
||||||
metadataCache[og.ID] = og
|
metadataCache.Store(og.ID, og)
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
@ -118,10 +116,8 @@ func UpdateAttachment(item models.Attachment) (models.Attachment, error) {
|
|||||||
if err := database.C.Save(&item).Error; err != nil {
|
if err := database.C.Save(&item).Error; err != nil {
|
||||||
return item, err
|
return item, err
|
||||||
} else {
|
} else {
|
||||||
if len(metadataCache) > metadataCacheLimit {
|
MaintainAttachmentCache()
|
||||||
clear(metadataCache)
|
metadataCache.Store(item.ID, item)
|
||||||
}
|
|
||||||
metadataCache[item.ID] = item
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return item, nil
|
return item, nil
|
||||||
@ -148,7 +144,7 @@ func DeleteAttachment(item models.Attachment) error {
|
|||||||
tx.Rollback()
|
tx.Rollback()
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
delete(metadataCache, item.ID)
|
metadataCache.Delete(item.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.Commit()
|
tx.Commit()
|
||||||
@ -159,3 +155,19 @@ func DeleteAttachment(item models.Attachment) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MaintainAttachmentCache() {
|
||||||
|
var keySet []uint
|
||||||
|
metadataCache.Range(func(k any, v any) bool {
|
||||||
|
keySet = append(keySet, k.(uint))
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if len(keySet) > metadataCacheLimit {
|
||||||
|
go func() {
|
||||||
|
log.Debug().Int("count", len(keySet)).Msg("Cleaning attachment metadata cache...")
|
||||||
|
for _, k := range keySet {
|
||||||
|
metadataCache.Delete(k)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -81,7 +81,7 @@ func ReUploadFileToPermanent(meta models.Attachment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
database.C.Save(&meta)
|
database.C.Save(&meta)
|
||||||
metadataCache[meta.ID] = meta
|
metadataCache.Store(meta.ID, meta)
|
||||||
return nil
|
return nil
|
||||||
case models.DestinationTypeS3:
|
case models.DestinationTypeS3:
|
||||||
var destConfigured models.S3Destination
|
var destConfigured models.S3Destination
|
||||||
@ -105,7 +105,7 @@ func ReUploadFileToPermanent(meta models.Attachment) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
database.C.Save(&meta)
|
database.C.Save(&meta)
|
||||||
metadataCache[meta.ID] = meta
|
metadataCache.Store(meta.ID, meta)
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("invalid destination: unsupported protocol %s", dest.Type)
|
return fmt.Errorf("invalid destination: unsupported protocol %s", dest.Type)
|
||||||
|
Loading…
Reference in New Issue
Block a user