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() pup := tailUpdates[pid] if pup != nil { pup.Next = update } else { headUpdates[pid] = update } tailUpdates[pid] = update 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 }