本站源代码
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

215 lines
4.2KB

  1. // Copyright 2019 Lunny Xiao. 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. "bytes"
  7. "encoding/binary"
  8. "sync"
  9. "github.com/syndtr/goleveldb/leveldb"
  10. )
  11. // Queue defines a queue struct
  12. type Queue struct {
  13. db *leveldb.DB
  14. highLock sync.Mutex
  15. lowLock sync.Mutex
  16. low int64
  17. high int64
  18. }
  19. // Open opens a queue object or create it if not exist
  20. func Open(dataDir string) (*Queue, error) {
  21. db, err := leveldb.OpenFile(dataDir, nil)
  22. if err != nil {
  23. return nil, err
  24. }
  25. var queue = &Queue{
  26. db: db,
  27. }
  28. queue.low, err = queue.readID(lowKey)
  29. if err == leveldb.ErrNotFound {
  30. queue.low = 1
  31. err = db.Put(lowKey, id2bytes(1), nil)
  32. }
  33. if err != nil {
  34. return nil, err
  35. }
  36. queue.high, err = queue.readID(highKey)
  37. if err == leveldb.ErrNotFound {
  38. err = db.Put(highKey, id2bytes(0), nil)
  39. }
  40. if err != nil {
  41. return nil, err
  42. }
  43. return queue, nil
  44. }
  45. func (queue *Queue) readID(key []byte) (int64, error) {
  46. bs, err := queue.db.Get(key, nil)
  47. if err != nil {
  48. return 0, err
  49. }
  50. return bytes2id(bs)
  51. }
  52. var (
  53. lowKey = []byte("low")
  54. highKey = []byte("high")
  55. )
  56. func (queue *Queue) highincrement() (int64, error) {
  57. id := queue.high + 1
  58. queue.high = id
  59. err := queue.db.Put(highKey, id2bytes(queue.high), nil)
  60. if err != nil {
  61. queue.high = queue.high - 1
  62. return 0, err
  63. }
  64. return id, nil
  65. }
  66. func (queue *Queue) highdecrement() (int64, error) {
  67. queue.high = queue.high - 1
  68. err := queue.db.Put(highKey, id2bytes(queue.high), nil)
  69. if err != nil {
  70. queue.high = queue.high + 1
  71. return 0, err
  72. }
  73. return queue.high, nil
  74. }
  75. func (queue *Queue) lowincrement() (int64, error) {
  76. queue.low = queue.low + 1
  77. err := queue.db.Put(lowKey, id2bytes(queue.low), nil)
  78. if err != nil {
  79. queue.low = queue.low - 1
  80. return 0, err
  81. }
  82. return queue.low, nil
  83. }
  84. func (queue *Queue) lowdecrement() (int64, error) {
  85. queue.low = queue.low - 1
  86. err := queue.db.Put(lowKey, id2bytes(queue.low), nil)
  87. if err != nil {
  88. queue.low = queue.low + 1
  89. return 0, err
  90. }
  91. return queue.low, nil
  92. }
  93. // Len returns the length of the queue
  94. func (queue *Queue) Len() int64 {
  95. queue.lowLock.Lock()
  96. queue.highLock.Lock()
  97. l := queue.high - queue.low + 1
  98. queue.highLock.Unlock()
  99. queue.lowLock.Unlock()
  100. return l
  101. }
  102. func id2bytes(id int64) []byte {
  103. var buf = make([]byte, 8)
  104. binary.PutVarint(buf, id)
  105. return buf
  106. }
  107. func bytes2id(b []byte) (int64, error) {
  108. return binary.ReadVarint(bytes.NewReader(b))
  109. }
  110. // RPush pushes a data from right of queue
  111. func (queue *Queue) RPush(data []byte) error {
  112. queue.highLock.Lock()
  113. id, err := queue.highincrement()
  114. if err != nil {
  115. queue.highLock.Unlock()
  116. return err
  117. }
  118. err = queue.db.Put(id2bytes(id), data, nil)
  119. queue.highLock.Unlock()
  120. return err
  121. }
  122. // LPush pushes a data from left of queue
  123. func (queue *Queue) LPush(data []byte) error {
  124. queue.highLock.Lock()
  125. id, err := queue.lowdecrement()
  126. if err != nil {
  127. queue.highLock.Unlock()
  128. return err
  129. }
  130. err = queue.db.Put(id2bytes(id), data, nil)
  131. queue.highLock.Unlock()
  132. return err
  133. }
  134. // RPop pop a data from right of queue
  135. func (queue *Queue) RPop() ([]byte, error) {
  136. queue.highLock.Lock()
  137. currentID := queue.high
  138. res, err := queue.db.Get(id2bytes(currentID), nil)
  139. if err != nil {
  140. queue.highLock.Unlock()
  141. if err == leveldb.ErrNotFound {
  142. return nil, ErrNotFound
  143. }
  144. return nil, err
  145. }
  146. _, err = queue.highdecrement()
  147. if err != nil {
  148. queue.highLock.Unlock()
  149. return nil, err
  150. }
  151. err = queue.db.Delete(id2bytes(currentID), nil)
  152. queue.highLock.Unlock()
  153. if err != nil {
  154. return nil, err
  155. }
  156. return res, nil
  157. }
  158. // LPop pop a data from left of queue
  159. func (queue *Queue) LPop() ([]byte, error) {
  160. queue.lowLock.Lock()
  161. currentID := queue.low
  162. res, err := queue.db.Get(id2bytes(currentID), nil)
  163. if err != nil {
  164. queue.lowLock.Unlock()
  165. if err == leveldb.ErrNotFound {
  166. return nil, ErrNotFound
  167. }
  168. return nil, err
  169. }
  170. _, err = queue.lowincrement()
  171. if err != nil {
  172. return nil, err
  173. }
  174. err = queue.db.Delete(id2bytes(currentID), nil)
  175. queue.lowLock.Unlock()
  176. if err != nil {
  177. return nil, err
  178. }
  179. return res, nil
  180. }
  181. // Close closes the queue
  182. func (queue *Queue) Close() error {
  183. err := queue.db.Close()
  184. queue.db = nil
  185. return err
  186. }
上海开阖软件有限公司 沪ICP备12045867号-1