updates.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package main
  2. import (
  3. "time"
  4. "sync"
  5. )
  6. const (
  7. addAction = 0
  8. removeAction = 1
  9. moveUpAction = 2
  10. moveDownAction = 3
  11. )
  12. type Update struct {
  13. Song *Song
  14. Action uint
  15. Timestamp int64
  16. Next *Update
  17. }
  18. type Listener struct {
  19. L chan bool
  20. Next *Listener
  21. }
  22. var headUpdates map[int]*Update
  23. var tailUpdates map[int]*Update
  24. var listeners map[int]*Listener
  25. var updateLock sync.Mutex
  26. func init() {
  27. headUpdates = make(map[int]*Update)
  28. tailUpdates = make(map[int]*Update)
  29. listeners = make(map[int]*Listener)
  30. }
  31. func addUpdate(pid int, action uint, song *Song) {
  32. update := new(Update)
  33. update.Song = song
  34. update.Action = action
  35. update.Timestamp = time.Nanoseconds()
  36. updateLock.Lock()
  37. defer updateLock.Unlock()
  38. pup := tailUpdates[pid]
  39. if pup != nil {
  40. pup.Next = update
  41. } else {
  42. headUpdates[pid] = update
  43. }
  44. tailUpdates[pid] = update
  45. listener := listeners[pid]
  46. for listener != nil {
  47. listener.L <- true
  48. listener = listener.Next
  49. }
  50. listeners[pid] = nil
  51. }
  52. // assumes caller has updateLock
  53. func checkUpdates(pid int, timestamp int64) *Update {
  54. pup, _ := headUpdates[pid]
  55. for pup != nil {
  56. if pup.Timestamp > timestamp {
  57. return pup
  58. }
  59. pup = pup.Next
  60. }
  61. return nil
  62. }
  63. func getUpdates(id string, timestamp int64) *Update {
  64. db := <-dbPool
  65. pid := getpid(db, id)
  66. dbPool <- db
  67. if pid == -1 {
  68. return nil
  69. }
  70. updateLock.Lock()
  71. pup := checkUpdates(pid, timestamp)
  72. if pup != nil {
  73. updateLock.Unlock()
  74. return pup
  75. }
  76. // didn't get updates
  77. listener := new(Listener)
  78. listener.L = make(chan bool)
  79. lhead := listeners[pid]
  80. if lhead != nil {
  81. listener.Next = lhead
  82. }
  83. listeners[pid] = listener
  84. updateLock.Unlock()
  85. <-listener.L
  86. updateLock.Lock()
  87. pup = checkUpdates(pid, timestamp)
  88. updateLock.Unlock()
  89. return pup
  90. }