-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Graceful: Xorm, RepoIndexer, Cron and Others #9282
Changes from 7 commits
5b3fa6d
00ddf85
b2dea35
c0ea8ef
7beda2d
db022dd
1aafb56
eae3144
7589a49
89154f5
9b5d465
d7d6c86
1a79b2f
7ce742c
fa751ea
19f2ca7
ef9db2d
90bde75
13a808d
f1c85e0
aa2dabd
d55db9e
398ab3b
c93f1a7
4411cae
5c2b081
9faf8da
cb2ac9b
607f2c2
a4a722f
a9269a5
3b97005
c227a34
0e38ea8
244b54a
2098dd2
1374ad2
d42cf0d
be4388c
3e79dae
caeecd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,8 +6,6 @@ | |
package sync | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/unknwon/com" | ||
) | ||
|
||
|
@@ -18,8 +16,9 @@ import ( | |
// This queue is particularly useful for preventing duplicated task | ||
// of same purpose. | ||
type UniqueQueue struct { | ||
table *StatusTable | ||
queue chan string | ||
table *StatusTable | ||
queue chan string | ||
closed chan struct{} | ||
} | ||
|
||
// NewUniqueQueue initializes and returns a new UniqueQueue object. | ||
|
@@ -29,11 +28,43 @@ func NewUniqueQueue(queueLength int) *UniqueQueue { | |
} | ||
|
||
return &UniqueQueue{ | ||
table: NewStatusTable(), | ||
queue: make(chan string, queueLength), | ||
table: NewStatusTable(), | ||
queue: make(chan string, queueLength), | ||
closed: make(chan struct{}), | ||
} | ||
} | ||
|
||
// Close closes this queue | ||
func (q *UniqueQueue) Close() { | ||
select { | ||
case <-q.closed: | ||
default: | ||
q.table.lock.Lock() | ||
select { | ||
case <-q.closed: | ||
default: | ||
close(q.closed) | ||
} | ||
q.table.lock.Unlock() | ||
} | ||
} | ||
|
||
// IsClosed returns a channel that is closed when this Queue is closed | ||
func (q *UniqueQueue) IsClosed() <-chan struct{} { | ||
return q.closed | ||
} | ||
|
||
// IDs returns the current ids in the pool | ||
func (q *UniqueQueue) IDs() []interface{} { | ||
q.table.lock.Lock() | ||
defer q.table.lock.Unlock() | ||
ids := make([]interface{}, 0, len(q.table.pool)) | ||
for id := range q.table.pool { | ||
ids = append(ids, id) | ||
} | ||
return ids | ||
} | ||
|
||
// Queue returns channel of queue for retrieving instances. | ||
func (q *UniqueQueue) Queue() <-chan string { | ||
return q.queue | ||
|
@@ -48,15 +79,8 @@ func (q *UniqueQueue) Exist(id interface{}) bool { | |
// AddFunc adds new instance to the queue with a custom runnable function, | ||
// the queue is blocked until the function exits. | ||
func (q *UniqueQueue) AddFunc(id interface{}, fn func()) { | ||
q.AddCtxFunc(context.Background(), id, fn) | ||
} | ||
|
||
// AddCtxFunc adds new instance to the queue with a custom runnable function, | ||
// the queue is blocked until the function exits. If the context is done before | ||
// the id is added to the queue it will not be added and false will be returned. | ||
func (q *UniqueQueue) AddCtxFunc(ctx context.Context, id interface{}, fn func()) bool { | ||
if q.Exist(id) { | ||
return true | ||
return | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a potential race condition when two goroutines attempt to add functions with the same ID and neither exists before this line, but they keep going end are both ran below. I know we've tried to avoid duplicating Exist() because of the lock, but I think the check for existance should be done inside the same lock as the rest of the function. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Damn. I didn't actually check that this code was syncing correctly. I need to stop assuming that this has been done correctly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK I've decided do a double check as the pool has a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (This has made me realise this code needs to be entirely eaten by the queue stuff in the WIP) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Mutexes are pretty fast devices. The chances are high that we'll have to enter the write lock anyway. so I'd skip the read lock. There's no harm in "write locking" without doing an actual write. 😁 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean: I'd skip the read lock. 😄 |
||
|
||
idStr := com.ToStr(id) | ||
|
@@ -67,10 +91,10 @@ func (q *UniqueQueue) AddCtxFunc(ctx context.Context, id interface{}, fn func()) | |
} | ||
q.table.lock.Unlock() | ||
select { | ||
case <-ctx.Done(): | ||
return false | ||
case <-q.closed: | ||
return | ||
case q.queue <- idStr: | ||
return true | ||
return | ||
} | ||
} | ||
|
||
|
@@ -79,11 +103,6 @@ func (q *UniqueQueue) Add(id interface{}) { | |
q.AddFunc(id, nil) | ||
} | ||
|
||
// AddCtx adds new instance to the queue with a context - if the context is done before the id is added to the queue it is cancelled | ||
func (q *UniqueQueue) AddCtx(ctx context.Context, id interface{}) bool { | ||
return q.AddCtxFunc(ctx, id, nil) | ||
} | ||
|
||
// Remove removes instance from the queue. | ||
func (q *UniqueQueue) Remove(id interface{}) { | ||
q.table.Stop(com.ToStr(id)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not needed in this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it returns a snapshot of the IDs of an ever-changing queue (instead of draining it), I'd suggest renaming it to
GetIDsSnapshot()
or something. Otherwise, when it's used for another PR its functionality will probably be overlooked and not reviewed properly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, it's to be used once the queue is closed... Patience my friend..