github.com/nutsdb/nutsdb@v1.0.4/tx_zset.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 "bytes" 19 "errors" 20 "strconv" 21 "strings" 22 "time" 23 24 "github.com/xujiajun/utils/strconv2" 25 ) 26 27 // SeparatorForZSetKey represents separator for zSet key. 28 const SeparatorForZSetKey = "|" 29 30 type SortedSetMember struct { 31 Value []byte 32 Score float64 33 } 34 35 // ZAdd Adds the specified member with the specified score into the sorted set specified by key in a bucket. 36 func (tx *Tx) ZAdd(bucket string, key []byte, score float64, val []byte) error { 37 var buffer bytes.Buffer 38 39 if strings.Contains(string(key), SeparatorForZSetKey) { 40 return ErrSeparatorForZSetKey() 41 } 42 43 buffer.Write(key) 44 buffer.Write([]byte(SeparatorForZSetKey)) 45 scoreBytes := []byte(strconv.FormatFloat(score, 'f', -1, 64)) 46 buffer.Write(scoreBytes) 47 newKey := buffer.Bytes() 48 49 return tx.put(bucket, newKey, val, Persistent, DataZAddFlag, uint64(time.Now().Unix()), DataStructureSortedSet) 50 } 51 52 // ZMembers Returns all the members and scores of members of the set specified by key in a bucket. 53 func (tx *Tx) ZMembers(bucket string, key []byte) (map[*SortedSetMember]struct{}, error) { 54 if err := tx.ZCheck(bucket); err != nil { 55 return nil, err 56 } 57 58 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 59 if err != nil { 60 return nil, err 61 } 62 63 var ( 64 bucketId = b.Id 65 sortedSet *SortedSet 66 exist bool 67 ) 68 69 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 70 return nil, ErrBucket 71 } 72 73 members, err := sortedSet.ZMembers(string(key)) 74 if err != nil { 75 return nil, err 76 } 77 78 res := make(map[*SortedSetMember]struct{}) 79 for record, score := range members { 80 value, err := tx.db.getValueByRecord(record) 81 if err != nil { 82 return nil, err 83 } 84 res[&SortedSetMember{ 85 Value: value, 86 Score: float64(score), 87 }] = struct{}{} 88 } 89 90 return res, nil 91 } 92 93 // ZCard Returns the sorted set cardinality (number of elements) of the sorted set specified by key in a bucket. 94 func (tx *Tx) ZCard(bucket string, key []byte) (int, error) { 95 if err := tx.ZCheck(bucket); err != nil { 96 return 0, err 97 } 98 99 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 100 if err != nil { 101 return 0, err 102 } 103 104 var ( 105 bucketId = b.Id 106 sortedSet *SortedSet 107 exist bool 108 ) 109 110 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 111 return 0, ErrBucket 112 } 113 114 return sortedSet.ZCard(string(key)) 115 } 116 117 // ZCount Returns the number of elements in the sorted set specified by key in a bucket with a score between min and max and opts. 118 // Opt includes the following parameters: 119 // Limit int // limit the max nodes to return 120 // ExcludeStart bool // exclude start value, so it search in interval (start, end] or (start, end) 121 // ExcludeEnd bool // exclude end value, so it search in interval [start, end) or (start, end) 122 func (tx *Tx) ZCount(bucket string, key []byte, start, end float64, opts *GetByScoreRangeOptions) (int, error) { 123 if err := tx.ZCheck(bucket); err != nil { 124 return 0, err 125 } 126 127 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 128 if err != nil { 129 return 0, err 130 } 131 132 var ( 133 bucketId = b.Id 134 sortedSet *SortedSet 135 exist bool 136 ) 137 138 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 139 return 0, ErrBucket 140 } 141 142 return sortedSet.ZCount(string(key), SCORE(start), SCORE(end), opts) 143 } 144 145 // ZPopMax Removes and returns the member with the highest score in the sorted set specified by key in a bucket. 146 func (tx *Tx) ZPopMax(bucket string, key []byte) (*SortedSetMember, error) { 147 if err := tx.ZCheck(bucket); err != nil { 148 return nil, err 149 } 150 151 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 152 if err != nil { 153 return nil, err 154 } 155 156 var ( 157 bucketId = b.Id 158 sortedSet *SortedSet 159 exist bool 160 ) 161 162 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 163 return nil, ErrBucket 164 } 165 166 record, score, err := sortedSet.ZPeekMax(string(key)) 167 if err != nil { 168 return nil, err 169 } 170 171 value, err := tx.db.getValueByRecord(record) 172 if err != nil { 173 return nil, err 174 } 175 176 return &SortedSetMember{Value: value, Score: float64(score)}, tx.put(bucket, key, []byte(""), Persistent, DataZPopMaxFlag, uint64(time.Now().Unix()), DataStructureSortedSet) 177 } 178 179 // ZPopMin Removes and returns the member with the lowest score in the sorted set specified by key in a bucket. 180 func (tx *Tx) ZPopMin(bucket string, key []byte) (*SortedSetMember, error) { 181 if err := tx.ZCheck(bucket); err != nil { 182 return nil, err 183 } 184 185 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 186 if err != nil { 187 return nil, err 188 } 189 190 var ( 191 bucketId = b.Id 192 sortedSet *SortedSet 193 exist bool 194 ) 195 196 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 197 return nil, ErrBucket 198 } 199 200 record, score, err := sortedSet.ZPeekMin(string(key)) 201 if err != nil { 202 return nil, err 203 } 204 205 value, err := tx.db.getValueByRecord(record) 206 if err != nil { 207 return nil, err 208 } 209 210 return &SortedSetMember{Value: value, Score: float64(score)}, tx.put(bucket, key, []byte(""), Persistent, DataZPopMinFlag, uint64(time.Now().Unix()), DataStructureSortedSet) 211 } 212 213 // ZPeekMax Returns the member with the highest score in the sorted set specified by key in a bucket. 214 func (tx *Tx) ZPeekMax(bucket string, key []byte) (*SortedSetMember, error) { 215 if err := tx.ZCheck(bucket); err != nil { 216 return nil, err 217 } 218 219 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 220 if err != nil { 221 return nil, err 222 } 223 224 var ( 225 bucketId = b.Id 226 sortedSet *SortedSet 227 exist bool 228 ) 229 230 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 231 return nil, ErrBucket 232 } 233 234 record, score, err := sortedSet.ZPeekMax(string(key)) 235 if err != nil { 236 return nil, err 237 } 238 239 value, err := tx.db.getValueByRecord(record) 240 if err != nil { 241 return nil, err 242 } 243 244 return &SortedSetMember{Value: value, Score: float64(score)}, nil 245 } 246 247 // ZPeekMin Returns the member with the lowest score in the sorted set specified by key in a bucket. 248 func (tx *Tx) ZPeekMin(bucket string, key []byte) (*SortedSetMember, error) { 249 if err := tx.ZCheck(bucket); err != nil { 250 return nil, err 251 } 252 253 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 254 if err != nil { 255 return nil, err 256 } 257 258 var ( 259 bucketId = b.Id 260 sortedSet *SortedSet 261 exist bool 262 ) 263 264 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 265 return nil, ErrBucket 266 } 267 268 record, score, err := sortedSet.ZPeekMin(string(key)) 269 if err != nil { 270 return nil, err 271 } 272 273 value, err := tx.db.getValueByRecord(record) 274 if err != nil { 275 return nil, err 276 } 277 278 return &SortedSetMember{Value: value, Score: float64(score)}, nil 279 } 280 281 // ZRangeByScore Returns all the elements in the sorted set specified by key in a bucket with a score between min and max. 282 // And the parameter `Opts` is the same as ZCount's. 283 func (tx *Tx) ZRangeByScore(bucket string, key []byte, start, end float64, opts *GetByScoreRangeOptions) ([]*SortedSetMember, error) { 284 if err := tx.ZCheck(bucket); err != nil { 285 return nil, err 286 } 287 288 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 289 if err != nil { 290 return nil, err 291 } 292 293 var ( 294 bucketId = b.Id 295 sortedSet *SortedSet 296 exist bool 297 ) 298 299 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 300 return nil, ErrBucket 301 } 302 303 records, scores, err := sortedSet.ZRangeByScore(string(key), SCORE(start), SCORE(end), opts) 304 if err != nil { 305 return nil, err 306 } 307 308 members := make([]*SortedSetMember, len(records)) 309 for i, record := range records { 310 value, err := tx.db.getValueByRecord(record) 311 if err != nil { 312 return nil, err 313 } 314 members[i] = &SortedSetMember{Value: value, Score: scores[i]} 315 } 316 317 return members, nil 318 } 319 320 // ZRangeByRank Returns all the elements in the sorted set specified by key in a bucket 321 // with a rank between start and end (including elements with rank equal to start or end). 322 func (tx *Tx) ZRangeByRank(bucket string, key []byte, start, end int) ([]*SortedSetMember, error) { 323 if err := tx.ZCheck(bucket); err != nil { 324 return nil, err 325 } 326 327 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 328 if err != nil { 329 return nil, err 330 } 331 332 var ( 333 bucketId = b.Id 334 sortedSet *SortedSet 335 exist bool 336 ) 337 338 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 339 return nil, ErrBucket 340 } 341 342 records, scores, err := sortedSet.ZRangeByRank(string(key), start, end) 343 if err != nil { 344 return nil, err 345 } 346 347 members := make([]*SortedSetMember, len(records)) 348 for i, record := range records { 349 value, err := tx.db.getValueByRecord(record) 350 if err != nil { 351 return nil, err 352 } 353 members[i] = &SortedSetMember{Value: value, Score: scores[i]} 354 } 355 356 return members, nil 357 } 358 359 // ZRem removes the specified members from the sorted set stored in one bucket at given bucket and key. 360 func (tx *Tx) ZRem(bucket string, key []byte, value []byte) error { 361 if err := tx.ZCheck(bucket); err != nil { 362 return err 363 } 364 365 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 366 if err != nil { 367 return err 368 } 369 370 var ( 371 bucketId = b.Id 372 sortedSet *SortedSet 373 exist bool 374 ) 375 376 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 377 return ErrBucket 378 } 379 380 exist, err = sortedSet.ZExist(string(key), value) 381 if err != nil { 382 return err 383 } 384 385 if !exist { 386 return ErrSortedSetMemberNotExist 387 } 388 389 return tx.put(bucket, key, value, Persistent, DataZRemFlag, uint64(time.Now().Unix()), DataStructureSortedSet) 390 } 391 392 // ZRemRangeByRank removes all elements in the sorted set stored in one bucket at given bucket with rank between start and end. 393 // the rank is 1-based integer. Rank 1 means the first node; Rank -1 means the last node. 394 func (tx *Tx) ZRemRangeByRank(bucket string, key []byte, start, end int) error { 395 if err := tx.ZCheck(bucket); err != nil { 396 return err 397 } 398 399 startStr := strconv2.IntToStr(start) 400 endStr := strconv2.IntToStr(end) 401 return tx.put(bucket, key, []byte(startStr+SeparatorForZSetKey+endStr), Persistent, DataZRemRangeByRankFlag, uint64(time.Now().Unix()), DataStructureSortedSet) 402 } 403 404 // ZRank Returns the rank of member in the sorted set specified by key in a bucket, with the scores ordered from low to high. 405 func (tx *Tx) ZRank(bucket string, key, value []byte) (int, error) { 406 if err := tx.ZCheck(bucket); err != nil { 407 return 0, err 408 } 409 410 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 411 if err != nil { 412 return 0, err 413 } 414 415 var ( 416 bucketId = b.Id 417 sortedSet *SortedSet 418 exist bool 419 ) 420 421 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 422 return 0, ErrBucket 423 } 424 425 return sortedSet.ZRank(string(key), value) 426 } 427 428 // ZRevRank Returns the rank of member in the sorted set specified by key in a bucket, with the scores ordered from high to low. 429 func (tx *Tx) ZRevRank(bucket string, key, value []byte) (int, error) { 430 if err := tx.ZCheck(bucket); err != nil { 431 return 0, err 432 } 433 434 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 435 if err != nil { 436 return 0, err 437 } 438 439 var ( 440 bucketId = b.Id 441 sortedSet *SortedSet 442 exist bool 443 ) 444 445 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 446 return 0, ErrBucket 447 } 448 449 return sortedSet.ZRevRank(string(key), value) 450 } 451 452 // ZScore Returns the score of members in a sorted set specified by key in a bucket. 453 func (tx *Tx) ZScore(bucket string, key, value []byte) (float64, error) { 454 if err := tx.ZCheck(bucket); err != nil { 455 return 0, err 456 } 457 458 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 459 if err != nil { 460 return 0.0, err 461 } 462 463 var ( 464 bucketId = b.Id 465 sortedSet *SortedSet 466 exist bool 467 ) 468 469 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 470 return 0, ErrBucket 471 } 472 473 return sortedSet.ZScore(string(key), value) 474 } 475 476 // ZKeys find all keys matching a given pattern in a bucket 477 func (tx *Tx) ZKeys(bucket, pattern string, f func(key string) bool) error { 478 if err := tx.ZCheck(bucket); err != nil { 479 return err 480 } 481 482 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 483 if err != nil { 484 return err 485 } 486 487 var ( 488 bucketId = b.Id 489 sortedSet *SortedSet 490 exist bool 491 ) 492 493 if sortedSet, exist = tx.db.Index.sortedSet.exist(bucketId); !exist { 494 return ErrBucket 495 } 496 497 for key := range sortedSet.M { 498 if end, err := MatchForRange(pattern, key, f); end || err != nil { 499 return err 500 } 501 } 502 return nil 503 } 504 505 func (tx *Tx) ZCheck(bucket string) error { 506 if err := tx.checkTxIsClosed(); err != nil { 507 return err 508 } 509 510 b, err := tx.db.bm.GetBucket(DataStructureSortedSet, bucket) 511 if err != nil { 512 return err 513 } 514 bucketId := b.Id 515 if _, ok := tx.db.Index.sortedSet.exist(bucketId); !ok { 516 return ErrBucket 517 } 518 return nil 519 } 520 521 // ErrSeparatorForZSetKey returns when zSet key contains the SeparatorForZSetKey flag. 522 func ErrSeparatorForZSetKey() error { 523 return errors.New("contain separator (" + SeparatorForZSetKey + ") for SortedSetIdx key") 524 }