track ttl between database reopens, fixes #11

This commit is contained in:
Josh Baker 2016-08-23 08:09:19 -07:00
parent 93cc8f3fcb
commit 7fb2c48afb
2 changed files with 67 additions and 10 deletions

View File

@ -160,6 +160,7 @@ func (db *DB) Close() error {
}
db.closed = true
if db.persist {
db.file.Sync() // do a sync but ignore the error
if err := db.file.Close(); err != nil {
return err
}
@ -657,6 +658,11 @@ var errValidEOF = errors.New("valid eof")
// http://redis.io/topics/protocol. The only supported RESP commands are DEL and
// SET.
func (db *DB) load() error {
fi, err := db.file.Stat()
if err != nil {
return err
}
modTime := fi.ModTime()
data := make([]byte, 4096)
parts := make([]string, 0, 8)
r := bufio.NewReader(db.file)
@ -764,15 +770,18 @@ func (db *DB) load() error {
if err != nil {
return err
}
dur := time.Duration(ex) * time.Second
db.insertIntoDatabase(&dbItem{
key: parts[1],
val: parts[2],
opts: &dbItemOpts{
ex: true,
exat: time.Now().Add(dur),
},
})
now := time.Now()
dur := (time.Duration(ex) * time.Second) - now.Sub(modTime)
if dur > 0 {
db.insertIntoDatabase(&dbItem{
key: parts[1],
val: parts[2],
opts: &dbItemOpts{
ex: true,
exat: now.Add(dur),
},
})
}
} else {
db.insertIntoDatabase(&dbItem{key: parts[1], val: parts[2]})
}

View File

@ -20,13 +20,17 @@ func testOpen(t testing.TB) *DB {
}
return testReOpen(t, nil)
}
func testReOpen(t testing.TB, db *DB) *DB {
return testReOpenDelay(t, db, 0)
}
func testReOpenDelay(t testing.TB, db *DB, dur time.Duration) *DB {
if db != nil {
if err := db.Close(); err != nil {
t.Fatal(err)
}
}
time.Sleep(dur)
db, err := Open("data.db")
if err != nil {
t.Fatal(err)
@ -1353,6 +1357,50 @@ func TestRectStrings(t *testing.T) {
}
}
// TestTTLReOpen test setting a TTL and then immediatelly closing the database and
// then waiting the TTL before reopening. The key should not be accessible.
func TestTTLReOpen(t *testing.T) {
ttl := time.Second * 3
db := testOpen(t)
defer testClose(db)
err := db.Update(func(tx *Tx) error {
if _, _, err := tx.Set("key1", "val1", &SetOptions{Expires: true, TTL: ttl}); err != nil {
return err
}
return nil
})
if err != nil {
t.Fatal(err)
}
db = testReOpenDelay(t, db, ttl/4)
err = db.View(func(tx *Tx) error {
val, err := tx.Get("key1")
if err != nil {
return err
}
if val != "val1" {
t.Fatalf("expecting '%v', got '%v'", "val1", val)
}
return nil
})
if err != nil {
t.Fatal(err)
}
db = testReOpenDelay(t, db, ttl-ttl/4)
defer testClose(db)
err = db.View(func(tx *Tx) error {
val, err := tx.Get("key1")
if err == nil || err != ErrNotFound || val != "" {
t.Fatal("expecting not found")
}
return nil
})
if err != nil {
t.Fatal(err)
}
}
func TestTTL(t *testing.T) {
db := testOpen(t)
defer testClose(db)