mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-04-16 06:14:13 +00:00
more code comments, don't bother inserting statuses if timeline not preloaded
This commit is contained in:
parent
2bd26dbedc
commit
13d5adbfe0
3 changed files with 63 additions and 35 deletions
36
internal/cache/timeline/preload.go
vendored
36
internal/cache/timeline/preload.go
vendored
|
@ -33,10 +33,34 @@ import (
|
|||
// - brand-new = nil (functionally same as 'needs preload')
|
||||
type preloader struct{ p atomic.Pointer[any] }
|
||||
|
||||
// Check will concurrency-safely check the preload
|
||||
// state, and if needed call the provided function.
|
||||
// if a preload is in progress, it will wait until complete.
|
||||
func (p *preloader) Check(preload func()) {
|
||||
// Check will return the current preload state,
|
||||
// waiting if a preload is currently in progress.
|
||||
func (p *preloader) Check() bool {
|
||||
for {
|
||||
// Get state ptr.
|
||||
ptr := p.p.Load()
|
||||
|
||||
// Check if requires preloading.
|
||||
if ptr == nil || *ptr == false {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check for a preload currently in progress.
|
||||
if wg, _ := (*ptr).(*sync.WaitGroup); wg != nil {
|
||||
wg.Wait()
|
||||
continue
|
||||
}
|
||||
|
||||
// Anything else
|
||||
// means success.
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// CheckPreload will safely check the preload state,
|
||||
// and if needed call the provided function. if a
|
||||
// preload is in progress, it will wait until complete.
|
||||
func (p *preloader) CheckPreload(preload func()) {
|
||||
for {
|
||||
// Get state ptr.
|
||||
ptr := p.p.Load()
|
||||
|
@ -95,7 +119,7 @@ func (p *preloader) start(old *any, preload func()) bool {
|
|||
|
||||
// done marks state as preloaded,
|
||||
// i.e. no more preload required.
|
||||
func (p *preloader) done() {
|
||||
func (p *preloader) Done() {
|
||||
old := p.p.Swap(new(any))
|
||||
if old == nil { // was brand-new
|
||||
return
|
||||
|
@ -109,7 +133,7 @@ func (p *preloader) done() {
|
|||
|
||||
// clear will clear the state, marking a "preload" as required.
|
||||
// i.e. next call to Check() will call provided preload func.
|
||||
func (p *preloader) clear() {
|
||||
func (p *preloader) Clear() {
|
||||
b := false
|
||||
a := any(b)
|
||||
for {
|
||||
|
|
19
internal/cache/timeline/status.go
vendored
19
internal/cache/timeline/status.go
vendored
|
@ -32,6 +32,12 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/util/xslices"
|
||||
)
|
||||
|
||||
// repeatBoostDepth determines the minimum count
|
||||
// of statuses after which repeat boosts, or boosts
|
||||
// of the original, may appear. This is may not end
|
||||
// up *exact*, as small races between insert and the
|
||||
// repeatBoost calculation may allow 1 or so extra
|
||||
// to sneak in ahead of time. but it mostly works!
|
||||
const repeatBoostDepth = 40
|
||||
|
||||
// StatusMeta contains minimum viable metadata
|
||||
|
@ -190,14 +196,14 @@ func (t *StatusTimeline) Preload(
|
|||
n int,
|
||||
err error,
|
||||
) {
|
||||
t.preloader.Check(func() {
|
||||
t.preloader.CheckPreload(func() {
|
||||
n, err = t.preload(loadPage, filter)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Mark preloaded.
|
||||
t.preloader.done()
|
||||
t.preloader.Done()
|
||||
})
|
||||
return
|
||||
}
|
||||
|
@ -547,6 +553,13 @@ func loadStatusTimeline(
|
|||
// InsertOne allows you to insert a single status into the timeline, with optional prepared API model.
|
||||
// The return value indicates whether status should be skipped from streams, e.g. if already boosted recently.
|
||||
func (t *StatusTimeline) InsertOne(status *gtsmodel.Status, prepared *apimodel.Status) (skip bool) {
|
||||
|
||||
// If timeline no preloaded, i.e.
|
||||
// no-one using it, don't insert.
|
||||
if !t.preloader.Check() {
|
||||
return false
|
||||
}
|
||||
|
||||
if status.BoostOfID != "" {
|
||||
// Check through top $repeatBoostDepth number of timeline items.
|
||||
for i, value := range t.cache.RangeUnsafe(structr.Desc) {
|
||||
|
@ -718,7 +731,7 @@ func (t *StatusTimeline) Trim() { t.cache.Trim(t.cut, structr.Asc) }
|
|||
|
||||
// Clear will mark the entire timeline as requiring preload,
|
||||
// which will trigger a clear and reload of the entire thing.
|
||||
func (t *StatusTimeline) Clear() { t.preloader.clear() }
|
||||
func (t *StatusTimeline) Clear() { t.preloader.Clear() }
|
||||
|
||||
// prepareStatuses takes a slice of cached (or, freshly loaded!) StatusMeta{}
|
||||
// models, and use given function to return prepared frontend API models.
|
||||
|
|
|
@ -108,29 +108,9 @@ func (p *Processor) getStatusTimeline(
|
|||
// input paging cursor.
|
||||
id.ValidatePage(page)
|
||||
|
||||
// Returned models and page params.
|
||||
var apiStatuses []*apimodel.Status
|
||||
var lo, hi string
|
||||
|
||||
// Pre-prepared filter function that just ensures we
|
||||
// don't end up serving multiple copies of the same boost.
|
||||
prepare := func(status *gtsmodel.Status) (*apimodel.Status, error) {
|
||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||
status,
|
||||
requester,
|
||||
filterCtx,
|
||||
filters,
|
||||
mutes,
|
||||
)
|
||||
if err != nil && !errors.Is(err, statusfilter.ErrHideStatus) {
|
||||
return nil, err
|
||||
}
|
||||
return apiStatus, nil
|
||||
}
|
||||
|
||||
// Load status page via timeline cache, also
|
||||
// getting lo, hi values for next, prev pages.
|
||||
apiStatuses, lo, hi, err = timeline.Load(ctx,
|
||||
apiStatuses, lo, hi, err := timeline.Load(ctx,
|
||||
|
||||
// Status page
|
||||
// to load.
|
||||
|
@ -145,13 +125,24 @@ func (p *Processor) getStatusTimeline(
|
|||
return p.state.DB.GetStatusesByIDs(ctx, ids)
|
||||
},
|
||||
|
||||
// Filtering function,
|
||||
// i.e. filter before caching.
|
||||
// Call provided status
|
||||
// filtering function.
|
||||
filter,
|
||||
|
||||
// Frontend API model
|
||||
// preparation function.
|
||||
prepare,
|
||||
// Frontend API model preparation function.
|
||||
func(status *gtsmodel.Status) (*apimodel.Status, error) {
|
||||
apiStatus, err := p.converter.StatusToAPIStatus(ctx,
|
||||
status,
|
||||
requester,
|
||||
filterCtx,
|
||||
filters,
|
||||
mutes,
|
||||
)
|
||||
if err != nil && !errors.Is(err, statusfilter.ErrHideStatus) {
|
||||
return nil, err
|
||||
}
|
||||
return apiStatus, nil
|
||||
},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
|
Loading…
Reference in a new issue