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 }