Skip to content

Commit cd1756d

Browse files
authored
Merge pull request #282 from wangchenguang123/ttl-set
fix some functions in set and list mainly ttl size
2 parents fb9ad86 + 91bdeb7 commit cd1756d

File tree

5 files changed

+312
-103
lines changed

5 files changed

+312
-103
lines changed

engine/grpc/service/set.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func NewSetService(options config.Options) (SetService, error) {
3030
}
3131

3232
func (s *set) SAdd(ctx context.Context, req *gset.SAddRequest) (*gset.EmptyResponse, error) {
33-
err := s.dbs.SAdd(req.Key, req.Member)
33+
err := s.dbs.SAdd(req.Key, req.Member, 0)
3434
if err != nil {
3535
return &gset.EmptyResponse{}, err
3636
}
@@ -39,7 +39,7 @@ func (s *set) SAdd(ctx context.Context, req *gset.SAddRequest) (*gset.EmptyRespo
3939

4040
func (s *set) SAdds(ctx context.Context, req *gset.SAddsRequest) (*gset.EmptyResponse, error) {
4141
for _, member := range req.Members {
42-
err := s.dbs.SAdd(req.Key, member)
42+
err := s.dbs.SAdd(req.Key, member, 0)
4343
if err != nil {
4444
return &gset.EmptyResponse{}, err
4545
}
@@ -56,7 +56,7 @@ func (s *set) SRem(ctx context.Context, req *gset.SRemRequest) (*gset.EmptyRespo
5656
}
5757

5858
func (s *set) SRems(ctx context.Context, req *gset.SRemsRequest) (*gset.EmptyResponse, error) {
59-
err := s.dbs.SRems(req.Key, req.Members...)
59+
err := s.dbs.SRems(req.Key, 0, req.Members...)
6060
if err != nil {
6161
return &gset.EmptyResponse{}, err
6262
}

structure/list.go

+42-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package structure
33
import (
44
"bytes"
55
"errors"
6+
"fmt"
67
"reflect"
78
"regexp"
89
"time"
@@ -586,7 +587,7 @@ func (l *ListStructure) getListFromDB(key string, isKeyCanNotExist bool) (*list,
586587
if len(dbData) != 0 {
587588
return nil, 0, err
588589
} else {
589-
decodedList = &DecodedList{List: &list{nil, 0}, Expiration: -1}
590+
decodedList = &DecodedList{List: &list{nil, 0}, Expiration: 0}
590591
}
591592
}
592593
return decodedList.List, decodedList.Expiration, nil
@@ -711,10 +712,13 @@ func (l *ListStructure) decodeList(value []byte) (*DecodedList, error) {
711712
if err != nil {
712713
return nil, err
713714
}
715+
714716
expiration := expiredItem.Expiration
717+
715718
if expiration != 0 && expiration < time.Now().UnixNano() {
716719
return nil, _const.ErrKeyIsExpired
717720
}
721+
718722
decodedList := &DecodedList{
719723
List: &lst,
720724
Expiration: expiration, // Calculate remaining time
@@ -727,3 +731,40 @@ func (s *ListStructure) Stop() error {
727731
err := s.db.Close()
728732
return err
729733
}
734+
735+
func (l *ListStructure) Size(key string) (string, error) {
736+
Llen, err := l.LLen(key)
737+
if err != nil {
738+
return "", err
739+
}
740+
lRange, err := l.LRange(key, 0, Llen-1)
741+
if err != nil {
742+
return "", err
743+
}
744+
var sizeInBytes int
745+
for _, v := range lRange {
746+
toString, err := interfaceToString(v)
747+
if err != nil {
748+
return "", err
749+
}
750+
sizeInBytes += len(toString)
751+
}
752+
// Convert bytes to corresponding units (KB, MB...)
753+
const (
754+
KB = 1 << 10
755+
MB = 1 << 20
756+
GB = 1 << 30
757+
)
758+
759+
var size string
760+
switch {
761+
case sizeInBytes < KB:
762+
size = fmt.Sprintf("%dB", sizeInBytes)
763+
case sizeInBytes < MB:
764+
size = fmt.Sprintf("%.2fKB", float64(sizeInBytes)/KB)
765+
case sizeInBytes < GB:
766+
size = fmt.Sprintf("%.2fMB", float64(sizeInBytes)/MB)
767+
}
768+
769+
return size, nil
770+
}

structure/list_test.go

+24-8
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,7 @@ func TestListStructure_TTL(t *testing.T) {
2525
list, _ := initList()
2626
defer list.db.Clean()
2727

28-
//err := list.LPush("1", "123123", 0)
29-
//assert.Nil(t, err)
30-
//
31-
//ttl, err := list.TTL("1")
32-
//assert.Nil(t, err)
33-
//assert.Equal(t, ttl, int64(0))
34-
35-
err = list.LPush("2", "123123", 2)
28+
err := list.LPush("2", "123123", 2)
3629
assert.Nil(t, err)
3730

3831
ttl, err := list.TTL("2")
@@ -48,6 +41,28 @@ func TestListStructure_TTL(t *testing.T) {
4841
ttl, err = list.TTL("1")
4942
assert.NotNil(t, err)
5043
assert.Equal(t, ttl, int64(-1))
44+
45+
err = list.LPush("1", "123123", 0)
46+
assert.Nil(t, err)
47+
48+
ttl1, err := list.TTL("1")
49+
assert.Nil(t, err)
50+
assert.Equal(t, ttl1, int64(0))
51+
}
52+
53+
func TestListStructure_Size(t *testing.T) {
54+
list, _ := initList()
55+
defer list.db.Clean()
56+
57+
err = list.LPush("2", "123123", 0)
58+
assert.Nil(t, err)
59+
60+
err = list.LPush("2", "1233", 0)
61+
assert.Nil(t, err)
62+
63+
value, err := list.Size("2")
64+
assert.Nil(t, err)
65+
assert.Equal(t, value, "10B")
5166
}
5267

5368
func TestListStructure_LPush(t *testing.T) {
@@ -109,6 +124,7 @@ func TestListStructure_LPop(t *testing.T) {
109124
// Test LPop function when the key exists
110125
listErr = list.LPush(string(randkv.GetTestKey(1)), randkv.RandomValue(100), 0)
111126
assert.Nil(t, listErr)
127+
listErr = list.LPush(string(randkv.GetTestKey(1)), "www", 0)
112128
value, err := list.LPop(string(randkv.GetTestKey(1)))
113129
assert.Nil(t, err)
114130
assert.NotNil(t, value)

structure/set.go

+108-22
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package structure
22

33
import (
44
"errors"
5+
"fmt"
56
"github.com/ByteStorage/FlyDB/config"
67
"github.com/ByteStorage/FlyDB/engine"
78
_const "github.com/ByteStorage/FlyDB/lib/const"
89
"github.com/ByteStorage/FlyDB/lib/encoding"
910
"regexp"
11+
"time"
1012
)
1113

1214
type SetStructure struct {
@@ -33,8 +35,8 @@ func NewSetStructure(options config.Options) (*SetStructure, error) {
3335
//
3436
// If the set did not exist, a new set will be created
3537
// and the member will be added to it.
36-
func (s *SetStructure) SAdd(key, member string) error {
37-
return s.SAdds(key, member)
38+
func (s *SetStructure) SAdd(key, member string, ttl int64) error {
39+
return s.SAdds(key, ttl, member)
3840
}
3941

4042
/*
@@ -57,30 +59,34 @@ Internal logic:
5759
5860
All the methods like 'getZSetFromDB', 'setZSetToDB', and 'add' handle the lower-level logic associated with database interaction and set manipulation.
5961
*/
60-
func (s *SetStructure) SAdds(key string, members ...string) error {
62+
func (s *SetStructure) SAdds(key string, ttl int64, members ...string) error {
6163
fs, err := s.checkAndGetSet(key, true)
6264
if err != nil {
6365
return err
6466
}
67+
var expirationTime time.Duration
6568
fs.add(members...)
66-
return s.setSetToDB(stringToBytesWithKey(key), fs)
69+
expirationTime = time.Duration(ttl) * time.Second
70+
return s.setSetToDB(stringToBytesWithKey(key), fs, expirationTime)
6771
}
6872

6973
// SRem removes a member from a set
7074
func (s *SetStructure) SRem(key, member string) error {
71-
return s.SRems(key, member)
75+
return s.SRems(key, 0, member)
7276
}
7377

7478
// SRems removes multiple members from a set
75-
func (s *SetStructure) SRems(key string, members ...string) error {
79+
func (s *SetStructure) SRems(key string, ttl int64, members ...string) error {
7680
fs, err := s.checkAndGetSet(key, false)
7781
if err != nil {
7882
return err
7983
}
84+
var expirationTime time.Duration
8085
if err = fs.remove(members...); err != nil {
8186
return err
8287
}
83-
return s.setSetToDB(stringToBytesWithKey(key), fs)
88+
expirationTime = time.Duration(ttl) * time.Second
89+
return s.setSetToDB(stringToBytesWithKey(key), fs, expirationTime)
8490
}
8591

8692
// SCard gets the cardinality (size) of a set
@@ -268,7 +274,7 @@ func (s *SetStructure) SUnionStore(destination string, keys ...string) error {
268274
if err != nil {
269275
return err
270276
}
271-
return s.SAdds(destination, union...)
277+
return s.SAdds(destination, 0, union...)
272278
}
273279

274280
/*
@@ -294,7 +300,7 @@ func (s *SetStructure) SInterStore(destination string, keys ...string) error {
294300
if err != nil {
295301
return err
296302
}
297-
return s.SAdds(destination, inter...)
303+
return s.SAdds(destination, 0, inter...)
298304
}
299305
func (s *SetStructure) checkAndGetSet(key string, createIfNotExist bool) (*FSets, error) {
300306
// Check if value is empty
@@ -303,7 +309,7 @@ func (s *SetStructure) checkAndGetSet(key string, createIfNotExist bool) (*FSets
303309
}
304310
keyBytes := stringToBytesWithKey(key)
305311
// Get the list
306-
set, err := s.getSetFromDB(keyBytes, createIfNotExist)
312+
set, _, err := s.getSetFromDB(keyBytes, createIfNotExist)
307313
if err != nil {
308314
return nil, err
309315
}
@@ -364,32 +370,55 @@ func (s *FSets) remove(member ...string) error {
364370

365371
// GetSetFromDB retrieves a set from database given a key. If createIfNotExist is true,
366372
// a new set will be created if the key is not found. It returns the file sets and any write error encountered.
367-
func (s *SetStructure) getSetFromDB(key []byte, createIfNotExist bool) (*FSets, error) {
373+
func (s *SetStructure) getSetFromDB(key []byte, createIfNotExist bool) (*FSets, int64, error) {
368374
if s.db == nil {
369-
return nil, ErrSetNotInitialized
375+
return nil, 0, ErrSetNotInitialized
370376
}
377+
var zSetValueWithTTL FSetWithTTL
371378
dbData, err := s.db.Get(key)
372-
var zSetValue FSets
379+
373380
// If key is not found, return nil for both; otherwise return the error.
374381
if err != nil {
375382
if errors.Is(err, _const.ErrKeyNotFound) && createIfNotExist {
376-
return &FSets{}, nil
383+
return &FSets{}, 0, nil
377384
}
378-
return nil, err
385+
return nil, 0, err
379386
} else {
380-
err = encoding.NewMessagePackDecoder(dbData).Decode(&zSetValue)
387+
err = encoding.NewMessagePackDecoder(dbData).Decode(&zSetValueWithTTL) // Decode the value along with TTL
381388
if err != nil {
382-
return nil, err
389+
return nil, 0, err
390+
}
391+
392+
expiration := zSetValueWithTTL.TTL
393+
if expiration != 0 && expiration < time.Now().UnixNano() {
394+
return nil, -1, _const.ErrKeyIsExpired
383395
}
384-
return &zSetValue, err
396+
397+
return zSetValueWithTTL.ZSet, zSetValueWithTTL.TTL, nil // Return the zSetValue and TTL
385398
}
386-
// return a pointer to the deserialized ZSetNodes, nil for the error
399+
}
400+
401+
type FSetWithTTL struct {
402+
ZSet *FSets
403+
TTL int64
387404
}
388405

389406
// setSetToDB
390-
func (s *SetStructure) setSetToDB(key []byte, zSetValue *FSets) error {
407+
func (s *SetStructure) setSetToDB(key []byte, zSetValue *FSets, ttl time.Duration) error {
408+
// create a new zSetValueWithTTL struct
409+
var expire int64 = 0
410+
411+
if ttl != 0 {
412+
expire = time.Now().Add(ttl).UnixNano()
413+
}
414+
415+
valueWithTTL := &FSetWithTTL{
416+
ZSet: zSetValue,
417+
TTL: expire,
418+
}
419+
391420
val := encoding.NewMessagePackEncoder()
392-
err := val.Encode(zSetValue)
421+
err := val.Encode(valueWithTTL) // Encode the value along with TTL
393422
if err != nil {
394423
return err
395424
}
@@ -402,7 +431,7 @@ func (s *SetStructure) exists(key string, member ...string) bool {
402431
}
403432
keyBytes := stringToBytesWithKey(key)
404433

405-
zSet, err := s.getSetFromDB(keyBytes, false)
434+
zSet, _, err := s.getSetFromDB(keyBytes, false)
406435

407436
if err != nil {
408437
return false
@@ -422,3 +451,60 @@ func (s *SetStructure) Stop() error {
422451
err := s.db.Close()
423452
return err
424453
}
454+
455+
func (s *SetStructure) TTL(k string) (int64, error) {
456+
keyBytes := stringToBytesWithKey(k)
457+
_, expire, err := s.getSetFromDB(keyBytes, false)
458+
if err != nil {
459+
return -1, err
460+
}
461+
462+
now := time.Now().UnixNano() / int64(time.Second)
463+
expire = expire / int64(time.Second)
464+
465+
remainingTTL := expire - now
466+
467+
//println("re",remainingTTL)
468+
if remainingTTL <= 0 {
469+
return 0, nil // Return 0 TTL for expired keys
470+
}
471+
472+
return remainingTTL, nil
473+
}
474+
475+
func (s *SetStructure) Size(key string) (string, error) {
476+
477+
members, err := s.SMembers(key)
478+
if err != nil {
479+
return "", err
480+
}
481+
var sizeInBytes int
482+
483+
// Calculate the size of the value
484+
for _, v := range members {
485+
toString, err := interfaceToString(v)
486+
if err != nil {
487+
return "", err
488+
}
489+
sizeInBytes += len(toString)
490+
}
491+
492+
// Convert bytes to corresponding units (KB, MB...)
493+
const (
494+
KB = 1 << 10
495+
MB = 1 << 20
496+
GB = 1 << 30
497+
)
498+
499+
var size string
500+
switch {
501+
case sizeInBytes < KB:
502+
size = fmt.Sprintf("%dB", sizeInBytes)
503+
case sizeInBytes < MB:
504+
size = fmt.Sprintf("%.2fKB", float64(sizeInBytes)/KB)
505+
case sizeInBytes < GB:
506+
size = fmt.Sprintf("%.2fMB", float64(sizeInBytes)/MB)
507+
}
508+
509+
return size, nil
510+
}

0 commit comments

Comments
 (0)