|
|
@@ -0,0 +1,68 @@ |
|
|
package store |
|
|
|
|
|
import ( |
|
|
"fmt" |
|
|
|
|
|
"github.com/boltdb/bolt" |
|
|
) |
|
|
|
|
|
// reap removes sessions older than a given duration. |
|
|
// This function assumes that all session data is stored in a "sessions" bucket |
|
|
// and the data is organized so the key is the session id and the value is |
|
|
// laid out as: |
|
|
// |
|
|
// -8 bytes- --n bytes-- |
|
|
// timestamp + sessiondata |
|
|
// |
|
|
func reap(db *bolt.DB, duration time.Duration) error { |
|
|
// The batch size represents how many sessions we'll check at |
|
|
// a time for a given transaction. We don't want to check all the |
|
|
// sessions every time because that would lock the database for |
|
|
// too long if the sessions bucket gets too large. |
|
|
batchsz := 1000 |
|
|
|
|
|
var prev []byte |
|
|
for { |
|
|
// Get the current timestamp. |
|
|
now := time.Now() |
|
|
|
|
|
// Iterate over a subset of keys at a time and delete old ones. |
|
|
err := db.Update(func(tx *bolt.Tx) error { |
|
|
c := tx.Bucket([]byte("sessions")).Cursor() |
|
|
|
|
|
var i int |
|
|
for k, v := c.Seek(prev); ; k, v = c.Next() { |
|
|
// If we hit the end of our sessions then exit and start over next time. |
|
|
if k == nil { |
|
|
seek = nil |
|
|
return nil |
|
|
} |
|
|
|
|
|
// If we have iterated over our batch size then save our place |
|
|
// and we'll start from there next time. We need to copy over |
|
|
// the bytes in "k" because it's not guarenteed to exist there |
|
|
// after the transaction is over. |
|
|
if i == batchsz { |
|
|
seek = make([]byte, len(k)) |
|
|
copy(seek, k) |
|
|
return nil |
|
|
} |
|
|
|
|
|
// If we've made it this far then we can check if a session's |
|
|
// timestamp is older than our expiration "duration". If so |
|
|
// then we can delete the item in-place in the cursor. |
|
|
timestamp := time.Unix(int64(binary.BigEndian.Uint64(v)), 0) |
|
|
if now.Since(timestamp) > duration { |
|
|
if err := c.Delete(); err != nil { |
|
|
return fmt.Errorf("delete: %s", err) |
|
|
} |
|
|
} |
|
|
} |
|
|
}) |
|
|
if err != nil { |
|
|
return err |
|
|
} |
|
|
|
|
|
time.Sleep(1 * time.Second) |
|
|
} |
|
|
} |