github.com/nutsdb/nutsdb@v1.0.4/list.go (about) 1 // Copyright 2023 The nutsdb Author. All rights reserved. 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 nutsdb 16 17 import ( 18 "errors" 19 "math" 20 "time" 21 ) 22 23 var ( 24 // ErrListNotFound is returned when the list not found. 25 ErrListNotFound = errors.New("the list not found") 26 27 // ErrCount is returned when count is error. 28 ErrCount = errors.New("err count") 29 30 // ErrEmptyList is returned when the list is empty. 31 ErrEmptyList = errors.New("the list is empty") 32 33 // ErrStartOrEnd is returned when start > end 34 ErrStartOrEnd = errors.New("start or end error") 35 ) 36 37 const ( 38 initialListSeq = math.MaxUint64 / 2 39 ) 40 41 // BTree represents the btree. 42 43 // HeadTailSeq list head and tail seq num 44 type HeadTailSeq struct { 45 Head uint64 46 Tail uint64 47 } 48 49 // List represents the list. 50 type List struct { 51 Items map[string]*BTree 52 TTL map[string]uint32 53 TimeStamp map[string]uint64 54 Seq map[string]*HeadTailSeq 55 } 56 57 func NewList() *List { 58 return &List{ 59 Items: make(map[string]*BTree), 60 TTL: make(map[string]uint32), 61 TimeStamp: make(map[string]uint64), 62 Seq: make(map[string]*HeadTailSeq), 63 } 64 } 65 66 func (l *List) LPush(key string, r *Record) error { 67 return l.push(key, r, true) 68 } 69 70 func (l *List) RPush(key string, r *Record) error { 71 return l.push(key, r, false) 72 } 73 74 func (l *List) push(key string, r *Record, isLeft bool) error { 75 // key is seq + user_key 76 userKey, curSeq := decodeListKey([]byte(key)) 77 userKeyStr := string(userKey) 78 if l.IsExpire(userKeyStr) { 79 return ErrListNotFound 80 } 81 82 list, ok := l.Items[userKeyStr] 83 if !ok { 84 l.Items[userKeyStr] = NewBTree() 85 list = l.Items[userKeyStr] 86 } 87 88 seq, ok := l.Seq[userKeyStr] 89 if !ok { 90 l.Seq[userKeyStr] = &HeadTailSeq{Head: initialListSeq, Tail: initialListSeq + 1} 91 seq = l.Seq[userKeyStr] 92 } 93 94 list.InsertRecord(ConvertUint64ToBigEndianBytes(curSeq), r) 95 if isLeft { 96 if seq.Head > curSeq-1 { 97 seq.Head = curSeq - 1 98 } 99 } else { 100 if seq.Tail < curSeq+1 { 101 seq.Tail = curSeq + 1 102 } 103 } 104 105 return nil 106 } 107 108 func (l *List) LPop(key string) (*Record, error) { 109 item, err := l.LPeek(key) 110 if err != nil { 111 return nil, err 112 } 113 114 l.Items[key].Delete(item.key) 115 l.Seq[key].Head = ConvertBigEndianBytesToUint64(item.key) 116 return item.record, nil 117 } 118 119 // RPop removes and returns the last element of the list stored at key. 120 func (l *List) RPop(key string) (*Record, error) { 121 item, err := l.RPeek(key) 122 if err != nil { 123 return nil, err 124 } 125 126 l.Items[key].Delete(item.key) 127 l.Seq[key].Tail = ConvertBigEndianBytesToUint64(item.key) 128 return item.record, nil 129 } 130 131 func (l *List) LPeek(key string) (*Item, error) { 132 return l.peek(key, true) 133 } 134 135 func (l *List) RPeek(key string) (*Item, error) { 136 return l.peek(key, false) 137 } 138 139 func (l *List) peek(key string, isLeft bool) (*Item, error) { 140 if l.IsExpire(key) { 141 return nil, ErrListNotFound 142 } 143 list, ok := l.Items[key] 144 if !ok { 145 return nil, ErrListNotFound 146 } 147 148 if isLeft { 149 item, ok := list.Min() 150 if ok { 151 return item, nil 152 } 153 } else { 154 item, ok := list.Max() 155 if ok { 156 return item, nil 157 } 158 } 159 160 return nil, ErrEmptyList 161 } 162 163 // LRange returns the specified elements of the list stored at key [start,end] 164 func (l *List) LRange(key string, start, end int) ([]*Record, error) { 165 size, err := l.Size(key) 166 if err != nil || size == 0 { 167 return nil, err 168 } 169 170 start, end, err = checkBounds(start, end, size) 171 if err != nil { 172 return nil, err 173 } 174 175 var res []*Record 176 allRecords := l.Items[key].All() 177 for i, item := range allRecords { 178 if i >= start && i <= end { 179 res = append(res, item) 180 } 181 } 182 183 return res, nil 184 } 185 186 // getRemoveIndexes returns a slice of indices to be removed from the list based on the count 187 func (l *List) getRemoveIndexes(key string, count int, cmp func(r *Record) (bool, error)) ([][]byte, error) { 188 if l.IsExpire(key) { 189 return nil, ErrListNotFound 190 } 191 192 list, ok := l.Items[key] 193 194 if !ok { 195 return nil, ErrListNotFound 196 } 197 198 var res [][]byte 199 var allItems []*Item 200 if 0 == count { 201 count = list.Count() 202 } 203 204 allItems = l.Items[key].AllItems() 205 if count > 0 { 206 for _, item := range allItems { 207 if count <= 0 { 208 break 209 } 210 r := item.record 211 ok, err := cmp(r) 212 if err != nil { 213 return nil, err 214 } 215 if ok { 216 res = append(res, item.key) 217 count-- 218 } 219 } 220 } else { 221 for i := len(allItems) - 1; i >= 0; i-- { 222 if count >= 0 { 223 break 224 } 225 r := allItems[i].record 226 ok, err := cmp(r) 227 if err != nil { 228 return nil, err 229 } 230 if ok { 231 res = append(res, allItems[i].key) 232 count++ 233 } 234 } 235 } 236 237 return res, nil 238 } 239 240 // LRem removes the first count occurrences of elements equal to value from the list stored at key. 241 // The count argument influences the operation in the following ways: 242 // count > 0: Remove elements equal to value moving from head to tail. 243 // count < 0: Remove elements equal to value moving from tail to head. 244 // count = 0: Remove all elements equal to value. 245 func (l *List) LRem(key string, count int, cmp func(r *Record) (bool, error)) error { 246 removeIndexes, err := l.getRemoveIndexes(key, count, cmp) 247 if err != nil { 248 return err 249 } 250 251 list := l.Items[key] 252 for _, idx := range removeIndexes { 253 list.Delete(idx) 254 } 255 256 return nil 257 } 258 259 // LTrim trim an existing list so that it will contain only the specified range of elements specified. 260 func (l *List) LTrim(key string, start, end int) error { 261 if l.IsExpire(key) { 262 return ErrListNotFound 263 } 264 if _, ok := l.Items[key]; !ok { 265 return ErrListNotFound 266 } 267 268 list := l.Items[key] 269 allItems := list.AllItems() 270 for i, item := range allItems { 271 if i < start || i > end { 272 list.Delete(item.key) 273 } 274 } 275 276 return nil 277 } 278 279 // LRemByIndex remove the list element at specified index 280 func (l *List) LRemByIndex(key string, indexes []int) error { 281 if l.IsExpire(key) { 282 return ErrListNotFound 283 } 284 285 idxes := l.getValidIndexes(key, indexes) 286 if len(idxes) == 0 { 287 return nil 288 } 289 290 list := l.Items[key] 291 allItems := list.AllItems() 292 for i, item := range allItems { 293 if _, ok := idxes[i]; ok { 294 list.Delete(item.key) 295 } 296 } 297 298 return nil 299 } 300 301 func (l *List) getValidIndexes(key string, indexes []int) map[int]struct{} { 302 idxes := make(map[int]struct{}) 303 listLen, err := l.Size(key) 304 if err != nil || 0 == listLen { 305 return idxes 306 } 307 308 for _, idx := range indexes { 309 if idx < 0 || idx >= listLen { 310 continue 311 } 312 idxes[idx] = struct{}{} 313 } 314 315 return idxes 316 } 317 318 func (l *List) IsExpire(key string) bool { 319 if l == nil { 320 return false 321 } 322 323 _, ok := l.TTL[key] 324 if !ok { 325 return false 326 } 327 328 now := time.Now().Unix() 329 timestamp := l.TimeStamp[key] 330 if l.TTL[key] > 0 && uint64(l.TTL[key])+timestamp > uint64(now) || l.TTL[key] == uint32(0) { 331 return false 332 } 333 334 delete(l.Items, key) 335 delete(l.TTL, key) 336 delete(l.TimeStamp, key) 337 delete(l.Seq, key) 338 339 return true 340 } 341 342 func (l *List) Size(key string) (int, error) { 343 if l.IsExpire(key) { 344 return 0, ErrListNotFound 345 } 346 if _, ok := l.Items[key]; !ok { 347 return 0, ErrListNotFound 348 } 349 350 return l.Items[key].Count(), nil 351 } 352 353 func (l *List) IsEmpty(key string) (bool, error) { 354 size, err := l.Size(key) 355 if err != nil || size > 0 { 356 return false, err 357 } 358 return true, nil 359 } 360 361 func (l *List) GetListTTL(key string) (uint32, error) { 362 if l.IsExpire(key) { 363 return 0, ErrListNotFound 364 } 365 366 ttl := l.TTL[key] 367 timestamp := l.TimeStamp[key] 368 if ttl == 0 || timestamp == 0 { 369 return 0, nil 370 } 371 372 now := time.Now().Unix() 373 remain := timestamp + uint64(ttl) - uint64(now) 374 375 return uint32(remain), nil 376 } 377 378 func checkBounds(start, end int, size int) (int, int, error) { 379 if start >= 0 && end < 0 { 380 end = size + end 381 } 382 383 if start < 0 && end > 0 { 384 start = size + start 385 } 386 387 if start < 0 && end < 0 { 388 start, end = size+start, size+end 389 } 390 391 if end >= size { 392 end = size - 1 393 } 394 395 if start > end { 396 return 0, 0, ErrStartOrEnd 397 } 398 399 return start, end, nil 400 }