github.com/livekit/protocol@v1.16.1-0.20240517185851-47e4c6bba773/utils/timeoutqueue.go (about) 1 // Copyright 2023 LiveKit, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package utils 16 17 import ( 18 "sync" 19 "time" 20 ) 21 22 type TimeoutQueueItem[T any] struct { 23 Value T 24 time int64 25 next, prev *TimeoutQueueItem[T] 26 removed bool 27 } 28 29 type TimeoutQueue[T any] struct { 30 mu sync.Mutex 31 head, tail *TimeoutQueueItem[T] 32 } 33 34 func (q *TimeoutQueue[T]) Reset(i *TimeoutQueueItem[T]) bool { 35 t := time.Now().UnixNano() 36 37 q.mu.Lock() 38 defer q.mu.Unlock() 39 40 if !i.removed { 41 i.time = t 42 q.remove(i) 43 q.push(i) 44 } 45 return !i.removed 46 } 47 48 func (q *TimeoutQueue[T]) Remove(i *TimeoutQueueItem[T]) { 49 q.mu.Lock() 50 defer q.mu.Unlock() 51 52 i.removed = true 53 q.remove(i) 54 } 55 56 func (q *TimeoutQueue[T]) popBefore(t time.Time, remove bool) *TimeoutQueueItem[T] { 57 q.mu.Lock() 58 defer q.mu.Unlock() 59 60 i := q.head 61 if i == nil || i.time > t.UnixNano() { 62 return nil 63 } 64 65 i.removed = i.removed || remove 66 i.time = 0 67 q.remove(i) 68 69 return i 70 } 71 72 func (q *TimeoutQueue[T]) push(i *TimeoutQueueItem[T]) { 73 i.prev = q.tail 74 i.next = nil 75 76 if i.prev != nil { 77 i.prev.next = i 78 } 79 80 q.tail = i 81 if q.head == nil { 82 q.head = i 83 } 84 } 85 86 func (q *TimeoutQueue[T]) remove(i *TimeoutQueueItem[T]) { 87 if q.tail == i { 88 q.tail = i.prev 89 } 90 if q.head == i { 91 q.head = i.next 92 } 93 if i.prev != nil { 94 i.prev.next = i.next 95 } 96 if i.next != nil { 97 i.next.prev = i.prev 98 } 99 i.next = nil 100 i.prev = nil 101 } 102 103 func (q *TimeoutQueue[T]) IterateAfter(timeout time.Duration) timeoutQueueIterator[T] { 104 return newTimeoutQueueIterator(q, timeout, false) 105 } 106 107 func (q *TimeoutQueue[T]) IterateRemoveAfter(timeout time.Duration) timeoutQueueIterator[T] { 108 return newTimeoutQueueIterator(q, timeout, true) 109 } 110 111 type timeoutQueueIterator[T any] struct { 112 q *TimeoutQueue[T] 113 time time.Time 114 remove bool 115 item *TimeoutQueueItem[T] 116 } 117 118 func newTimeoutQueueIterator[T any](q *TimeoutQueue[T], timeout time.Duration, remove bool) timeoutQueueIterator[T] { 119 return timeoutQueueIterator[T]{ 120 q: q, 121 time: time.Now().Add(-timeout), 122 remove: remove, 123 } 124 } 125 126 func (i *timeoutQueueIterator[T]) Next() bool { 127 i.item = i.q.popBefore(i.time, i.remove) 128 return i.item != nil 129 } 130 131 func (i *timeoutQueueIterator[T]) Item() *TimeoutQueueItem[T] { 132 return i.item 133 }