github.com/m3db/m3@v1.5.0/src/metrics/matcher/cache/list.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package cache 22 23 import ( 24 "sync" 25 "sync/atomic" 26 "time" 27 28 "github.com/m3db/m3/src/metrics/rules" 29 ) 30 31 // element is a list element 32 type element struct { 33 namespace []byte 34 id []byte 35 result rules.MatchResult 36 deleted bool 37 expiryNanos int64 38 prev *element 39 next *element 40 } 41 42 func newElement( 43 namespace, id []byte, 44 result rules.MatchResult, 45 ) *element { 46 return &element{ 47 namespace: append([]byte(nil), namespace...), 48 id: append([]byte(nil), id...), 49 result: result, 50 } 51 } 52 53 // ShouldPromote determines whether the previous promotion has expired 54 // and we should perform a new promotion. 55 func (e *element) ShouldPromote(now time.Time) bool { 56 return atomic.LoadInt64(&e.expiryNanos) <= now.UnixNano() 57 } 58 59 // SetPromotionExpiry sets the expiry time of the current promotion. 60 func (e *element) SetPromotionExpiry(t time.Time) { 61 atomic.StoreInt64(&e.expiryNanos, t.UnixNano()) 62 } 63 64 // list is a type-specific implementation of doubly linked lists consisting 65 // of elements so when we retrieve match results, there is no conversion 66 // between interface{} and the concrete result type. 67 type list struct { 68 head *element 69 tail *element 70 length int 71 } 72 73 // Len returns the number of elements in the list. 74 func (l *list) Len() int { return l.length } 75 76 // Front returns the first element in the list. 77 func (l *list) Front() *element { return l.head } 78 79 // Back returns the last element in the list. 80 func (l *list) Back() *element { return l.tail } 81 82 // PushFront pushes an element to the front of the list. 83 func (l *list) PushFront(elem *element) { 84 if elem == nil || elem.deleted { 85 return 86 } 87 if l.head == nil { 88 l.head = elem 89 l.tail = elem 90 elem.prev = nil 91 elem.next = nil 92 } else { 93 elem.next = l.head 94 elem.prev = nil 95 l.head.prev = elem 96 l.head = elem 97 } 98 l.length++ 99 } 100 101 // PushBack pushes an element to the back of the list. 102 func (l *list) PushBack(elem *element) { 103 if elem == nil || elem.deleted { 104 return 105 } 106 if l.tail == nil { 107 l.head = elem 108 l.tail = elem 109 elem.prev = nil 110 elem.next = nil 111 } else { 112 elem.prev = l.tail 113 elem.next = nil 114 l.tail.next = elem 115 l.tail = elem 116 } 117 l.length++ 118 } 119 120 // Remove removes an element from the list. 121 func (l *list) Remove(elem *element) { 122 if elem == nil || elem.deleted { 123 return 124 } 125 126 // Remove the element from the list. 127 l.remove(elem, true) 128 } 129 130 // MoveToFront moves an element to the beginning of the list. 131 func (l *list) MoveToFront(elem *element) { 132 if elem == nil || elem.deleted { 133 return 134 } 135 136 // Removing the element from the list. 137 l.remove(elem, false) 138 139 // Pushing the element to the front of the list. 140 l.PushFront(elem) 141 } 142 143 func (l *list) remove(elem *element, markDeleted bool) { 144 prev := elem.prev 145 next := elem.next 146 if prev == nil { 147 l.head = next 148 } else { 149 prev.next = next 150 } 151 if next == nil { 152 l.tail = prev 153 } else { 154 next.prev = prev 155 } 156 l.length-- 157 elem.prev = nil // avoid memory leak. 158 elem.next = nil // avoid memory leak. 159 elem.deleted = markDeleted 160 } 161 162 type lockedList struct { 163 sync.Mutex 164 list 165 }