| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- package main
- import (
- "time"
- "sync"
- )
- const (
- addAction = 0
- removeAction = 1
- moveUpAction = 2
- moveDownAction = 3
- )
- type Update struct {
- Song *Song
- Action uint
- Timestamp int64
- Next *Update
- }
- type Listener struct {
- L chan bool
- Next *Listener
- }
- var headUpdates map[int]*Update
- var tailUpdates map[int]*Update
- var listeners map[int]*Listener
- var updateLock sync.Mutex
- func init() {
- headUpdates = make(map[int]*Update)
- tailUpdates = make(map[int]*Update)
- listeners = make(map[int]*Listener)
- }
- func addUpdate(pid int, action uint, song *Song) {
- update := new(Update)
- update.Song = song
- update.Action = action
- update.Timestamp = time.Nanoseconds()
- updateLock.Lock()
- defer updateLock.Unlock()
- // write new update
- pup := tailUpdates[pid]
- if pup != nil {
- pup.Next = update
- } else {
- headUpdates[pid] = update
- }
- tailUpdates[pid] = update
- // expire old updates
- const expiryTime = 1e9 * 3 * 60 // 3 minutes
- pup = headUpdates[pid]
- for pup != nil && pup.Timestamp < update.Timestamp - expiryTime {
- pup = pup.Next
- headUpdates[pid] = pup
- }
- // notify listeners
- listener := listeners[pid]
- for listener != nil {
- listener.L <- true
- listener = listener.Next
- }
- listeners[pid] = nil
- }
- // assumes caller has updateLock
- func checkUpdates(pid int, timestamp int64) *Update {
- pup, _ := headUpdates[pid]
- for pup != nil {
- if pup.Timestamp > timestamp {
- return pup
- }
- pup = pup.Next
- }
- return nil
- }
- func getUpdates(id string, timestamp int64) *Update {
- db := <-dbPool
- pid := getpid(db, id)
- dbPool <- db
- if pid == -1 {
- return nil
- }
- updateLock.Lock()
- pup := checkUpdates(pid, timestamp)
- if pup != nil {
- updateLock.Unlock()
- return pup
- }
- // didn't get updates
- listener := new(Listener)
- listener.L = make(chan bool)
- lhead := listeners[pid]
- if lhead != nil {
- listener.Next = lhead
- }
- listeners[pid] = listener
- updateLock.Unlock()
- <-listener.L
- updateLock.Lock()
- pup = checkUpdates(pid, timestamp)
- updateLock.Unlock()
- return pup
- }
|