Use absolute expiration in peristed db file

This commit ensures that the absolute unix expiration timestamp
is stored for applicable records in the persisted db file.

Previously the relative seconds was stored.

fixes #85
This commit is contained in:
tidwall 2023-04-13 07:30:20 -07:00
parent 71088bcabf
commit 4ac2e321b1
1 changed files with 23 additions and 8 deletions

View File

@ -61,6 +61,8 @@ var (
ErrTxIterating = errors.New("tx is iterating") ErrTxIterating = errors.New("tx is iterating")
) )
const useAbsEx = true
// DB represents a collection of key-value pairs that persist on disk. // DB represents a collection of key-value pairs that persist on disk.
// Transactions are used for all forms of data access to the DB. // Transactions are used for all forms of data access to the DB.
type DB struct { type DB struct {
@ -895,22 +897,29 @@ func (db *DB) readLoad(rd io.Reader, modTime time.Time) (n int64, err error) {
return totalSize, ErrInvalid return totalSize, ErrInvalid
} }
if len(parts) == 5 { if len(parts) == 5 {
if strings.ToLower(parts[3]) != "ex" { arg := strings.ToLower(parts[3])
if arg != "ex" && arg != "ae" {
return totalSize, ErrInvalid return totalSize, ErrInvalid
} }
ex, err := strconv.ParseUint(parts[4], 10, 64) ex, err := strconv.ParseInt(parts[4], 10, 64)
if err != nil { if err != nil {
return totalSize, err return totalSize, err
} }
var exat time.Time
now := time.Now() now := time.Now()
dur := (time.Duration(ex) * time.Second) - now.Sub(modTime) if arg == "ex" {
if dur > 0 { dur := (time.Duration(ex) * time.Second) - now.Sub(modTime)
exat = now.Add(dur)
} else {
exat = time.Unix(ex, 0)
}
if exat.After(now) {
db.insertIntoDatabase(&dbItem{ db.insertIntoDatabase(&dbItem{
key: parts[1], key: parts[1],
val: parts[2], val: parts[2],
opts: &dbItemOpts{ opts: &dbItemOpts{
ex: true, ex: true,
exat: now.Add(dur), exat: exat,
}, },
}) })
} }
@ -1330,13 +1339,19 @@ func appendBulkString(buf []byte, s string) []byte {
// writeSetTo writes an item as a single SET record to the a bufio Writer. // writeSetTo writes an item as a single SET record to the a bufio Writer.
func (dbi *dbItem) writeSetTo(buf []byte, now time.Time) []byte { func (dbi *dbItem) writeSetTo(buf []byte, now time.Time) []byte {
if dbi.opts != nil && dbi.opts.ex { if dbi.opts != nil && dbi.opts.ex {
ex := dbi.opts.exat.Sub(now) / time.Second
buf = appendArray(buf, 5) buf = appendArray(buf, 5)
buf = appendBulkString(buf, "set") buf = appendBulkString(buf, "set")
buf = appendBulkString(buf, dbi.key) buf = appendBulkString(buf, dbi.key)
buf = appendBulkString(buf, dbi.val) buf = appendBulkString(buf, dbi.val)
buf = appendBulkString(buf, "ex") if useAbsEx {
buf = appendBulkString(buf, strconv.FormatUint(uint64(ex), 10)) ex := dbi.opts.exat.Unix()
buf = appendBulkString(buf, "ae")
buf = appendBulkString(buf, strconv.FormatUint(uint64(ex), 10))
} else {
ex := dbi.opts.exat.Sub(now) / time.Second
buf = appendBulkString(buf, "ex")
buf = appendBulkString(buf, strconv.FormatUint(uint64(ex), 10))
}
} else { } else {
buf = appendArray(buf, 3) buf = appendArray(buf, 3)
buf = appendBulkString(buf, "set") buf = appendBulkString(buf, "set")