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 }