github.com/flower-corp/rosedb@v1.1.2-0.20230117132829-21dc4f7b319a/hash.go (about)

     1  package rosedb
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"github.com/flower-corp/rosedb/ds/art"
     7  	"github.com/flower-corp/rosedb/logfile"
     8  	"github.com/flower-corp/rosedb/logger"
     9  	"github.com/flower-corp/rosedb/util"
    10  	"math"
    11  	"math/rand"
    12  	"regexp"
    13  	"strconv"
    14  	"time"
    15  )
    16  
    17  // HSet sets field in the hash stored at key to value. If key does not exist, a new key holding a hash is created.
    18  // If field already exists in the hash, it is overwritten.
    19  // Return num of elements in hash of the specified key.
    20  // Multiple field-value pair is accepted. Parameter order should be like "key", "field", "value", "field", "value"...
    21  func (db *RoseDB) HSet(key []byte, args ...[]byte) error {
    22  	db.hashIndex.mu.Lock()
    23  	defer db.hashIndex.mu.Unlock()
    24  
    25  	if len(args) == 0 || len(args)&1 == 1 {
    26  		return ErrWrongNumberOfArgs
    27  	}
    28  	if db.hashIndex.trees[string(key)] == nil {
    29  		db.hashIndex.trees[string(key)] = art.NewART()
    30  	}
    31  	idxTree := db.hashIndex.trees[string(key)]
    32  
    33  	// add multiple field value pairs
    34  	for i := 0; i < len(args); i += 2 {
    35  		field, value := args[i], args[i+1]
    36  		hashKey := db.encodeKey(key, field)
    37  		entry := &logfile.LogEntry{Key: hashKey, Value: value}
    38  		valuePos, err := db.writeLogEntry(entry, Hash)
    39  		if err != nil {
    40  			return err
    41  		}
    42  
    43  		ent := &logfile.LogEntry{Key: field, Value: value}
    44  		_, size := logfile.EncodeEntry(entry)
    45  		valuePos.entrySize = size
    46  		err = db.updateIndexTree(idxTree, ent, valuePos, true, Hash)
    47  		if err != nil {
    48  			return err
    49  		}
    50  	}
    51  	return nil
    52  }
    53  
    54  // HSetNX sets the given value only if the field doesn't exist.
    55  // If the key doesn't exist, new hash is created.
    56  // If field already exist, HSetNX doesn't have side effect.
    57  func (db *RoseDB) HSetNX(key, field, value []byte) (bool, error) {
    58  	db.hashIndex.mu.Lock()
    59  	defer db.hashIndex.mu.Unlock()
    60  
    61  	if db.hashIndex.trees[string(key)] == nil {
    62  		db.hashIndex.trees[string(key)] = art.NewART()
    63  	}
    64  	idxTree := db.hashIndex.trees[string(key)]
    65  	val, err := db.getVal(idxTree, field, Hash)
    66  	if err != nil {
    67  		return false, err
    68  	}
    69  
    70  	// field exists in db
    71  	if val != nil {
    72  		return false, nil
    73  	}
    74  	hashKey := db.encodeKey(key, field)
    75  	ent := &logfile.LogEntry{Key: hashKey, Value: value}
    76  	valuePos, err := db.writeLogEntry(ent, Hash)
    77  	if err != nil {
    78  		return false, err
    79  	}
    80  
    81  	entry := &logfile.LogEntry{Key: field, Value: value}
    82  	_, size := logfile.EncodeEntry(ent)
    83  	valuePos.entrySize = size
    84  	err = db.updateIndexTree(idxTree, entry, valuePos, true, Hash)
    85  	if err != nil {
    86  		return false, err
    87  	}
    88  	return true, nil
    89  }
    90  
    91  // HGet returns the value associated with field in the hash stored at key.
    92  func (db *RoseDB) HGet(key, field []byte) ([]byte, error) {
    93  	db.hashIndex.mu.RLock()
    94  	defer db.hashIndex.mu.RUnlock()
    95  
    96  	if db.hashIndex.trees[string(key)] == nil {
    97  		return nil, nil
    98  	}
    99  	idxTree := db.hashIndex.trees[string(key)]
   100  	val, err := db.getVal(idxTree, field, Hash)
   101  	if err == ErrKeyNotFound {
   102  		return nil, nil
   103  	}
   104  	return val, err
   105  }
   106  
   107  // HMGet returns the values associated with the specified fields in the hash stored at the key.
   108  // For every field that does not exist in the hash, a nil value is returned.
   109  // Because non-existing keys are treated as empty hashes,
   110  // running HMGET against a non-existing key will return a list of nil values.
   111  func (db *RoseDB) HMGet(key []byte, fields ...[]byte) (vals [][]byte, err error) {
   112  	db.hashIndex.mu.RLock()
   113  	defer db.hashIndex.mu.RUnlock()
   114  
   115  	length := len(fields)
   116  	// key not exist
   117  	if db.hashIndex.trees[string(key)] == nil {
   118  		for i := 0; i < length; i++ {
   119  			vals = append(vals, nil)
   120  		}
   121  		return vals, nil
   122  	}
   123  	// key exist
   124  	idxTree := db.hashIndex.trees[string(key)]
   125  
   126  	for _, field := range fields {
   127  		val, err := db.getVal(idxTree, field, Hash)
   128  		if err == ErrKeyNotFound {
   129  			vals = append(vals, nil)
   130  		} else {
   131  			vals = append(vals, val)
   132  		}
   133  	}
   134  	return
   135  }
   136  
   137  // HDel removes the specified fields from the hash stored at key.
   138  // Specified fields that do not exist within this hash are ignored.
   139  // If key does not exist, it is treated as an empty hash and this command returns false.
   140  func (db *RoseDB) HDel(key []byte, fields ...[]byte) (int, error) {
   141  	db.hashIndex.mu.Lock()
   142  	defer db.hashIndex.mu.Unlock()
   143  
   144  	if db.hashIndex.trees[string(key)] == nil {
   145  		return 0, nil
   146  	}
   147  	idxTree := db.hashIndex.trees[string(key)]
   148  
   149  	var count int
   150  	for _, field := range fields {
   151  		hashKey := db.encodeKey(key, field)
   152  		entry := &logfile.LogEntry{Key: hashKey, Type: logfile.TypeDelete}
   153  		valuePos, err := db.writeLogEntry(entry, Hash)
   154  		if err != nil {
   155  			return 0, err
   156  		}
   157  
   158  		val, updated := idxTree.Delete(field)
   159  		if updated {
   160  			count++
   161  		}
   162  		db.sendDiscard(val, updated, Hash)
   163  		// The deleted entry itself is also invalid.
   164  		_, size := logfile.EncodeEntry(entry)
   165  		node := &indexNode{fid: valuePos.fid, entrySize: size}
   166  		select {
   167  		case db.discards[Hash].valChan <- node:
   168  		default:
   169  			logger.Warn("send to discard chan fail")
   170  		}
   171  	}
   172  	return count, nil
   173  }
   174  
   175  // HExists returns whether the field exists in the hash stored at key.
   176  // If the hash contains field, it returns true.
   177  // If the hash does not contain field, or key does not exist, it returns false.
   178  func (db *RoseDB) HExists(key, field []byte) (bool, error) {
   179  	db.hashIndex.mu.RLock()
   180  	defer db.hashIndex.mu.RUnlock()
   181  
   182  	if db.hashIndex.trees[string(key)] == nil {
   183  		return false, nil
   184  	}
   185  	idxTree := db.hashIndex.trees[string(key)]
   186  	val, err := db.getVal(idxTree, field, Hash)
   187  	if err != nil && err != ErrKeyNotFound {
   188  		return false, err
   189  	}
   190  	return val != nil, nil
   191  }
   192  
   193  // HLen returns the number of fields contained in the hash stored at key.
   194  func (db *RoseDB) HLen(key []byte) int {
   195  	db.hashIndex.mu.RLock()
   196  	defer db.hashIndex.mu.RUnlock()
   197  
   198  	if db.hashIndex.trees[string(key)] == nil {
   199  		return 0
   200  	}
   201  	idxTree := db.hashIndex.trees[string(key)]
   202  	return idxTree.Size()
   203  }
   204  
   205  // HKeys returns all field names in the hash stored at key.
   206  func (db *RoseDB) HKeys(key []byte) ([][]byte, error) {
   207  	db.hashIndex.mu.RLock()
   208  	defer db.hashIndex.mu.RUnlock()
   209  
   210  	var keys [][]byte
   211  	tree, ok := db.hashIndex.trees[string(key)]
   212  	if !ok {
   213  		return keys, nil
   214  	}
   215  	iter := tree.Iterator()
   216  	for iter.HasNext() {
   217  		node, err := iter.Next()
   218  		if err != nil {
   219  			return nil, err
   220  		}
   221  		keys = append(keys, node.Key())
   222  	}
   223  	return keys, nil
   224  }
   225  
   226  // HVals return all values in the hash stored at key.
   227  func (db *RoseDB) HVals(key []byte) ([][]byte, error) {
   228  	db.hashIndex.mu.RLock()
   229  	defer db.hashIndex.mu.RUnlock()
   230  
   231  	var values [][]byte
   232  	tree, ok := db.hashIndex.trees[string(key)]
   233  	if !ok {
   234  		return values, nil
   235  	}
   236  
   237  	iter := tree.Iterator()
   238  	for iter.HasNext() {
   239  		node, err := iter.Next()
   240  		if err != nil {
   241  			return nil, err
   242  		}
   243  		val, err := db.getVal(tree, node.Key(), Hash)
   244  		if err != nil && err != ErrKeyNotFound {
   245  			return nil, err
   246  		}
   247  		values = append(values, val)
   248  	}
   249  	return values, nil
   250  }
   251  
   252  // HGetAll return all fields and values of the hash stored at key.
   253  func (db *RoseDB) HGetAll(key []byte) ([][]byte, error) {
   254  	db.hashIndex.mu.RLock()
   255  	defer db.hashIndex.mu.RUnlock()
   256  
   257  	tree, ok := db.hashIndex.trees[string(key)]
   258  	if !ok {
   259  		return [][]byte{}, nil
   260  	}
   261  
   262  	var index int
   263  	pairs := make([][]byte, tree.Size()*2)
   264  	iter := tree.Iterator()
   265  	for iter.HasNext() {
   266  		node, err := iter.Next()
   267  		if err != nil {
   268  			return nil, err
   269  		}
   270  		field := node.Key()
   271  		val, err := db.getVal(tree, field, Hash)
   272  		if err != nil && err != ErrKeyNotFound {
   273  			return nil, err
   274  		}
   275  		pairs[index], pairs[index+1] = field, val
   276  		index += 2
   277  	}
   278  	return pairs[:index], nil
   279  }
   280  
   281  // HStrLen returns the string length of the value associated with field in the hash stored at key.
   282  // If the key or the field do not exist, 0 is returned.
   283  func (db *RoseDB) HStrLen(key, field []byte) int {
   284  	db.hashIndex.mu.RLock()
   285  	defer db.hashIndex.mu.RUnlock()
   286  
   287  	if db.hashIndex.trees[string(key)] == nil {
   288  		return 0
   289  	}
   290  	idxTree := db.hashIndex.trees[string(key)]
   291  	val, err := db.getVal(idxTree, field, Hash)
   292  	if err == ErrKeyNotFound {
   293  		return 0
   294  	}
   295  	return len(val)
   296  }
   297  
   298  // HScan iterates over a specified key of type Hash and finds its fields and values.
   299  // Parameter prefix will match field`s prefix, and pattern is a regular expression that also matchs the field.
   300  // Parameter count limits the number of keys, a nil slice will be returned if count is not a positive number.
   301  // The returned values will be a mixed data of fields and values, like [field1, value1, field2, value2, etc...].
   302  func (db *RoseDB) HScan(key []byte, prefix []byte, pattern string, count int) ([][]byte, error) {
   303  	if count <= 0 {
   304  		return nil, nil
   305  	}
   306  
   307  	db.hashIndex.mu.RLock()
   308  	defer db.hashIndex.mu.RUnlock()
   309  	if db.hashIndex.trees[string(key)] == nil {
   310  		return nil, nil
   311  	}
   312  	idxTree := db.hashIndex.trees[string(key)]
   313  	fields := idxTree.PrefixScan(prefix, count)
   314  	if len(fields) == 0 {
   315  		return nil, nil
   316  	}
   317  
   318  	var reg *regexp.Regexp
   319  	if pattern != "" {
   320  		var err error
   321  		if reg, err = regexp.Compile(pattern); err != nil {
   322  			return nil, err
   323  		}
   324  	}
   325  
   326  	values := make([][]byte, 2*len(fields))
   327  	var index int
   328  	for _, field := range fields {
   329  		if reg != nil && !reg.Match(field) {
   330  			continue
   331  		}
   332  		val, err := db.getVal(idxTree, field, Hash)
   333  		if err != nil && err != ErrKeyNotFound {
   334  			return nil, err
   335  		}
   336  		values[index], values[index+1] = field, val
   337  		index += 2
   338  	}
   339  	return values, nil
   340  }
   341  
   342  // HIncrBy increments the number stored at field in the hash stored at key by increment.
   343  // If key does not exist, a new key holding a hash is created. If field does not exist
   344  // the value is set to 0 before the operation is performed. The range of values supported
   345  // by HINCRBY is limited to 64bit signed integers.
   346  func (db *RoseDB) HIncrBy(key, field []byte, incr int64) (int64, error) {
   347  	db.hashIndex.mu.Lock()
   348  	defer db.hashIndex.mu.Unlock()
   349  
   350  	if db.hashIndex.trees[string(key)] == nil {
   351  		db.hashIndex.trees[string(key)] = art.NewART()
   352  	}
   353  
   354  	idxTree := db.hashIndex.trees[string(key)]
   355  	val, err := db.getVal(idxTree, field, Hash)
   356  	if err != nil && !errors.Is(err, ErrKeyNotFound) {
   357  		return 0, err
   358  	}
   359  	if bytes.Equal(val, nil) {
   360  		val = []byte("0")
   361  	}
   362  	valInt64, err := util.StrToInt64(string(val))
   363  	if err != nil {
   364  		return 0, ErrWrongValueType
   365  	}
   366  
   367  	if (incr < 0 && valInt64 < 0 && incr < (math.MinInt64-valInt64)) ||
   368  		(incr > 0 && valInt64 > 0 && incr > (math.MaxInt64-valInt64)) {
   369  		return 0, ErrIntegerOverflow
   370  	}
   371  
   372  	valInt64 += incr
   373  	val = []byte(strconv.FormatInt(valInt64, 10))
   374  
   375  	hashKey := db.encodeKey(key, field)
   376  	ent := &logfile.LogEntry{Key: hashKey, Value: val}
   377  	valuePos, err := db.writeLogEntry(ent, Hash)
   378  	if err != nil {
   379  		return 0, err
   380  	}
   381  
   382  	entry := &logfile.LogEntry{Key: field, Value: val}
   383  	_, size := logfile.EncodeEntry(ent)
   384  	valuePos.entrySize = size
   385  	err = db.updateIndexTree(idxTree, entry, valuePos, true, Hash)
   386  	if err != nil {
   387  		return 0, err
   388  	}
   389  	return valInt64, nil
   390  }
   391  
   392  // HRandField returns a random field from the hash value stored at key, when called with just
   393  // the key argument. If the provided count argument is positive, return an array of distinct
   394  // fields. If called with a negative count, the behavior changes and the command is allowed
   395  // to return the same field multiple times.
   396  func (db *RoseDB) HRandField(key []byte, count int, withValues bool) ([][]byte, error) {
   397  	if count == 0 {
   398  		return [][]byte{}, nil
   399  	}
   400  	var values [][]byte
   401  	var err error
   402  	var pairLength = 1
   403  	if !withValues {
   404  		values, err = db.HKeys(key)
   405  	} else {
   406  		pairLength = 2
   407  		values, err = db.HGetAll(key)
   408  	}
   409  	if err != nil {
   410  		return [][]byte{}, err
   411  	}
   412  	if len(values) == 0 {
   413  		return [][]byte{}, nil
   414  	}
   415  
   416  	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
   417  	pairCount := len(values) / pairLength
   418  
   419  	// return an array of distinct fields
   420  	if count > 0 {
   421  		// return all fields
   422  		if count >= pairCount {
   423  			return values, nil
   424  		}
   425  		// reduce diff count to avoid creating duplicates
   426  		var noDupValues = values
   427  		diff := pairCount - count
   428  		for i := 0; i < diff; i++ {
   429  			rndIdx := rnd.Intn(len(noDupValues)/pairLength) * pairLength
   430  			noDupValues = append(noDupValues[:rndIdx], noDupValues[rndIdx+pairLength:]...)
   431  		}
   432  		return noDupValues, nil
   433  	}
   434  	// return the same field multiple times
   435  	count = -count
   436  	var dupValues [][]byte
   437  	for i := 0; i < count; i++ {
   438  		rndIdx := rnd.Intn(pairCount) * pairLength
   439  		dupValues = append(dupValues, values[rndIdx:rndIdx+pairLength]...)
   440  	}
   441  	return dupValues, nil
   442  }