@@ -8,6 +8,10 @@ import (
8
8
"github.com/yosssi/boltstore/shared"
9
9
)
10
10
11
+ //##############//
12
+ //### Public ###//
13
+ //##############//
14
+
11
15
// Run invokes a reap function as a goroutine.
12
16
func Run (db * bolt.DB , options Options ) (chan <- struct {}, <- chan struct {}) {
13
17
options .setDefault ()
@@ -22,66 +26,114 @@ func Quit(quitC chan<- struct{}, doneC <-chan struct{}) {
22
26
<- doneC
23
27
}
24
28
29
+ //###############//
30
+ //### Private ###//
31
+ //###############//
32
+
25
33
func reap (db * bolt.DB , options Options , quitC <- chan struct {}, doneC chan <- struct {}) {
26
- var prevKey []byte
27
- for {
28
- err := db .View (func (tx * bolt.Tx ) error {
29
- bucket := tx .Bucket (options .BucketName )
30
- if bucket == nil {
31
- return nil
32
- }
34
+ // Create a new ticker
35
+ ticker := time .NewTicker (options .CheckInterval )
33
36
34
- c := bucket .Cursor ()
37
+ defer func () {
38
+ // Stop the ticker
39
+ ticker .Stop ()
40
+ }()
35
41
36
- var i int
42
+ var prevKey [] byte
37
43
38
- for k , v := c .Seek (prevKey ); ; k , v = c .Next () {
39
- // If we hit the end of our sessions then
40
- // exit and start over next time.
41
- if k == nil {
42
- prevKey = nil
44
+ for {
45
+ select {
46
+ case <- quitC : // Check if a quit signal is sent.
47
+ doneC <- struct {}{}
48
+ return
49
+ case <- ticker .C : // Check if the ticker fires a signal.
50
+ // This slice is a buffer to save all expired session keys.
51
+ expiredSessionKeys := make ([][]byte , 0 )
52
+
53
+ // Start a bolt read transaction.
54
+ err := db .View (func (tx * bolt.Tx ) error {
55
+ bucket := tx .Bucket (options .BucketName )
56
+ if bucket == nil {
43
57
return nil
44
58
}
45
59
46
- i ++
60
+ c := bucket . Cursor ()
47
61
48
- session , err := shared .Session (v )
49
- if err != nil {
50
- return err
51
- }
62
+ var i int
63
+ var isExpired bool
64
+
65
+ for k , v := c .Seek (prevKey ); ; k , v = c .Next () {
66
+ // If we hit the end of our sessions then
67
+ // exit and start over next time.
68
+ if k == nil {
69
+ prevKey = nil
70
+ return nil
71
+ }
52
72
53
- if shared .Expired (session ) {
54
- err := db .Update (func (txu * bolt.Tx ) error {
55
- return txu .Bucket (options .BucketName ).Delete (k )
56
- })
73
+ i ++
74
+
75
+ // The flag if the session is expired
76
+ isExpired = false
77
+
78
+ session , err := shared .Session (v )
57
79
if err != nil {
58
- return err
80
+ // Just remove the session with the invalid session data.
81
+ // Log the error first.
82
+ log .Printf ("boltstore: removing session from database with invalid value: %v" , err )
83
+ isExpired = true
84
+ } else if shared .Expired (session ) {
85
+ isExpired = true
59
86
}
60
- }
61
87
62
- if options .BatchSize == i {
63
- // Store the current key to the previous key.
64
- // Copy the byte slice key, because this data is
65
- // not safe outside of this transaction.
66
- prevKey = make ([]byte , len (k ))
67
- copy (prevKey , k )
68
- return nil
88
+ if isExpired {
89
+ // Copy the byte slice key, because this data is
90
+ // not safe outside of this transaction.
91
+ temp := make ([]byte , len (k ))
92
+ copy (temp , k )
93
+
94
+ // Add it to the expired sessios keys slice
95
+ expiredSessionKeys = append (expiredSessionKeys , temp )
96
+ }
97
+
98
+ if options .BatchSize == i {
99
+ // Store the current key to the previous key.
100
+ // Copy the byte slice key, because this data is
101
+ // not safe outside of this transaction.
102
+ prevKey = make ([]byte , len (k ))
103
+ copy (prevKey , k )
104
+ return nil
105
+ }
69
106
}
107
+ })
108
+
109
+ if err != nil {
110
+ log .Printf ("boltstore: obtain expired sessions error: %v" , err )
70
111
}
71
- })
72
112
73
- if err != nil {
74
- log .Println (err .Error ())
75
- }
113
+ if len (expiredSessionKeys ) > 0 {
114
+ // Remove the expired sessions from the database
115
+ err = db .Update (func (txu * bolt.Tx ) error {
116
+ // Get the bucket
117
+ b := txu .Bucket (options .BucketName )
118
+ if b == nil {
119
+ return nil
120
+ }
76
121
77
- // Check if a quit signal is sent.
78
- select {
79
- case <- quitC :
80
- doneC <- struct {}{}
81
- return
82
- default :
83
- }
122
+ // Remove all expired sessions in the slice
123
+ for _ , key := range expiredSessionKeys {
124
+ err = b .Delete (key )
125
+ if err != nil {
126
+ return err
127
+ }
128
+ }
129
+
130
+ return nil
131
+ })
84
132
85
- time .Sleep (options .CheckInterval )
133
+ if err != nil {
134
+ log .Printf ("boltstore: remove expired sessions error: %v" , err )
135
+ }
136
+ }
137
+ }
86
138
}
87
139
}
0 commit comments