Created
June 13, 2014 12:04
-
-
Save benbjohnson/a3e9e35f73dae8d15c49 to your computer and use it in GitHub Desktop.
Session Store Expiration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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