Skip to content

Instantly share code, notes, and snippets.

@benbjohnson
Created June 13, 2014 12:04
Show Gist options
  • Save benbjohnson/a3e9e35f73dae8d15c49 to your computer and use it in GitHub Desktop.
Save benbjohnson/a3e9e35f73dae8d15c49 to your computer and use it in GitHub Desktop.
Session Store Expiration
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)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment