vecio.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package util
  2. import (
  3. //"fmt"
  4. "io"
  5. "net"
  6. "os"
  7. "unsafe"
  8. )
  9. /*
  10. #include <sys/uio.h>
  11. // Structure for scatter/gather I/O.
  12. struct iovec{
  13. void *iov_base; // Pointer to data.
  14. size_t iov_len; // Length of data.
  15. };
  16. */
  17. type SysIOVec struct {
  18. Base uintptr
  19. Length uint64
  20. }
  21. type IOVec struct {
  22. Data [][]byte
  23. Length int
  24. index int
  25. }
  26. func (iov *IOVec) Append(b []byte) {
  27. iov.Data = append(iov.Data, b)
  28. iov.Length += len(b)
  29. }
  30. // Data模型:
  31. // index -> | Data[0][0] | Data[0][1] | Data[0][2] | ... | Data[0][n] |
  32. // | Data[1][0] | Data[1][1] | Data[1][2] | ... | Data[1][n] |
  33. // ......
  34. // | Data[n][0] | Data[n][1] | Data[n][2] | ... | Data[n][n] |
  35. //
  36. // index是下标
  37. func (iov *IOVec) WriteTo(w io.Writer, n int) (written int, err error) {
  38. for n > 0 && iov.Length > 0 {
  39. data := iov.Data[iov.index]
  40. // 用来存放每次需要写入的数据
  41. var b []byte
  42. // 只会读n个字节,超出n个字节,不管
  43. // 如果iov.Data里面有1000个数据,可是每次只读184个字节,那么剩下的数据(856)重新放回Data
  44. if n > len(data) {
  45. b = data
  46. } else {
  47. b = data[:n]
  48. }
  49. // n个字节后面的数据
  50. // 如果这时候n个字节后面已经没有数据了,我们就将下标index往后移一位
  51. // 否则我们将n个字节后面的数据重新放回Data里.
  52. data = data[len(b):]
  53. if len(data) == 0 {
  54. iov.index++
  55. } else {
  56. iov.Data[iov.index] = data
  57. }
  58. n -= len(b)
  59. iov.Length -= len(b)
  60. written += len(b)
  61. if _, err = w.Write(b); err != nil {
  62. return
  63. }
  64. }
  65. return
  66. }
  67. type IOVecWriter struct {
  68. fd uintptr
  69. smallBuffer []byte
  70. sysIOV []SysIOVec
  71. }
  72. func NewIOVecWriter(w io.Writer) (iow *IOVecWriter) {
  73. var err error
  74. var file *os.File
  75. // TODO:是否要增加其他的类型断言
  76. switch value := w.(type) {
  77. case *net.TCPConn:
  78. {
  79. file, err = value.File()
  80. if err != nil {
  81. return
  82. }
  83. }
  84. case *os.File:
  85. {
  86. file = value
  87. }
  88. default:
  89. return
  90. }
  91. iow = &IOVecWriter{
  92. fd: file.Fd(),
  93. }
  94. return
  95. }
  96. // 1 2 3 4 5 6
  97. // --- -------------- --- --- --- -----------
  98. // | | | | | | | | | | | | ......
  99. // --- -------------- --- --- --- -----------
  100. //
  101. // 1 -> 5个字节, 3 -> 15个字节, 4 -> 10个字节, 5 -> 15个字节
  102. // 1,3,4,5内存块太小(小于16个字节),因此我们将它组装起来为samllbuffer
  103. // 并且将Base置于每次组装smallBuffer前总长度的尾部.
  104. //
  105. // samllbuffer:
  106. // 1 3 4 5 ........
  107. // ------------------------------
  108. // | |
  109. // ------------------------------
  110. // <--> 第一个小内存块,假设地址为0xF10000
  111. // 5
  112. // <------> 第二个小内存块,假设地址为0xF20000
  113. // 20
  114. // <----------> 第三个小内存块,假设地址为0xF30000
  115. // 30
  116. // <--------------> 第四个小内存块,假设地址为0xF40000
  117. // 45
  118. //
  119. // 开始Base == 每次组装smallBuffer尾部
  120. // 即:
  121. // Base1 = 0, smallBuffer += 5,
  122. // Base3 = 5, smallBuffer += 15,
  123. // Base4 = 20, smallBuffer += 10,
  124. // Base5 = 30, smallBuffer += 15,
  125. //
  126. // 然后我们将每一块内存块都取出来,比samllBuffer小的内存块,我们就将Base指向内存块的地址
  127. // 之前小于16个字节的内存块,肯定会比smallBuffer小,因为smallBuffer是所有小内存快的总和.
  128. // 即:
  129. // Base1 = &smallBuffer[0], Base1 = 0xF10000,
  130. // Base3 = &smallBuffer[5], Base3 = 0xF20000,
  131. // Base4 = &smallBuffer[20], Base4 = 0xF30000,
  132. // Base5 = &smallBuffer[30], Base5 = 0xF40000,
  133. func (iow *IOVecWriter) Write(data []byte) (written int, err error) {
  134. siov := SysIOVec{
  135. Length: uint64(len(data)),
  136. }
  137. // unsafe.Pointer == void *
  138. // Base 用整数的形式来记录内存中有几个数据
  139. // 如果数据小于16,这个时候小块内存的Base还不是数据的内存地址
  140. if siov.Length < 16 {
  141. // Base 置于上一块samllBuffer的末尾
  142. // 然后拼接smallBuffer
  143. siov.Base = uintptr(len(iow.smallBuffer))
  144. iow.smallBuffer = append(iow.smallBuffer, data...)
  145. } else {
  146. siov.Base = uintptr(unsafe.Pointer(&data[0]))
  147. }
  148. iow.sysIOV = append(iow.sysIOV, siov)
  149. return written, nil
  150. }
  151. func (iow *IOVecWriter) Flush() error {
  152. // 取出每一块内存
  153. for i, _ := range iow.sysIOV {
  154. siov := &iow.sysIOV[i] // 一定要拿地址,如果这里不是取地址,那么无法改变下面Base的值
  155. if siov.Base < uintptr(len(iow.smallBuffer)) {
  156. // 这个时候小块内存的Base就是数据的内存地址
  157. siov.Base = uintptr(unsafe.Pointer(&iow.smallBuffer[siov.Base]))
  158. }
  159. }
  160. N := 1024
  161. count := len(iow.sysIOV)
  162. // 每次最多取1024个内存块(不管是大内存块,还是小内存块)
  163. for i := 0; i < count; i += N {
  164. n := count - i
  165. if n > N {
  166. n = N
  167. }
  168. // _, _, errno := syscall.Syscall(syscall.SYS_WRITEV, iow.fd, uintptr(unsafe.Pointer(&iow.sysIOV[i])), uintptr(n))
  169. // if errno != 0 {
  170. // return errors.New(errno.Error())
  171. // }
  172. }
  173. iow.sysIOV = iow.sysIOV[:0]
  174. iow.smallBuffer = iow.smallBuffer[:0]
  175. return nil
  176. }