prune.go (2289B)
1 // GoToSocial 2 // Copyright (C) GoToSocial Authors admin@gotosocial.org 3 // SPDX-License-Identifier: AGPL-3.0-or-later 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package timeline 19 20 import ( 21 "container/list" 22 ) 23 24 func (t *timeline) Prune(desiredPreparedItemsLength int, desiredIndexedItemsLength int) int { 25 t.Lock() 26 defer t.Unlock() 27 28 l := t.items.data 29 if l == nil { 30 // Nothing to prune. 31 return 0 32 } 33 34 var ( 35 position int 36 totalPruned int 37 toRemove *[]*list.Element 38 ) 39 40 // Only initialize toRemove if we know we're 41 // going to need it, otherwise skiperino. 42 if toRemoveLen := t.items.data.Len() - desiredIndexedItemsLength; toRemoveLen > 0 { 43 toRemove = func() *[]*list.Element { tr := make([]*list.Element, 0, toRemoveLen); return &tr }() 44 } 45 46 // Work from the front of the list until we get 47 // to the point where we need to start pruning. 48 for e := l.Front(); e != nil; e = e.Next() { 49 position++ 50 51 if position <= desiredPreparedItemsLength { 52 // We're still within our allotted 53 // prepped length, nothing to do yet. 54 continue 55 } 56 57 // We need to *at least* unprepare this entry. 58 // If we're beyond our indexed length already, 59 // we can just remove the item completely. 60 if position > desiredIndexedItemsLength { 61 *toRemove = append(*toRemove, e) 62 totalPruned++ 63 continue 64 } 65 66 entry := e.Value.(*indexedItemsEntry) //nolint:forcetypeassert 67 if entry.prepared == nil { 68 // It's already unprepared (mood). 69 continue 70 } 71 72 entry.prepared = nil // <- eat this up please garbage collector nom nom nom 73 totalPruned++ 74 } 75 76 if toRemove != nil { 77 for _, e := range *toRemove { 78 l.Remove(e) 79 } 80 } 81 82 return totalPruned 83 }