diff --git a/internal/cache/timeline/status.go b/internal/cache/timeline/status.go index 9660f1303..fe5120aec 100644 --- a/internal/cache/timeline/status.go +++ b/internal/cache/timeline/status.go @@ -34,6 +34,8 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util/xslices" ) +const repeatBoostDepth = 40 + // StatusMeta contains minimum viable metadata // about a Status in order to cache a timeline. type StatusMeta struct { @@ -381,6 +383,29 @@ func (t *StatusTimeline) Preload( n = t.cache.Insert(metas...) } + // This is a potentially 100-1000s size map, + // but still easily manageable memory-wise. + recentBoosts := make(map[string]int, t.cut) + + // Iterate the entire timeline cache and mark repeat boosts. + for idx, value := range t.cache.RangeUnsafe(structr.Asc) { + + // Store current ID in map. + recentBoosts[value.ID] = idx + + // If it's a boost, check if the original, + // or a boost of it has been seen recently. + if id := value.BoostOfID; id != "" { + + // Check if seen recently. + last := recentBoosts[id] + value.repeatBoost = last < 40 + + // Update last-seen idx. + recentBoosts[id] = idx + } + } + return n, nil } @@ -703,8 +728,6 @@ func LoadStatusTimeline( // the return value indicates whether the passed status has been boosted recently on the timeline. func (t *StatusTimeline) InsertOne(status *gtsmodel.Status, prepared *apimodel.Status) (repeatBoost bool) { if status.BoostOfID != "" { - const repeatBoostDepth = 40 - // Check through top $repeatBoostDepth number of timeline items. for i, value := range t.cache.RangeUnsafe(structr.Desc) { if i >= repeatBoostDepth {