improve timed queue performance

pull/69/head
v2ray 9 years ago
parent 8f9b23a6ab
commit d1fecba6e4

@ -41,55 +41,63 @@ func (queue *timedQueueImpl) Pop() interface{} {
// TimedQueue is a priority queue that entries with oldest timestamp get removed first. // TimedQueue is a priority queue that entries with oldest timestamp get removed first.
type TimedQueue struct { type TimedQueue struct {
queue timedQueueImpl queue timedQueueImpl
access sync.RWMutex access sync.Mutex
removed chan interface{} removedCallback func(interface{})
} }
func NewTimedQueue(updateInterval int) *TimedQueue { func NewTimedQueue(updateInterval int, removedCallback func(interface{})) *TimedQueue {
queue := &TimedQueue{ queue := &TimedQueue{
queue: make([]*timedQueueEntry, 0, 256), queue: make([]*timedQueueEntry, 0, 256),
removed: make(chan interface{}, 16), removedCallback: removedCallback,
access: sync.RWMutex{}, access: sync.Mutex{},
} }
go queue.cleanup(time.Tick(time.Duration(updateInterval) * time.Second)) go queue.cleanup(time.Tick(time.Duration(updateInterval) * time.Second))
return queue return queue
} }
func (queue *TimedQueue) Add(value interface{}, time2Remove int64) { func (queue *TimedQueue) Add(value interface{}, time2Remove int64) {
queue.access.Lock() newEntry := &timedQueueEntry{
heap.Push(&queue.queue, &timedQueueEntry{
timeSec: time2Remove, timeSec: time2Remove,
value: value, value: value,
}) }
var removedEntry *timedQueueEntry
queue.access.Lock()
nowSec := time.Now().Unix()
if queue.queue.Len() > 0 && queue.queue[0].timeSec < nowSec {
removedEntry = queue.queue[0]
queue.queue[0] = newEntry
heap.Fix(&queue.queue, 0)
} else {
heap.Push(&queue.queue, newEntry)
}
queue.access.Unlock() queue.access.Unlock()
} if removedEntry != nil {
queue.removedCallback(removedEntry)
func (queue *TimedQueue) RemovedEntries() <-chan interface{} { }
return queue.removed
} }
func (queue *TimedQueue) cleanup(tick <-chan time.Time) { func (queue *TimedQueue) cleanup(tick <-chan time.Time) {
for now := range tick { for now := range tick {
nowSec := now.Unix() nowSec := now.Unix()
for { removedEntries := make([]*timedQueueEntry, 0, 128)
queue.access.RLock() queue.access.Lock()
queueLen := queue.queue.Len() changed := false
queue.access.RUnlock() for i := 0; i < queue.queue.Len(); i++ {
if queueLen == 0 { entry := queue.queue[i]
break if entry.timeSec < nowSec {
} removedEntries = append(removedEntries, entry)
queue.access.RLock() queue.queue.Swap(i, queue.queue.Len()-1)
entry := queue.queue[0] queue.queue.Pop()
queue.access.RUnlock() changed = true
if entry.timeSec > nowSec {
break
} }
queue.access.Lock() }
heap.Pop(&queue.queue) if changed {
queue.access.Unlock() heap.Init(&queue.queue)
}
queue.removed <- entry.value queue.access.Unlock()
for _, entry := range removedEntries {
queue.removedCallback(entry.value)
} }
} }
} }

@ -14,14 +14,9 @@ func TestTimedQueue(t *testing.T) {
removed := make(map[string]bool) removed := make(map[string]bool)
nowSec := time.Now().Unix() nowSec := time.Now().Unix()
q := NewTimedQueue(2) q := NewTimedQueue(2, func(v interface{}) {
removed[v.(string)] = true
go func() { })
for {
entry := <-q.RemovedEntries()
removed[entry.(string)] = true
}
}()
q.Add("Value1", nowSec) q.Add("Value1", nowSec)
q.Add("Value2", nowSec+5) q.Add("Value2", nowSec+5)

@ -32,22 +32,19 @@ type indexTimePair struct {
func NewTimedUserSet() UserSet { func NewTimedUserSet() UserSet {
tus := &TimedUserSet{ tus := &TimedUserSet{
validUsers: make([]vmess.User, 0, 16), validUsers: make([]vmess.User, 0, 16),
userHash: make(map[string]indexTimePair, 512), userHash: make(map[string]indexTimePair, 512),
userHashDeleteQueue: collect.NewTimedQueue(updateIntervalSec), access: sync.RWMutex{},
access: sync.RWMutex{},
} }
tus.userHashDeleteQueue = collect.NewTimedQueue(updateIntervalSec, tus.removeEntry)
go tus.updateUserHash(time.Tick(updateIntervalSec * time.Second)) go tus.updateUserHash(time.Tick(updateIntervalSec * time.Second))
go tus.removeEntries(tus.userHashDeleteQueue.RemovedEntries())
return tus return tus
} }
func (us *TimedUserSet) removeEntries(entries <-chan interface{}) { func (us *TimedUserSet) removeEntry(entry interface{}) {
for entry := range entries { us.access.Lock()
us.access.Lock() delete(us.userHash, entry.(string))
delete(us.userHash, entry.(string)) us.access.Unlock()
us.access.Unlock()
}
} }
func (us *TimedUserSet) generateNewHashes(lastSec, nowSec int64, idx int, id *vmess.ID) { func (us *TimedUserSet) generateNewHashes(lastSec, nowSec int64, idx int, id *vmess.ID) {

Loading…
Cancel
Save