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

ring.go 3.9 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package io2
  2. import (
  3. "io"
  4. "sync"
  5. "time"
  6. "gitlink.org.cn/cloudream/common/utils/math2"
  7. )
  8. type RingBufferStats struct {
  9. MaxWaitDataTime time.Duration // 外部读取数据时的最长等待时间
  10. MaxWaitFreeSpaceTime time.Duration // 从数据源读取数据之前,等待空闲空间的最长时间
  11. TotalWaitDataTime time.Duration // 总等待读取数据的时间
  12. TotalWaitFreeSpaceTime time.Duration // 总等待空闲空间的时间
  13. }
  14. type RingBuffer struct {
  15. buf []byte
  16. src io.ReadCloser
  17. maxPerRead int // 后台读取线程每次读取的最大字节数,太小会导致IO次数增多,太大会导致读、写并行性下降
  18. err error
  19. isReading bool
  20. writePos int // 指向下一次写入的位置,应该是一个空位
  21. readPos int // 执行下一次读取的位置,应该是有效数据
  22. waitReading *sync.Cond
  23. waitComsuming *sync.Cond
  24. stats RingBufferStats
  25. }
  26. func Ring(src io.ReadCloser, size int) *RingBuffer {
  27. lk := &sync.Mutex{}
  28. return &RingBuffer{
  29. buf: make([]byte, size),
  30. src: src,
  31. maxPerRead: size / 4,
  32. waitReading: sync.NewCond(lk),
  33. waitComsuming: sync.NewCond(lk),
  34. }
  35. }
  36. func (r *RingBuffer) Stats() RingBufferStats {
  37. return r.stats
  38. }
  39. func (r *RingBuffer) Read(p []byte) (n int, err error) {
  40. r.waitReading.L.Lock()
  41. if !r.isReading {
  42. go r.reading()
  43. r.isReading = true
  44. }
  45. for r.writePos == r.readPos {
  46. if r.err != nil {
  47. r.waitReading.L.Unlock()
  48. return 0, r.err
  49. }
  50. startTime := time.Now()
  51. r.waitReading.Wait()
  52. dt := time.Since(startTime)
  53. r.stats.MaxWaitDataTime = math2.Max(r.stats.MaxWaitDataTime, dt)
  54. r.stats.TotalWaitDataTime += dt
  55. }
  56. writePos := r.writePos
  57. readPos := r.readPos
  58. r.waitReading.L.Unlock()
  59. if readPos < writePos {
  60. maxRead := math2.Min(r.maxPerRead, writePos-readPos)
  61. n = copy(p, r.buf[readPos:readPos+maxRead])
  62. } else {
  63. maxRead := math2.Min(r.maxPerRead, len(r.buf)-readPos)
  64. n = copy(p, r.buf[readPos:readPos+maxRead])
  65. }
  66. r.waitComsuming.L.Lock()
  67. r.readPos = (r.readPos + n) % len(r.buf)
  68. r.waitComsuming.L.Unlock()
  69. r.waitComsuming.Broadcast()
  70. err = nil
  71. return
  72. }
  73. func (r *RingBuffer) Close() error {
  74. r.src.Close()
  75. r.waitComsuming.L.Lock()
  76. r.err = io.ErrClosedPipe
  77. r.waitComsuming.L.Unlock()
  78. r.waitComsuming.Broadcast()
  79. r.waitReading.Broadcast()
  80. return nil
  81. }
  82. func (r *RingBuffer) reading() {
  83. defer r.src.Close()
  84. for {
  85. r.waitComsuming.L.Lock()
  86. // writePos不能和readPos重合,因为无法区分缓冲区是已经满了,还是完全是空的
  87. // 所以writePos最多能到readPos的前一格
  88. for (r.writePos+1)%len(r.buf) == r.readPos {
  89. startTime := time.Now()
  90. r.waitComsuming.Wait()
  91. dt := time.Since(startTime)
  92. r.stats.MaxWaitFreeSpaceTime = math2.Max(r.stats.MaxWaitFreeSpaceTime, dt)
  93. r.stats.TotalWaitFreeSpaceTime += dt
  94. if r.err != nil {
  95. return
  96. }
  97. }
  98. writePos := r.writePos
  99. readPos := r.readPos
  100. r.waitComsuming.L.Unlock()
  101. var n int
  102. var err error
  103. if readPos <= writePos {
  104. // 同上理,写入数据的时候如果readPos为0,则它的前一格是底层缓冲区的最后一格
  105. // 那就不能写入到这一格
  106. if readPos == 0 {
  107. maxWrite := math2.Min(r.maxPerRead, len(r.buf)-1-writePos)
  108. n, err = r.src.Read(r.buf[writePos : writePos+maxWrite])
  109. } else {
  110. maxWrite := math2.Min(r.maxPerRead, len(r.buf)-writePos)
  111. n, err = r.src.Read(r.buf[writePos : writePos+maxWrite])
  112. }
  113. } else {
  114. maxWrite := math2.Min(r.maxPerRead, readPos-1-writePos)
  115. n, err = r.src.Read(r.buf[writePos : writePos+maxWrite])
  116. }
  117. // 无论成功还是失败,都发送一下信号通知读取端
  118. r.waitReading.L.Lock()
  119. r.err = err
  120. r.writePos = (r.writePos + n) % len(r.buf)
  121. r.waitReading.L.Unlock()
  122. r.waitReading.Broadcast()
  123. if err != nil {
  124. break
  125. }
  126. }
  127. }