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.

uniquequeue.go 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright 2020 Andrew Thornton. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. package levelqueue
  5. import (
  6. "fmt"
  7. "github.com/syndtr/goleveldb/leveldb"
  8. "github.com/syndtr/goleveldb/leveldb/errors"
  9. )
  10. const (
  11. uniqueQueuePrefixStr = "unique"
  12. )
  13. // UniqueQueue defines an unique queue struct
  14. type UniqueQueue struct {
  15. q *Queue
  16. set *Set
  17. db *leveldb.DB
  18. closeUnderlyingDB bool
  19. }
  20. // OpenUnique opens an unique queue from the db path or creates a set if it doesn't exist.
  21. // The keys in the queue portion will not be prefixed, and the set keys will be prefixed with "set-"
  22. func OpenUnique(dataDir string) (*UniqueQueue, error) {
  23. db, err := leveldb.OpenFile(dataDir, nil)
  24. if err != nil {
  25. if !errors.IsCorrupted(err) {
  26. return nil, err
  27. }
  28. db, err = leveldb.RecoverFile(dataDir, nil)
  29. if err != nil {
  30. return nil, err
  31. }
  32. }
  33. return NewUniqueQueue(db, []byte{}, []byte(uniqueQueuePrefixStr), true)
  34. }
  35. // NewUniqueQueue creates a new unique queue from a db.
  36. // The queue keys will be prefixed with queuePrefix and the set keys with setPrefix
  37. // and at close the db will be closed as per closeUnderlyingDB
  38. func NewUniqueQueue(db *leveldb.DB, queuePrefix []byte, setPrefix []byte, closeUnderlyingDB bool) (*UniqueQueue, error) {
  39. internal, err := NewQueue(db, queuePrefix, false)
  40. if err != nil {
  41. return nil, err
  42. }
  43. set, err := NewSet(db, setPrefix, false)
  44. if err != nil {
  45. return nil, err
  46. }
  47. queue := &UniqueQueue{
  48. q: internal,
  49. set: set,
  50. db: db,
  51. closeUnderlyingDB: closeUnderlyingDB,
  52. }
  53. return queue, err
  54. }
  55. // LPush pushes data to the left of the queue
  56. func (queue *UniqueQueue) LPush(data []byte) error {
  57. return queue.LPushFunc(data, nil)
  58. }
  59. // LPushFunc pushes data to the left of the queue and calls the callback if it is added
  60. func (queue *UniqueQueue) LPushFunc(data []byte, fn func() error) error {
  61. added, err := queue.set.Add(data)
  62. if err != nil {
  63. return err
  64. }
  65. if !added {
  66. return ErrAlreadyInQueue
  67. }
  68. if fn != nil {
  69. err = fn()
  70. if err != nil {
  71. _, remErr := queue.set.Remove(data)
  72. if remErr != nil {
  73. return fmt.Errorf("%v & %v", err, remErr)
  74. }
  75. return err
  76. }
  77. }
  78. return queue.q.LPush(data)
  79. }
  80. // RPush pushes data to the right of the queue
  81. func (queue *UniqueQueue) RPush(data []byte) error {
  82. return queue.RPushFunc(data, nil)
  83. }
  84. // RPushFunc pushes data to the right of the queue and calls the callback if is added
  85. func (queue *UniqueQueue) RPushFunc(data []byte, fn func() error) error {
  86. added, err := queue.set.Add(data)
  87. if err != nil {
  88. return err
  89. }
  90. if !added {
  91. return ErrAlreadyInQueue
  92. }
  93. if fn != nil {
  94. err = fn()
  95. if err != nil {
  96. _, remErr := queue.set.Remove(data)
  97. if remErr != nil {
  98. return fmt.Errorf("%v & %v", err, remErr)
  99. }
  100. return err
  101. }
  102. }
  103. return queue.q.RPush(data)
  104. }
  105. // RPop pop data from the right of the queue
  106. func (queue *UniqueQueue) RPop() ([]byte, error) {
  107. popped, err := queue.q.RPop()
  108. if err != nil {
  109. return popped, err
  110. }
  111. _, err = queue.set.Remove(popped)
  112. return popped, err
  113. }
  114. // RHandle receives a user callback function to handle the right element of the queue, if the function returns nil, then delete the element, otherwise keep the element.
  115. func (queue *UniqueQueue) RHandle(h func([]byte) error) error {
  116. return queue.q.RHandle(func(data []byte) error {
  117. err := h(data)
  118. if err != nil {
  119. return err
  120. }
  121. _, err = queue.set.Remove(data)
  122. return err
  123. })
  124. }
  125. // LPop pops data from left of the queue
  126. func (queue *UniqueQueue) LPop() ([]byte, error) {
  127. popped, err := queue.q.LPop()
  128. if err != nil {
  129. return popped, err
  130. }
  131. _, err = queue.set.Remove(popped)
  132. return popped, err
  133. }
  134. // LHandle receives a user callback function to handle the left element of the queue, if the function returns nil, then delete the element, otherwise keep the element.
  135. func (queue *UniqueQueue) LHandle(h func([]byte) error) error {
  136. return queue.q.LHandle(func(data []byte) error {
  137. err := h(data)
  138. if err != nil {
  139. return err
  140. }
  141. _, err = queue.set.Remove(data)
  142. return err
  143. })
  144. }
  145. // Has checks whether the data is already in the queue
  146. func (queue *UniqueQueue) Has(data []byte) (bool, error) {
  147. return queue.set.Has(data)
  148. }
  149. // Len returns the length of the queue
  150. func (queue *UniqueQueue) Len() int64 {
  151. queue.set.lock.Lock()
  152. defer queue.set.lock.Unlock()
  153. return queue.q.Len()
  154. }
  155. // Close closes the queue (and the underlying DB if set to closeUnderlyingDB)
  156. func (queue *UniqueQueue) Close() error {
  157. _ = queue.q.Close()
  158. _ = queue.set.Close()
  159. if !queue.closeUnderlyingDB {
  160. queue.db = nil
  161. return nil
  162. }
  163. err := queue.db.Close()
  164. queue.db = nil
  165. return err
  166. }