github.com/m3db/m3@v1.5.0/src/dbnode/storage/id_list_gen.go (about) 1 // Copyright (c) 2021 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 // This file was automatically generated by genny. 22 // Any changes will be lost if this file is regenerated. 23 // see https://github.com/mauricelam/genny 24 25 package storage 26 27 import ( 28 "sync" 29 30 "github.com/m3db/m3/src/m3ninx/doc" 31 "github.com/m3db/m3/src/x/pool" 32 ) 33 34 // Copyright (c) 2019 Uber Technologies, Inc. 35 // 36 // Permission is hereby granted, free of charge, to any person obtaining a copy 37 // of this software and associated documentation files (the "Software"), to deal 38 // in the Software without restriction, including without limitation the rights 39 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 40 // copies of the Software, and to permit persons to whom the Software is 41 // furnished to do so, subject to the following conditions: 42 // 43 // The above copyright notice and this permission notice shall be included in 44 // all copies or substantial portions of the Software. 45 // 46 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 47 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 48 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 49 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 50 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 51 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 52 // THE SOFTWARE. 53 54 // This is a doubly linked list with its internal elements pooled. This allows 55 // the list to be reused as a shared resource to prevent unnecessary 56 // allocations/GC. 57 58 // This implementation is a modification from Go's container/list source code. 59 // Here is its license: 60 61 // Copyright (c) 2009 The Go Authors. All rights reserved. 62 63 // Redistribution and use in source and binary forms, with or without 64 // modification, are permitted provided that the following conditions are 65 // met: 66 67 // * Redistributions of source code must retain the above copyright 68 // notice, this list of conditions and the following disclaimer. 69 // * Redistributions in binary form must reproduce the above 70 // copyright notice, this list of conditions and the following disclaimer 71 // in the documentation and/or other materials provided with the 72 // distribution. 73 // * Neither the name of Google Inc. nor the names of its 74 // contributors may be used to endorse or promote products derived from 75 // this software without specific prior written permission. 76 77 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 78 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 79 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 80 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 81 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 82 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 83 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 84 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 85 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 86 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 87 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 88 89 // idElement is an element of a linked list. 90 type idElement struct { 91 // Next and previous pointers in the doubly-linked list of elements. 92 // To simplify the implementation, internally a list l is implemented 93 // as a ring, such that &l.root is both the next element of the last 94 // list element (l.Back()) and the previous element of the first list 95 // element (l.Front()). 96 next, prev *idElement 97 98 // The list to which this element belongs. 99 list *idList 100 101 // The value stored with this element. 102 Value doc.Metadata 103 } 104 105 // Next returns the next list element or nil. 106 func (e *idElement) Next() *idElement { 107 if p := e.next; e.list != nil && p != &e.list.root { 108 return p 109 } 110 return nil 111 } 112 113 // Prev returns the previous list element or nil. 114 func (e *idElement) Prev() *idElement { 115 if p := e.prev; e.list != nil && p != &e.list.root { 116 return p 117 } 118 return nil 119 } 120 121 // idList represents a doubly linked list. 122 // The zero value is an empty, ready to use list. 123 type idList struct { 124 root idElement // sentinel list element, only &root, root.prev, and root.next are used 125 len int // current list length excluding (this) sentinel element 126 Pool *idElementPool 127 } 128 129 // Init initializes or clears list l. 130 func (l *idList) Init() *idList { 131 l.root.next = &l.root 132 l.root.prev = &l.root 133 l.len = 0 134 if l.Pool == nil { 135 // Use a static pool at least, otherwise each time 136 // we create a list with no pool we create a wholly 137 // new pool of finalizeables (4096 of them). 138 defaultElementPoolOnce.Do(initElementPool) 139 l.Pool = defaultElementPool 140 } 141 return l 142 } 143 144 var ( 145 defaultElementPoolOnce sync.Once 146 defaultElementPool *idElementPool 147 ) 148 149 // define as a static method so lambda alloc not required 150 // when passing function pointer to sync.Once.Do. 151 func initElementPool() { 152 defaultElementPool = newIDElementPool(nil) 153 } 154 155 // newIDList returns an initialized list. 156 func newIDList(p *idElementPool) *idList { 157 l := &idList{Pool: p} 158 return l.Init() 159 } 160 161 // Len returns the number of elements of list l. 162 // The complexity is O(1). 163 func (l *idList) Len() int { return l.len } 164 165 // Front returns the first element of list l or nil if the list is empty. 166 func (l *idList) Front() *idElement { 167 if l.len == 0 { 168 return nil 169 } 170 return l.root.next 171 } 172 173 // Back returns the last element of list l or nil if the list is empty. 174 func (l *idList) Back() *idElement { 175 if l.len == 0 { 176 return nil 177 } 178 return l.root.prev 179 } 180 181 // lazyInit lazily initializes a zero List value. 182 func (l *idList) lazyInit() { 183 if l.root.next == nil { 184 l.Init() 185 } 186 } 187 188 // insert inserts e after at, increments l.len, and returns e. 189 func (l *idList) insert(e, at *idElement) *idElement { 190 n := at.next 191 at.next = e 192 e.prev = at 193 e.next = n 194 n.prev = e 195 e.list = l 196 l.len++ 197 return e 198 } 199 200 // insertValue is a convenience wrapper for inserting using the list's pool. 201 func (l *idList) insertValue(v doc.Metadata, at *idElement) *idElement { 202 e := l.Pool.get() 203 e.Value = v 204 return l.insert(e, at) 205 } 206 207 // remove removes e from its list, decrements l.len, and returns e. 208 func (l *idList) remove(e *idElement) *idElement { 209 e.prev.next = e.next 210 e.next.prev = e.prev 211 e.next = nil // avoid memory leaks 212 e.prev = nil // avoid memory leaks 213 e.list = nil 214 l.len-- 215 return e 216 } 217 218 // Remove removes e from l if e is an element of list l. 219 // It returns the element value e.Value. 220 // The element must not be nil. 221 func (l *idList) Remove(e *idElement) doc.Metadata { 222 // read the value before returning to the pool to avoid a data race with another goroutine getting access to the 223 // list after it has been put back into the pool. 224 v := e.Value 225 if e.list == l { 226 // if e.list == l, l must have been initialized when e was inserted 227 // in l or l == nil (e is a zero Element) and l.remove will crash. 228 l.remove(e) 229 l.Pool.put(e) 230 } 231 return v 232 } 233 234 // PushFront inserts a new element e with value v at the front of list l and returns e. 235 func (l *idList) PushFront(v doc.Metadata) *idElement { 236 l.lazyInit() 237 return l.insertValue(v, &l.root) 238 } 239 240 // PushBack inserts a new element e with value v at the back of list l and returns e. 241 func (l *idList) PushBack(v doc.Metadata) *idElement { 242 l.lazyInit() 243 return l.insertValue(v, l.root.prev) 244 } 245 246 // InsertBefore inserts a new element e with value v immediately before mark and returns e. 247 // If mark is not an element of l, the list is not modified. 248 // The mark must not be nil. 249 func (l *idList) InsertBefore(v doc.Metadata, mark *idElement) *idElement { 250 if mark.list != l { 251 return nil 252 } 253 // see comment in List.Remove about initialization of l 254 return l.insertValue(v, mark.prev) 255 } 256 257 // InsertAfter inserts a new element e with value v immediately after mark and returns e. 258 // If mark is not an element of l, the list is not modified. 259 // The mark must not be nil. 260 func (l *idList) InsertAfter(v doc.Metadata, mark *idElement) *idElement { 261 if mark.list != l { 262 return nil 263 } 264 // see comment in List.Remove about initialization of l 265 return l.insertValue(v, mark) 266 } 267 268 // MoveToFront moves element e to the front of list l. 269 // If e is not an element of l, the list is not modified. 270 // The element must not be nil. 271 func (l *idList) MoveToFront(e *idElement) { 272 if e.list != l || l.root.next == e { 273 return 274 } 275 // see comment in List.Remove about initialization of l 276 l.insert(l.remove(e), &l.root) 277 } 278 279 // MoveToBack moves element e to the back of list l. 280 // If e is not an element of l, the list is not modified. 281 // The element must not be nil. 282 func (l *idList) MoveToBack(e *idElement) { 283 if e.list != l || l.root.prev == e { 284 return 285 } 286 // see comment in List.Remove about initialization of l 287 l.insert(l.remove(e), l.root.prev) 288 } 289 290 // MoveBefore moves element e to its new position before mark. 291 // If e or mark is not an element of l, or e == mark, the list is not modified. 292 // The element and mark must not be nil. 293 func (l *idList) MoveBefore(e, mark *idElement) { 294 if e.list != l || e == mark || mark.list != l { 295 return 296 } 297 l.insert(l.remove(e), mark.prev) 298 } 299 300 // MoveAfter moves element e to its new position after mark. 301 // If e or mark is not an element of l, or e == mark, the list is not modified. 302 // The element and mark must not be nil. 303 func (l *idList) MoveAfter(e, mark *idElement) { 304 if e.list != l || e == mark || mark.list != l { 305 return 306 } 307 l.insert(l.remove(e), mark) 308 } 309 310 // PushBackList inserts a copy of an other list at the back of list l. 311 // The lists l and other may be the same. They must not be nil. 312 func (l *idList) PushBackList(other *idList) { 313 l.lazyInit() 314 for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { 315 l.insertValue(e.Value, l.root.prev) 316 } 317 } 318 319 // PushFrontList inserts a copy of an other list at the front of list l. 320 // The lists l and other may be the same. They must not be nil. 321 func (l *idList) PushFrontList(other *idList) { 322 l.lazyInit() 323 for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { 324 l.insertValue(e.Value, &l.root) 325 } 326 } 327 328 // Reset resets list l for reuse and puts all elements back into the pool. 329 func (l *idList) Reset() { 330 for e := l.Back(); e != nil; e = l.Back() { 331 l.Remove(e) 332 } 333 } 334 335 // idElementPool provides a pool for Elements. 336 type idElementPool struct { 337 pool pool.ObjectPool 338 } 339 340 // Get gets an Element from the pool. 341 func (p *idElementPool) get() *idElement { 342 return p.pool.Get().(*idElement) 343 } 344 345 // Put puts an Element back into the pool. 346 func (p *idElementPool) put(e *idElement) { 347 p.pool.Put(e) 348 } 349 350 // newIDElementPool creates a new generic ElementPool. 351 func newIDElementPool(opts pool.ObjectPoolOptions) *idElementPool { 352 p := &idElementPool{pool: pool.NewObjectPool(opts)} 353 p.pool.Init(func() interface{} { 354 return &idElement{} 355 }) 356 return p 357 }