You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

409 lines
8.8 KiB

  1. package clist
  2. /*
  3. The purpose of CList is to provide a goroutine-safe linked-list.
  4. This list can be traversed concurrently by any number of goroutines.
  5. However, removed CElements cannot be added back.
  6. NOTE: Not all methods of container/list are (yet) implemented.
  7. NOTE: Removed elements need to DetachPrev or DetachNext consistently
  8. to ensure garbage collection of removed elements.
  9. */
  10. import (
  11. "fmt"
  12. "sync"
  13. tmsync "github.com/tendermint/tendermint/libs/sync"
  14. )
  15. // MaxLength is the max allowed number of elements a linked list is
  16. // allowed to contain.
  17. // If more elements are pushed to the list it will panic.
  18. const MaxLength = int(^uint(0) >> 1)
  19. /*
  20. CElement is an element of a linked-list
  21. Traversal from a CElement is goroutine-safe.
  22. We can't avoid using WaitGroups or for-loops given the documentation
  23. spec without re-implementing the primitives that already exist in
  24. golang/sync. Notice that WaitGroup allows many go-routines to be
  25. simultaneously released, which is what we want. Mutex doesn't do
  26. this. RWMutex does this, but it's clumsy to use in the way that a
  27. WaitGroup would be used -- and we'd end up having two RWMutex's for
  28. prev/next each, which is doubly confusing.
  29. sync.Cond would be sort-of useful, but we don't need a write-lock in
  30. the for-loop. Use sync.Cond when you need serial access to the
  31. "condition". In our case our condition is if `next != nil || removed`,
  32. and there's no reason to serialize that condition for goroutines
  33. waiting on NextWait() (since it's just a read operation).
  34. */
  35. type CElement struct {
  36. mtx tmsync.RWMutex
  37. prev *CElement
  38. prevWg *sync.WaitGroup
  39. prevWaitCh chan struct{}
  40. next *CElement
  41. nextWg *sync.WaitGroup
  42. nextWaitCh chan struct{}
  43. removed bool
  44. Value interface{} // immutable
  45. }
  46. // Blocking implementation of Next().
  47. // May return nil iff CElement was tail and got removed.
  48. func (e *CElement) NextWait() *CElement {
  49. for {
  50. e.mtx.RLock()
  51. next := e.next
  52. nextWg := e.nextWg
  53. removed := e.removed
  54. e.mtx.RUnlock()
  55. if next != nil || removed {
  56. return next
  57. }
  58. nextWg.Wait()
  59. // e.next doesn't necessarily exist here.
  60. // That's why we need to continue a for-loop.
  61. }
  62. }
  63. // Blocking implementation of Prev().
  64. // May return nil iff CElement was head and got removed.
  65. func (e *CElement) PrevWait() *CElement {
  66. for {
  67. e.mtx.RLock()
  68. prev := e.prev
  69. prevWg := e.prevWg
  70. removed := e.removed
  71. e.mtx.RUnlock()
  72. if prev != nil || removed {
  73. return prev
  74. }
  75. prevWg.Wait()
  76. }
  77. }
  78. // PrevWaitChan can be used to wait until Prev becomes not nil. Once it does,
  79. // channel will be closed.
  80. func (e *CElement) PrevWaitChan() <-chan struct{} {
  81. e.mtx.RLock()
  82. defer e.mtx.RUnlock()
  83. return e.prevWaitCh
  84. }
  85. // NextWaitChan can be used to wait until Next becomes not nil. Once it does,
  86. // channel will be closed.
  87. func (e *CElement) NextWaitChan() <-chan struct{} {
  88. e.mtx.RLock()
  89. defer e.mtx.RUnlock()
  90. return e.nextWaitCh
  91. }
  92. // Nonblocking, may return nil if at the end.
  93. func (e *CElement) Next() *CElement {
  94. e.mtx.RLock()
  95. val := e.next
  96. e.mtx.RUnlock()
  97. return val
  98. }
  99. // Nonblocking, may return nil if at the end.
  100. func (e *CElement) Prev() *CElement {
  101. e.mtx.RLock()
  102. prev := e.prev
  103. e.mtx.RUnlock()
  104. return prev
  105. }
  106. func (e *CElement) Removed() bool {
  107. e.mtx.RLock()
  108. isRemoved := e.removed
  109. e.mtx.RUnlock()
  110. return isRemoved
  111. }
  112. func (e *CElement) DetachNext() {
  113. e.mtx.Lock()
  114. if !e.removed {
  115. e.mtx.Unlock()
  116. panic("DetachNext() must be called after Remove(e)")
  117. }
  118. e.next = nil
  119. e.mtx.Unlock()
  120. }
  121. func (e *CElement) DetachPrev() {
  122. e.mtx.Lock()
  123. if !e.removed {
  124. e.mtx.Unlock()
  125. panic("DetachPrev() must be called after Remove(e)")
  126. }
  127. e.prev = nil
  128. e.mtx.Unlock()
  129. }
  130. // NOTE: This function needs to be safe for
  131. // concurrent goroutines waiting on nextWg.
  132. func (e *CElement) SetNext(newNext *CElement) {
  133. e.mtx.Lock()
  134. oldNext := e.next
  135. e.next = newNext
  136. if oldNext != nil && newNext == nil {
  137. // See https://golang.org/pkg/sync/:
  138. //
  139. // If a WaitGroup is reused to wait for several independent sets of
  140. // events, new Add calls must happen after all previous Wait calls have
  141. // returned.
  142. e.nextWg = waitGroup1() // WaitGroups are difficult to re-use.
  143. e.nextWaitCh = make(chan struct{})
  144. }
  145. if oldNext == nil && newNext != nil {
  146. e.nextWg.Done()
  147. close(e.nextWaitCh)
  148. }
  149. e.mtx.Unlock()
  150. }
  151. // NOTE: This function needs to be safe for
  152. // concurrent goroutines waiting on prevWg
  153. func (e *CElement) SetPrev(newPrev *CElement) {
  154. e.mtx.Lock()
  155. oldPrev := e.prev
  156. e.prev = newPrev
  157. if oldPrev != nil && newPrev == nil {
  158. e.prevWg = waitGroup1() // WaitGroups are difficult to re-use.
  159. e.prevWaitCh = make(chan struct{})
  160. }
  161. if oldPrev == nil && newPrev != nil {
  162. e.prevWg.Done()
  163. close(e.prevWaitCh)
  164. }
  165. e.mtx.Unlock()
  166. }
  167. func (e *CElement) SetRemoved() {
  168. e.mtx.Lock()
  169. e.removed = true
  170. // This wakes up anyone waiting in either direction.
  171. if e.prev == nil {
  172. e.prevWg.Done()
  173. close(e.prevWaitCh)
  174. }
  175. if e.next == nil {
  176. e.nextWg.Done()
  177. close(e.nextWaitCh)
  178. }
  179. e.mtx.Unlock()
  180. }
  181. //--------------------------------------------------------------------------------
  182. // CList represents a linked list.
  183. // The zero value for CList is an empty list ready to use.
  184. // Operations are goroutine-safe.
  185. // Panics if length grows beyond the max.
  186. type CList struct {
  187. mtx tmsync.RWMutex
  188. wg *sync.WaitGroup
  189. waitCh chan struct{}
  190. head *CElement // first element
  191. tail *CElement // last element
  192. len int // list length
  193. maxLen int // max list length
  194. }
  195. func (l *CList) Init() *CList {
  196. l.mtx.Lock()
  197. l.wg = waitGroup1()
  198. l.waitCh = make(chan struct{})
  199. l.head = nil
  200. l.tail = nil
  201. l.len = 0
  202. l.mtx.Unlock()
  203. return l
  204. }
  205. // Return CList with MaxLength. CList will panic if it goes beyond MaxLength.
  206. func New() *CList { return newWithMax(MaxLength) }
  207. // Return CList with given maxLength.
  208. // Will panic if list exceeds given maxLength.
  209. func newWithMax(maxLength int) *CList {
  210. l := new(CList)
  211. l.maxLen = maxLength
  212. return l.Init()
  213. }
  214. func (l *CList) Len() int {
  215. l.mtx.RLock()
  216. len := l.len
  217. l.mtx.RUnlock()
  218. return len
  219. }
  220. func (l *CList) Front() *CElement {
  221. l.mtx.RLock()
  222. head := l.head
  223. l.mtx.RUnlock()
  224. return head
  225. }
  226. func (l *CList) FrontWait() *CElement {
  227. // Loop until the head is non-nil else wait and try again
  228. for {
  229. l.mtx.RLock()
  230. head := l.head
  231. wg := l.wg
  232. l.mtx.RUnlock()
  233. if head != nil {
  234. return head
  235. }
  236. wg.Wait()
  237. // NOTE: If you think l.head exists here, think harder.
  238. }
  239. }
  240. func (l *CList) Back() *CElement {
  241. l.mtx.RLock()
  242. back := l.tail
  243. l.mtx.RUnlock()
  244. return back
  245. }
  246. func (l *CList) BackWait() *CElement {
  247. for {
  248. l.mtx.RLock()
  249. tail := l.tail
  250. wg := l.wg
  251. l.mtx.RUnlock()
  252. if tail != nil {
  253. return tail
  254. }
  255. wg.Wait()
  256. // l.tail doesn't necessarily exist here.
  257. // That's why we need to continue a for-loop.
  258. }
  259. }
  260. // WaitChan can be used to wait until Front or Back becomes not nil. Once it
  261. // does, channel will be closed.
  262. func (l *CList) WaitChan() <-chan struct{} {
  263. l.mtx.Lock()
  264. defer l.mtx.Unlock()
  265. return l.waitCh
  266. }
  267. // Panics if list grows beyond its max length.
  268. func (l *CList) PushBack(v interface{}) *CElement {
  269. l.mtx.Lock()
  270. // Construct a new element
  271. e := &CElement{
  272. prev: nil,
  273. prevWg: waitGroup1(),
  274. prevWaitCh: make(chan struct{}),
  275. next: nil,
  276. nextWg: waitGroup1(),
  277. nextWaitCh: make(chan struct{}),
  278. removed: false,
  279. Value: v,
  280. }
  281. // Release waiters on FrontWait/BackWait maybe
  282. if l.len == 0 {
  283. l.wg.Done()
  284. close(l.waitCh)
  285. }
  286. if l.len >= l.maxLen {
  287. panic(fmt.Sprintf("clist: maximum length list reached %d", l.maxLen))
  288. }
  289. l.len++
  290. // Modify the tail
  291. if l.tail == nil {
  292. l.head = e
  293. l.tail = e
  294. } else {
  295. e.SetPrev(l.tail) // We must init e first.
  296. l.tail.SetNext(e) // This will make e accessible.
  297. l.tail = e // Update the list.
  298. }
  299. l.mtx.Unlock()
  300. return e
  301. }
  302. // CONTRACT: Caller must call e.DetachPrev() and/or e.DetachNext() to avoid memory leaks.
  303. // NOTE: As per the contract of CList, removed elements cannot be added back.
  304. func (l *CList) Remove(e *CElement) interface{} {
  305. l.mtx.Lock()
  306. prev := e.Prev()
  307. next := e.Next()
  308. if l.head == nil || l.tail == nil {
  309. l.mtx.Unlock()
  310. panic("Remove(e) on empty CList")
  311. }
  312. if prev == nil && l.head != e {
  313. l.mtx.Unlock()
  314. panic("Remove(e) with false head")
  315. }
  316. if next == nil && l.tail != e {
  317. l.mtx.Unlock()
  318. panic("Remove(e) with false tail")
  319. }
  320. // If we're removing the only item, make CList FrontWait/BackWait wait.
  321. if l.len == 1 {
  322. l.wg = waitGroup1() // WaitGroups are difficult to re-use.
  323. l.waitCh = make(chan struct{})
  324. }
  325. // Update l.len
  326. l.len--
  327. // Connect next/prev and set head/tail
  328. if prev == nil {
  329. l.head = next
  330. } else {
  331. prev.SetNext(next)
  332. }
  333. if next == nil {
  334. l.tail = prev
  335. } else {
  336. next.SetPrev(prev)
  337. }
  338. // Set .Done() on e, otherwise waiters will wait forever.
  339. e.SetRemoved()
  340. l.mtx.Unlock()
  341. return e.Value
  342. }
  343. func waitGroup1() (wg *sync.WaitGroup) {
  344. wg = &sync.WaitGroup{}
  345. wg.Add(1)
  346. return
  347. }