@@ -6,18 +6,21 @@ package queue
6
6
import (
7
7
"context"
8
8
"sync"
9
- "unsafe "
9
+ "sync/atomic "
10
10
11
11
"code.gitea.io/gitea/modules/nosql"
12
+ "code.gitea.io/gitea/modules/queue/lqinternal"
12
13
13
14
"gitea.com/lunny/levelqueue"
14
15
"github.com/syndtr/goleveldb/leveldb"
15
16
)
16
17
17
18
type baseLevelQueueUnique struct {
18
- internal * levelqueue.UniqueQueue
19
- conn string
20
- cfg * BaseConfig
19
+ internal atomic.Pointer [levelqueue.UniqueQueue ]
20
+
21
+ conn string
22
+ cfg * BaseConfig
23
+ db * leveldb.DB
21
24
22
25
mu sync.Mutex // the levelqueue.UniqueQueue is not thread-safe, there is no mutex protecting the underlying queue&set together
23
26
}
@@ -29,68 +32,57 @@ func newBaseLevelQueueUnique(cfg *BaseConfig) (baseQueue, error) {
29
32
if err != nil {
30
33
return nil , err
31
34
}
32
- q := & baseLevelQueueUnique {conn : conn , cfg : cfg }
33
- q . internal , err = levelqueue .NewUniqueQueue (db , []byte (cfg .QueueFullName ), []byte (cfg .SetFullName ), false )
35
+ q := & baseLevelQueueUnique {conn : conn , cfg : cfg , db : db }
36
+ lq , err : = levelqueue .NewUniqueQueue (db , []byte (cfg .QueueFullName ), []byte (cfg .SetFullName ), false )
34
37
if err != nil {
35
38
return nil , err
36
39
}
37
-
40
+ q . internal . Store ( lq )
38
41
return q , nil
39
42
}
40
43
41
44
func (q * baseLevelQueueUnique ) PushItem (ctx context.Context , data []byte ) error {
42
- return baseLevelQueueCommon (q .cfg , q .internal , & q .mu ).PushItem (ctx , data )
45
+ c := baseLevelQueueCommon (q .cfg , & q .mu , func () baseLevelQueuePushPoper { return q .internal .Load () })
46
+ return c .PushItem (ctx , data )
43
47
}
44
48
45
49
func (q * baseLevelQueueUnique ) PopItem (ctx context.Context ) ([]byte , error ) {
46
- return baseLevelQueueCommon (q .cfg , q .internal , & q .mu ).PopItem (ctx )
50
+ c := baseLevelQueueCommon (q .cfg , & q .mu , func () baseLevelQueuePushPoper { return q .internal .Load () })
51
+ return c .PopItem (ctx )
47
52
}
48
53
49
54
func (q * baseLevelQueueUnique ) HasItem (ctx context.Context , data []byte ) (bool , error ) {
50
55
q .mu .Lock ()
51
56
defer q .mu .Unlock ()
52
- return q .internal .Has (data )
57
+ return q .internal .Load (). Has (data )
53
58
}
54
59
55
60
func (q * baseLevelQueueUnique ) Len (ctx context.Context ) (int , error ) {
56
61
q .mu .Lock ()
57
62
defer q .mu .Unlock ()
58
- return int (q .internal .Len ()), nil
63
+ return int (q .internal .Load (). Len ()), nil
59
64
}
60
65
61
66
func (q * baseLevelQueueUnique ) Close () error {
62
67
q .mu .Lock ()
63
68
defer q .mu .Unlock ()
64
- err := q .internal .Close ()
69
+ err := q .internal .Load ().Close ()
70
+ q .db = nil // the db is not managed by us, it's managed by the nosql manager
65
71
_ = nosql .GetManager ().CloseLevelDB (q .conn )
66
72
return err
67
73
}
68
74
69
75
func (q * baseLevelQueueUnique ) RemoveAll (ctx context.Context ) error {
70
76
q .mu .Lock ()
71
77
defer q .mu .Unlock ()
72
-
73
- type levelUniqueQueue struct {
74
- q * levelqueue.Queue
75
- set * levelqueue.Set
76
- db * leveldb.DB
77
- }
78
- lq := (* levelUniqueQueue )(unsafe .Pointer (q .internal ))
79
-
80
- for lq .q .Len () > 0 {
81
- if _ , err := lq .q .LPop (); err != nil {
82
- return err
83
- }
84
- }
85
-
86
- // the "set" must be cleared after the "list" because there is no transaction.
87
- // it's better to have duplicate items than losing items.
88
- members , err := lq .set .Members ()
78
+ lqinternal .RemoveLevelQueueKeys (q .db , []byte (q .cfg .QueueFullName ))
79
+ lqinternal .RemoveLevelQueueKeys (q .db , []byte (q .cfg .SetFullName ))
80
+ lq , err := levelqueue .NewUniqueQueue (q .db , []byte (q .cfg .QueueFullName ), []byte (q .cfg .SetFullName ), false )
89
81
if err != nil {
90
- return err // seriously corrupted
91
- }
92
- for _ , v := range members {
93
- _ , _ = lq .set .Remove (v )
82
+ return err
94
83
}
84
+ old := q .internal .Load ()
85
+ q .internal .Store (lq )
86
+ _ = old .Close () // Not ideal for concurrency. Luckily, the levelqueue only sets its db=nil because it doesn't manage the db, so far so good
95
87
return nil
96
88
}
0 commit comments