github.com/claygod/queue@v0.0.0-20221013165802-9870c6dace8e/queue.go (about) 1 package queue 2 3 // Queue 4 // API 5 // Copyright © 2016-2018 Eduard Sesigin. All rights reserved. Contacts: <claygod@yandex.ru> 6 7 import ( 8 // "fmt" 9 "runtime" 10 "sync" 11 "sync/atomic" 12 ) 13 14 const sizeBlockDefault int = 1000 15 const sizeQueueMax int = 100000 16 const trialLimit int = 20000000 17 18 // Queue - main struct. 19 type Queue struct { 20 m *sync.Mutex 21 hasp int32 22 db []interface{} 23 dbReserve []interface{} 24 head int 25 tail int 26 sizeQueue int 27 sizeBlock int 28 sizeIn int 29 } 30 31 // New - create new queue. 32 // The optional argument: the initial size of the queue. 33 func New(args ...int) *Queue { 34 var sizeBlock int 35 if len(args) > 0 { 36 sizeBlock = args[0] 37 } else { 38 sizeBlock = sizeBlockDefault 39 } 40 q := Queue{ 41 m: &sync.Mutex{}, 42 hasp: 0, 43 db: make([]interface{}, sizeBlock), 44 dbReserve: make([]interface{}, sizeBlock), 45 head: sizeBlock / 2, 46 tail: sizeBlock / 2, 47 sizeQueue: sizeBlock, 48 sizeBlock: sizeBlock, // nil, 49 sizeIn: sizeBlock, 50 } 51 // q.unlock() // q.hasp = 0 52 return &q 53 } 54 55 // PushTail - Insert element in the tail queue 56 func (q *Queue) PushTail(n interface{}) bool { 57 // q.lock() 58 q.m.Lock() 59 defer q.m.Unlock() 60 if q.sizeQueue >= sizeQueueMax { // || !q.lock() 61 //q.m.Unlock() 62 //q.unlock() 63 return false 64 } 65 q.db[q.tail] = n 66 q.tail++ 67 if q.tail >= q.sizeQueue { 68 q.db = append(q.db, make([]interface{}, q.sizeBlock)...) 69 q.sizeQueue += q.sizeBlock 70 } 71 //q.unlock() // q.hasp = 0 72 //q.m.Unlock() 73 return true 74 } 75 76 // PushHead - Paste item in the queue head 77 func (q *Queue) PushHead(n interface{}) bool { 78 q.m.Lock() 79 defer q.m.Unlock() 80 if q.sizeQueue >= sizeQueueMax { // || !q.lock() 81 //q.m.Unlock() 82 return false 83 } 84 q.head-- 85 if q.head == 0 { 86 newDb := make([]interface{}, q.sizeQueue+q.sizeBlock) 87 copy(newDb[q.sizeBlock:], q.db) 88 q.db = newDb 89 q.head += q.sizeBlock 90 q.tail += q.sizeBlock 91 q.sizeQueue = q.sizeQueue + q.sizeBlock 92 } 93 q.db[q.head] = n 94 //q.unlock() // q.hasp = 0 95 //q.m.Unlock() 96 return true 97 } 98 99 // PopHead - Get the first element of the queue 100 func (q *Queue) PopHead() (interface{}, bool) { 101 q.m.Lock() 102 defer q.m.Unlock() 103 var n interface{} 104 //if !q.lock() { 105 // return n, false 106 //} 107 if q.tail == q.head { 108 //q.unlock() // q.hasp = 0 109 return n, false 110 } 111 n, q.db[q.head] = q.db[q.head], nil 112 q.head++ 113 if q.head == q.tail { // && q.sizeQueue >= q.sizeBlock*3 114 q.clean() 115 } 116 //q.unlock() // q.hasp = 0 117 return n, true 118 } 119 120 func (q *Queue) PopHeadList(num int) []interface{} { 121 //q.lock() 122 q.m.Lock() 123 defer q.m.Unlock() 124 //if !q.lock() { 125 // return make([]interface{}, 0), false 126 //} 127 if q.tail == q.head { 128 //q.unlock() // q.hasp = 0 129 //q.m.Unlock() 130 //q.unlock() 131 return make([]interface{}, 0) 132 } 133 end := q.head + num 134 if end > q.tail { 135 end = q.tail 136 } 137 out := make([]interface{}, end-q.head) 138 copy(out, q.db[q.head:end]) 139 q.head = end 140 if q.head == q.tail { // && q.sizeQueue >= q.sizeBlock*3 141 q.clean() 142 } 143 // q.unlock() // q.hasp = 0 144 //q.m.Unlock() 145 //q.unlock() 146 return out 147 } 148 149 func (q *Queue) PopAll() []interface{} { 150 ndb := make([]interface{}, q.sizeIn) 151 q.m.Lock() 152 defer q.m.Unlock() 153 out := q.db[q.head:q.tail] 154 155 q.hasp = 0 156 q.db = ndb 157 q.head = q.sizeIn / 2 158 q.tail = q.sizeIn / 2 159 q.sizeQueue = q.sizeIn 160 q.sizeBlock = q.sizeIn 161 //q.m.Unlock() 162 return out 163 } 164 165 // PopTail - Get the item from the queue tail 166 func (q *Queue) PopTail() (interface{}, bool) { 167 var n interface{} 168 //if !q.lock() { 169 // return n, false 170 //} 171 q.m.Lock() 172 defer q.m.Unlock() 173 if q.head == q.tail { 174 //q.unlock() // q.hasp = 0 175 return n, false 176 } 177 q.tail-- 178 n, q.db[q.tail] = q.db[q.tail], nil 179 if q.head == q.tail { // && q.sizeQueue >= q.sizeBlock*3 180 q.clean() 181 } 182 //q.unlock() // q.hasp = 0 183 return n, true 184 } 185 186 // LenQueue - The number of elements in the queue 187 func (q *Queue) LenQueue() int { 188 q.m.Lock() 189 defer q.m.Unlock() 190 //q.lock() 191 ln := q.tail - q.head 192 //q.unlock() // q.hasp = 0 193 return ln 194 } 195 196 // SizeQueue - The size reserved for queue 197 func (q *Queue) SizeQueue() int { 198 q.m.Lock() 199 defer q.m.Unlock() 200 //q.lock() 201 ln := q.sizeQueue 202 //q.unlock() // q.hasp = 0 203 return ln 204 } 205 206 func (q *Queue) cleanAlternative() { 207 // fmt.Print("\r\n------------ CLEAN!!\r\n") 208 if q.dbReserve == nil { 209 q.db = make([]interface{}, q.sizeBlock) 210 } else { 211 q.db = q.dbReserve // make([]interface{}, q.sizeBlock) 212 } 213 214 q.head = q.sizeBlock / 2 215 q.tail = q.sizeBlock / 2 216 q.sizeQueue = q.sizeBlock 217 q.dbReserve = nil 218 go q.genDbReserve() 219 } 220 221 // cleanAndReplace - Resetting the queue (not thread-safe, is called only after the lock) 222 func (q *Queue) cleanAndReplace() { 223 q.db = make([]interface{}, q.sizeBlock) 224 q.head = q.sizeBlock / 2 225 q.tail = q.sizeBlock / 2 226 q.sizeQueue = q.sizeBlock 227 } 228 229 func (q *Queue) clean() { 230 if q.sizeQueue >= sizeQueueMax/2 { // q.sizeBlock*3 231 q.db = make([]interface{}, q.sizeBlock) 232 q.head = q.sizeBlock / 2 233 q.tail = q.sizeBlock / 2 234 q.sizeQueue = q.sizeBlock 235 } else { 236 q.head = q.sizeQueue / 2 237 q.tail = q.sizeQueue / 2 238 } 239 240 } 241 242 func (q *Queue) genDbReserve() { 243 q.dbReserve = make([]interface{}, q.sizeBlock) 244 245 } 246 247 // lock - block queue 248 func (q *Queue) lock() bool { 249 for { // i := trialLimit; i > 0; i-- 250 if q.hasp == 0 && atomic.CompareAndSwapInt32(&q.hasp, 0, 1) { 251 break 252 } 253 //if i == 0 { 254 // return false 255 //} 256 runtime.Gosched() 257 } 258 return true 259 } 260 261 func (q *Queue) unlock() { 262 atomic.StoreInt32(&q.hasp, 0) 263 // q.hasp = 0 264 }