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  }