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

     1  package rosedb
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"github.com/flower-corp/rosedb/logfile"
     7  	"github.com/flower-corp/rosedb/logger"
     8  	"github.com/flower-corp/rosedb/util"
     9  	"math"
    10  	"regexp"
    11  	"strconv"
    12  	"time"
    13  )
    14  
    15  // Set set key to hold the string value. If key already holds a value, it is overwritten.
    16  // Any previous time to live associated with the key is discarded on successful Set operation.
    17  func (db *RoseDB) Set(key, value []byte) error {
    18  	db.strIndex.mu.Lock()
    19  	defer db.strIndex.mu.Unlock()
    20  
    21  	// write entry to log file.
    22  	entry := &logfile.LogEntry{Key: key, Value: value}
    23  	valuePos, err := db.writeLogEntry(entry, String)
    24  	if err != nil {
    25  		return err
    26  	}
    27  	// set String index info, stored at adaptive radix tree.
    28  	err = db.updateIndexTree(db.strIndex.idxTree, entry, valuePos, true, String)
    29  	return err
    30  }
    31  
    32  // Get get the value of key.
    33  // If the key does not exist the error ErrKeyNotFound is returned.
    34  func (db *RoseDB) Get(key []byte) ([]byte, error) {
    35  	db.strIndex.mu.RLock()
    36  	defer db.strIndex.mu.RUnlock()
    37  	return db.getVal(db.strIndex.idxTree, key, String)
    38  }
    39  
    40  // MGet get the values of all specified keys.
    41  // If the key that does not hold a string value or does not exist, nil is returned.
    42  func (db *RoseDB) MGet(keys [][]byte) ([][]byte, error) {
    43  	db.strIndex.mu.RLock()
    44  	defer db.strIndex.mu.RUnlock()
    45  
    46  	if len(keys) == 0 {
    47  		return nil, ErrWrongNumberOfArgs
    48  	}
    49  	values := make([][]byte, len(keys))
    50  	for i, key := range keys {
    51  		val, err := db.getVal(db.strIndex.idxTree, key, String)
    52  		if err != nil && !errors.Is(ErrKeyNotFound, err) {
    53  			return nil, err
    54  		}
    55  		values[i] = val
    56  	}
    57  	return values, nil
    58  }
    59  
    60  // GetRange returns the substring of the string value stored at key,
    61  // determined by the offsets start and end.
    62  func (db *RoseDB) GetRange(key []byte, start, end int) ([]byte, error) {
    63  	db.strIndex.mu.RLock()
    64  	defer db.strIndex.mu.RUnlock()
    65  
    66  	val, err := db.getVal(db.strIndex.idxTree, key, String)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	if len(val) == 0 {
    71  		return []byte{}, nil
    72  	}
    73  	// Negative offsets can be used in order to provide an offset starting from the end of the string.
    74  	// So -1 means the last character, -2 the penultimate and so forth
    75  	if start < 0 {
    76  		start = len(val) + start
    77  		if start < 0 {
    78  			start = 0
    79  		}
    80  	}
    81  	if end < 0 {
    82  		end = len(val) + end
    83  		if end < 0 {
    84  			end = 0
    85  		}
    86  	}
    87  
    88  	// handles out of range requests by limiting the resulting range to the actual length of the string.
    89  	if end > len(val)-1 {
    90  		end = len(val) - 1
    91  	}
    92  	if start > len(val)-1 || start > end {
    93  		return []byte{}, nil
    94  	}
    95  	return val[start : end+1], nil
    96  }
    97  
    98  // GetDel gets the value of the key and deletes the key. This method is similar
    99  // to Get method. It also deletes the key if it exists.
   100  func (db *RoseDB) GetDel(key []byte) ([]byte, error) {
   101  	db.strIndex.mu.Lock()
   102  	defer db.strIndex.mu.Unlock()
   103  
   104  	val, err := db.getVal(db.strIndex.idxTree, key, String)
   105  	if err != nil && err != ErrKeyNotFound {
   106  		return nil, err
   107  	}
   108  	if val == nil {
   109  		return nil, nil
   110  	}
   111  
   112  	entry := &logfile.LogEntry{Key: key, Type: logfile.TypeDelete}
   113  	pos, err := db.writeLogEntry(entry, String)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	oldVal, updated := db.strIndex.idxTree.Delete(key)
   119  	db.sendDiscard(oldVal, updated, String)
   120  	_, size := logfile.EncodeEntry(entry)
   121  	node := &indexNode{fid: pos.fid, entrySize: size}
   122  	select {
   123  	case db.discards[String].valChan <- node:
   124  	default:
   125  		logger.Warn("send to discard chan fail")
   126  	}
   127  	return val, nil
   128  }
   129  
   130  // Delete value at the given key.
   131  func (db *RoseDB) Delete(key []byte) error {
   132  	db.strIndex.mu.Lock()
   133  	defer db.strIndex.mu.Unlock()
   134  
   135  	entry := &logfile.LogEntry{Key: key, Type: logfile.TypeDelete}
   136  	pos, err := db.writeLogEntry(entry, String)
   137  	if err != nil {
   138  		return err
   139  	}
   140  	val, updated := db.strIndex.idxTree.Delete(key)
   141  	db.sendDiscard(val, updated, String)
   142  	// The deleted entry itself is also invalid.
   143  	_, size := logfile.EncodeEntry(entry)
   144  	node := &indexNode{fid: pos.fid, entrySize: size}
   145  	select {
   146  	case db.discards[String].valChan <- node:
   147  	default:
   148  		logger.Warn("send to discard chan fail")
   149  	}
   150  	return nil
   151  }
   152  
   153  // SetEX set key to hold the string value and set key to timeout after the given duration.
   154  func (db *RoseDB) SetEX(key, value []byte, duration time.Duration) error {
   155  	db.strIndex.mu.Lock()
   156  	defer db.strIndex.mu.Unlock()
   157  
   158  	expiredAt := time.Now().Add(duration).Unix()
   159  	entry := &logfile.LogEntry{Key: key, Value: value, ExpiredAt: expiredAt}
   160  	valuePos, err := db.writeLogEntry(entry, String)
   161  	if err != nil {
   162  		return err
   163  	}
   164  
   165  	return db.updateIndexTree(db.strIndex.idxTree, entry, valuePos, true, String)
   166  }
   167  
   168  // SetNX sets the key-value pair if it is not exist. It returns nil if the key already exists.
   169  func (db *RoseDB) SetNX(key, value []byte) error {
   170  	db.strIndex.mu.Lock()
   171  	defer db.strIndex.mu.Unlock()
   172  
   173  	val, err := db.getVal(db.strIndex.idxTree, key, String)
   174  	if err != nil && !errors.Is(err, ErrKeyNotFound) {
   175  		return err
   176  	}
   177  	// Key exists in db.
   178  	if val != nil {
   179  		return nil
   180  	}
   181  
   182  	entry := &logfile.LogEntry{Key: key, Value: value}
   183  	valuePos, err := db.writeLogEntry(entry, String)
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	return db.updateIndexTree(db.strIndex.idxTree, entry, valuePos, true, String)
   189  }
   190  
   191  // MSet is multiple set command. Parameter order should be like "key", "value", "key", "value", ...
   192  func (db *RoseDB) MSet(args ...[]byte) error {
   193  	db.strIndex.mu.Lock()
   194  	defer db.strIndex.mu.Unlock()
   195  
   196  	if len(args) == 0 || len(args)%2 != 0 {
   197  		return ErrWrongNumberOfArgs
   198  	}
   199  
   200  	// Add multiple key-value pairs.
   201  	for i := 0; i < len(args); i += 2 {
   202  		key, value := args[i], args[i+1]
   203  		entry := &logfile.LogEntry{Key: key, Value: value}
   204  		valuePos, err := db.writeLogEntry(entry, String)
   205  		if err != nil {
   206  			return err
   207  		}
   208  		err = db.updateIndexTree(db.strIndex.idxTree, entry, valuePos, true, String)
   209  		if err != nil {
   210  			return err
   211  		}
   212  	}
   213  	return nil
   214  }
   215  
   216  // MSetNX sets given keys to their respective values. MSetNX will not perform
   217  // any operation at all even if just a single key already exists.
   218  func (db *RoseDB) MSetNX(args ...[]byte) error {
   219  	db.strIndex.mu.Lock()
   220  	defer db.strIndex.mu.Unlock()
   221  
   222  	if len(args) == 0 || len(args)%2 != 0 {
   223  		return ErrWrongNumberOfArgs
   224  	}
   225  
   226  	// Firstly, check each keys whether they are exists.
   227  	for i := 0; i < len(args); i += 2 {
   228  		key := args[i]
   229  		val, err := db.getVal(db.strIndex.idxTree, key, String)
   230  		if err != nil && !errors.Is(err, ErrKeyNotFound) {
   231  			return err
   232  		}
   233  
   234  		// Key exists in db. We discard the rest of the key-value pairs. It
   235  		// provides the atomicity of the method.
   236  		if val != nil {
   237  			return nil
   238  		}
   239  	}
   240  
   241  	var addedKeys = make(map[uint64]struct{})
   242  	// Set keys to their values.
   243  	for i := 0; i < len(args); i += 2 {
   244  		key, value := args[i], args[i+1]
   245  		h := util.MemHash(key)
   246  		if _, ok := addedKeys[h]; ok {
   247  			continue
   248  		}
   249  		entry := &logfile.LogEntry{Key: key, Value: value}
   250  		valPos, err := db.writeLogEntry(entry, String)
   251  		if err != nil {
   252  			return err
   253  		}
   254  		err = db.updateIndexTree(db.strIndex.idxTree, entry, valPos, true, String)
   255  		if err != nil {
   256  			return err
   257  		}
   258  		addedKeys[h] = struct{}{}
   259  	}
   260  	return nil
   261  }
   262  
   263  // Append appends the value at the end of the old value if key already exists.
   264  // It will be similar to Set if key does not exist.
   265  func (db *RoseDB) Append(key, value []byte) error {
   266  	db.strIndex.mu.Lock()
   267  	defer db.strIndex.mu.Unlock()
   268  
   269  	oldVal, err := db.getVal(db.strIndex.idxTree, key, String)
   270  	if err != nil && !errors.Is(err, ErrKeyNotFound) {
   271  		return err
   272  	}
   273  
   274  	// Key exists in db.
   275  	if oldVal != nil {
   276  		value = append(oldVal, value...)
   277  	}
   278  	// write entry to log file.
   279  	entry := &logfile.LogEntry{Key: key, Value: value}
   280  	valuePos, err := db.writeLogEntry(entry, String)
   281  	if err != nil {
   282  		return err
   283  	}
   284  	err = db.updateIndexTree(db.strIndex.idxTree, entry, valuePos, true, String)
   285  	return err
   286  }
   287  
   288  // Decr decrements the number stored at key by one. If the key does not exist,
   289  // it is set to 0 before performing the operation. It returns ErrWrongKeyType
   290  // error if the value is not integer type. Also, it returns ErrIntegerOverflow
   291  // error if the value exceeds after decrementing the value.
   292  func (db *RoseDB) Decr(key []byte) (int64, error) {
   293  	db.strIndex.mu.Lock()
   294  	defer db.strIndex.mu.Unlock()
   295  	return db.incrDecrBy(key, -1)
   296  }
   297  
   298  // DecrBy decrements the number stored at key by decr. If the key doesn't
   299  // exist, it is set to 0 before performing the operation. It returns ErrWrongKeyType
   300  // error if the value is not integer type. Also, it returns ErrIntegerOverflow
   301  // error if the value exceeds after decrementing the value.
   302  func (db *RoseDB) DecrBy(key []byte, decr int64) (int64, error) {
   303  	db.strIndex.mu.Lock()
   304  	defer db.strIndex.mu.Unlock()
   305  	return db.incrDecrBy(key, -decr)
   306  }
   307  
   308  // Incr increments the number stored at key by one. If the key does not exist,
   309  // it is set to 0 before performing the operation. It returns ErrWrongKeyType
   310  // error if the value is not integer type. Also, it returns ErrIntegerOverflow
   311  // error if the value exceeds after incrementing the value.
   312  func (db *RoseDB) Incr(key []byte) (int64, error) {
   313  	db.strIndex.mu.Lock()
   314  	defer db.strIndex.mu.Unlock()
   315  	return db.incrDecrBy(key, 1)
   316  }
   317  
   318  // IncrBy increments the number stored at key by incr. If the key doesn't
   319  // exist, it is set to 0 before performing the operation. It returns ErrWrongKeyType
   320  // error if the value is not integer type. Also, it returns ErrIntegerOverflow
   321  // error if the value exceeds after incrementing the value.
   322  func (db *RoseDB) IncrBy(key []byte, incr int64) (int64, error) {
   323  	db.strIndex.mu.Lock()
   324  	defer db.strIndex.mu.Unlock()
   325  	return db.incrDecrBy(key, incr)
   326  }
   327  
   328  // incrDecrBy is a helper method for Incr, IncrBy, Decr, and DecrBy methods. It updates the key by incr.
   329  func (db *RoseDB) incrDecrBy(key []byte, incr int64) (int64, error) {
   330  	val, err := db.getVal(db.strIndex.idxTree, key, String)
   331  	if err != nil && !errors.Is(err, ErrKeyNotFound) {
   332  		return 0, err
   333  	}
   334  	if bytes.Equal(val, nil) {
   335  		val = []byte("0")
   336  	}
   337  	valInt64, err := strconv.ParseInt(string(val), 10, 64)
   338  	if err != nil {
   339  		return 0, ErrWrongValueType
   340  	}
   341  
   342  	if (incr < 0 && valInt64 < 0 && incr < (math.MinInt64-valInt64)) ||
   343  		(incr > 0 && valInt64 > 0 && incr > (math.MaxInt64-valInt64)) {
   344  		return 0, ErrIntegerOverflow
   345  	}
   346  
   347  	valInt64 += incr
   348  	val = []byte(strconv.FormatInt(valInt64, 10))
   349  	entry := &logfile.LogEntry{Key: key, Value: val}
   350  	valuePos, err := db.writeLogEntry(entry, String)
   351  	if err != nil {
   352  		return 0, err
   353  	}
   354  	err = db.updateIndexTree(db.strIndex.idxTree, entry, valuePos, true, String)
   355  	if err != nil {
   356  		return 0, err
   357  	}
   358  	return valInt64, nil
   359  }
   360  
   361  // StrLen returns the length of the string value stored at key. If the key
   362  // doesn't exist, it returns 0.
   363  func (db *RoseDB) StrLen(key []byte) int {
   364  	db.strIndex.mu.RLock()
   365  	defer db.strIndex.mu.RUnlock()
   366  
   367  	val, err := db.getVal(db.strIndex.idxTree, key, String)
   368  	if err != nil {
   369  		return 0
   370  	}
   371  	return len(val)
   372  }
   373  
   374  // Count returns the total number of keys of String.
   375  func (db *RoseDB) Count() int {
   376  	db.strIndex.mu.RLock()
   377  	defer db.strIndex.mu.RUnlock()
   378  
   379  	if db.strIndex.idxTree == nil {
   380  		return 0
   381  	}
   382  	return db.strIndex.idxTree.Size()
   383  }
   384  
   385  // Scan iterates over all keys of type String and finds its value.
   386  // Parameter prefix will match key`s prefix, and pattern is a regular expression that also matchs the key.
   387  // Parameter count limits the number of keys, a nil slice will be returned if count is not a positive number.
   388  // The returned values will be a mixed data of keys and values, like [key1, value1, key2, value2, etc...].
   389  func (db *RoseDB) Scan(prefix []byte, pattern string, count int) ([][]byte, error) {
   390  	if count <= 0 {
   391  		return nil, nil
   392  	}
   393  
   394  	var reg *regexp.Regexp
   395  	if pattern != "" {
   396  		var err error
   397  		if reg, err = regexp.Compile(pattern); err != nil {
   398  			return nil, err
   399  		}
   400  	}
   401  
   402  	db.strIndex.mu.RLock()
   403  	defer db.strIndex.mu.RUnlock()
   404  	if db.strIndex.idxTree == nil {
   405  		return nil, nil
   406  	}
   407  	keys := db.strIndex.idxTree.PrefixScan(prefix, count)
   408  	if len(keys) == 0 {
   409  		return nil, nil
   410  	}
   411  
   412  	var results [][]byte
   413  	for _, key := range keys {
   414  		if reg != nil && !reg.Match(key) {
   415  			continue
   416  		}
   417  		val, err := db.getVal(db.strIndex.idxTree, key, String)
   418  		if err != nil && err != ErrKeyNotFound {
   419  			return nil, err
   420  		}
   421  		if err != ErrKeyNotFound {
   422  			results = append(results, key, val)
   423  		}
   424  	}
   425  	return results, nil
   426  }
   427  
   428  // Expire set the expiration time for the given key.
   429  func (db *RoseDB) Expire(key []byte, duration time.Duration) error {
   430  	if duration <= 0 {
   431  		return nil
   432  	}
   433  	db.strIndex.mu.Lock()
   434  	val, err := db.getVal(db.strIndex.idxTree, key, String)
   435  	if err != nil {
   436  		db.strIndex.mu.Unlock()
   437  		return err
   438  	}
   439  	db.strIndex.mu.Unlock()
   440  	return db.SetEX(key, val, duration)
   441  }
   442  
   443  // TTL get ttl(time to live) for the given key.
   444  func (db *RoseDB) TTL(key []byte) (int64, error) {
   445  	db.strIndex.mu.Lock()
   446  	defer db.strIndex.mu.Unlock()
   447  
   448  	node, err := db.getIndexNode(db.strIndex.idxTree, key)
   449  	if err != nil {
   450  		return 0, err
   451  	}
   452  	var ttl int64
   453  	if node.expiredAt != 0 {
   454  		ttl = node.expiredAt - time.Now().Unix()
   455  	}
   456  	return ttl, nil
   457  }
   458  
   459  // Persist remove the expiration time for the given key.
   460  func (db *RoseDB) Persist(key []byte) error {
   461  	db.strIndex.mu.Lock()
   462  	val, err := db.getVal(db.strIndex.idxTree, key, String)
   463  	if err != nil {
   464  		db.strIndex.mu.Unlock()
   465  		return err
   466  	}
   467  	db.strIndex.mu.Unlock()
   468  
   469  	return db.Set(key, val)
   470  }
   471  
   472  // GetStrsKeys get all stored keys of type String.
   473  func (db *RoseDB) GetStrsKeys() ([][]byte, error) {
   474  	db.strIndex.mu.RLock()
   475  	defer db.strIndex.mu.RUnlock()
   476  
   477  	if db.strIndex.idxTree == nil {
   478  		return nil, nil
   479  	}
   480  
   481  	var keys [][]byte
   482  	iter := db.strIndex.idxTree.Iterator()
   483  	ts := time.Now().Unix()
   484  	for iter.HasNext() {
   485  		node, err := iter.Next()
   486  		if err != nil {
   487  			return nil, err
   488  		}
   489  		indexNode, _ := node.Value().(*indexNode)
   490  		if indexNode == nil {
   491  			continue
   492  		}
   493  		if indexNode.expiredAt != 0 && indexNode.expiredAt <= ts {
   494  			continue
   495  		}
   496  		keys = append(keys, node.Key())
   497  	}
   498  	return keys, nil
   499  }