@@ -2,11 +2,13 @@ package structure
2
2
3
3
import (
4
4
"errors"
5
+ "fmt"
5
6
"github.com/ByteStorage/FlyDB/config"
6
7
"github.com/ByteStorage/FlyDB/engine"
7
8
_const "github.com/ByteStorage/FlyDB/lib/const"
8
9
"github.com/ByteStorage/FlyDB/lib/encoding"
9
10
"regexp"
11
+ "time"
10
12
)
11
13
12
14
type SetStructure struct {
@@ -33,8 +35,8 @@ func NewSetStructure(options config.Options) (*SetStructure, error) {
33
35
//
34
36
// If the set did not exist, a new set will be created
35
37
// 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 )
38
40
}
39
41
40
42
/*
@@ -57,30 +59,34 @@ Internal logic:
57
59
58
60
All the methods like 'getZSetFromDB', 'setZSetToDB', and 'add' handle the lower-level logic associated with database interaction and set manipulation.
59
61
*/
60
- func (s * SetStructure ) SAdds (key string , members ... string ) error {
62
+ func (s * SetStructure ) SAdds (key string , ttl int64 , members ... string ) error {
61
63
fs , err := s .checkAndGetSet (key , true )
62
64
if err != nil {
63
65
return err
64
66
}
67
+ var expirationTime time.Duration
65
68
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 )
67
71
}
68
72
69
73
// SRem removes a member from a set
70
74
func (s * SetStructure ) SRem (key , member string ) error {
71
- return s .SRems (key , member )
75
+ return s .SRems (key , 0 , member )
72
76
}
73
77
74
78
// 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 {
76
80
fs , err := s .checkAndGetSet (key , false )
77
81
if err != nil {
78
82
return err
79
83
}
84
+ var expirationTime time.Duration
80
85
if err = fs .remove (members ... ); err != nil {
81
86
return err
82
87
}
83
- return s .setSetToDB (stringToBytesWithKey (key ), fs )
88
+ expirationTime = time .Duration (ttl ) * time .Second
89
+ return s .setSetToDB (stringToBytesWithKey (key ), fs , expirationTime )
84
90
}
85
91
86
92
// SCard gets the cardinality (size) of a set
@@ -268,7 +274,7 @@ func (s *SetStructure) SUnionStore(destination string, keys ...string) error {
268
274
if err != nil {
269
275
return err
270
276
}
271
- return s .SAdds (destination , union ... )
277
+ return s .SAdds (destination , 0 , union ... )
272
278
}
273
279
274
280
/*
@@ -294,7 +300,7 @@ func (s *SetStructure) SInterStore(destination string, keys ...string) error {
294
300
if err != nil {
295
301
return err
296
302
}
297
- return s .SAdds (destination , inter ... )
303
+ return s .SAdds (destination , 0 , inter ... )
298
304
}
299
305
func (s * SetStructure ) checkAndGetSet (key string , createIfNotExist bool ) (* FSets , error ) {
300
306
// Check if value is empty
@@ -303,7 +309,7 @@ func (s *SetStructure) checkAndGetSet(key string, createIfNotExist bool) (*FSets
303
309
}
304
310
keyBytes := stringToBytesWithKey (key )
305
311
// Get the list
306
- set , err := s .getSetFromDB (keyBytes , createIfNotExist )
312
+ set , _ , err := s .getSetFromDB (keyBytes , createIfNotExist )
307
313
if err != nil {
308
314
return nil , err
309
315
}
@@ -364,32 +370,55 @@ func (s *FSets) remove(member ...string) error {
364
370
365
371
// GetSetFromDB retrieves a set from database given a key. If createIfNotExist is true,
366
372
// 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 ) {
368
374
if s .db == nil {
369
- return nil , ErrSetNotInitialized
375
+ return nil , 0 , ErrSetNotInitialized
370
376
}
377
+ var zSetValueWithTTL FSetWithTTL
371
378
dbData , err := s .db .Get (key )
372
- var zSetValue FSets
379
+
373
380
// If key is not found, return nil for both; otherwise return the error.
374
381
if err != nil {
375
382
if errors .Is (err , _const .ErrKeyNotFound ) && createIfNotExist {
376
- return & FSets {}, nil
383
+ return & FSets {}, 0 , nil
377
384
}
378
- return nil , err
385
+ return nil , 0 , err
379
386
} else {
380
- err = encoding .NewMessagePackDecoder (dbData ).Decode (& zSetValue )
387
+ err = encoding .NewMessagePackDecoder (dbData ).Decode (& zSetValueWithTTL ) // Decode the value along with TTL
381
388
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
383
395
}
384
- return & zSetValue , err
396
+
397
+ return zSetValueWithTTL .ZSet , zSetValueWithTTL .TTL , nil // Return the zSetValue and TTL
385
398
}
386
- // return a pointer to the deserialized ZSetNodes, nil for the error
399
+ }
400
+
401
+ type FSetWithTTL struct {
402
+ ZSet * FSets
403
+ TTL int64
387
404
}
388
405
389
406
// 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
+
391
420
val := encoding .NewMessagePackEncoder ()
392
- err := val .Encode (zSetValue )
421
+ err := val .Encode (valueWithTTL ) // Encode the value along with TTL
393
422
if err != nil {
394
423
return err
395
424
}
@@ -402,7 +431,7 @@ func (s *SetStructure) exists(key string, member ...string) bool {
402
431
}
403
432
keyBytes := stringToBytesWithKey (key )
404
433
405
- zSet , err := s .getSetFromDB (keyBytes , false )
434
+ zSet , _ , err := s .getSetFromDB (keyBytes , false )
406
435
407
436
if err != nil {
408
437
return false
@@ -422,3 +451,60 @@ func (s *SetStructure) Stop() error {
422
451
err := s .db .Close ()
423
452
return err
424
453
}
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