本站源代码
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.

313 satır
5.4KB

  1. package nodb
  2. import (
  3. "bufio"
  4. "bytes"
  5. "errors"
  6. "io"
  7. "os"
  8. "time"
  9. "github.com/lunny/log"
  10. "github.com/lunny/nodb/store/driver"
  11. )
  12. const (
  13. maxReplBatchNum = 100
  14. maxReplLogSize = 1 * 1024 * 1024
  15. )
  16. var (
  17. ErrSkipEvent = errors.New("skip to next event")
  18. )
  19. var (
  20. errInvalidBinLogEvent = errors.New("invalid binglog event")
  21. errInvalidBinLogFile = errors.New("invalid binlog file")
  22. )
  23. type replBatch struct {
  24. wb driver.IWriteBatch
  25. events [][]byte
  26. l *Nodb
  27. lastHead *BinLogHead
  28. }
  29. func (b *replBatch) Commit() error {
  30. b.l.commitLock.Lock()
  31. defer b.l.commitLock.Unlock()
  32. err := b.wb.Commit()
  33. if err != nil {
  34. b.Rollback()
  35. return err
  36. }
  37. if b.l.binlog != nil {
  38. if err = b.l.binlog.Log(b.events...); err != nil {
  39. b.Rollback()
  40. return err
  41. }
  42. }
  43. b.events = [][]byte{}
  44. b.lastHead = nil
  45. return nil
  46. }
  47. func (b *replBatch) Rollback() error {
  48. b.wb.Rollback()
  49. b.events = [][]byte{}
  50. b.lastHead = nil
  51. return nil
  52. }
  53. func (l *Nodb) replicateEvent(b *replBatch, event []byte) error {
  54. if len(event) == 0 {
  55. return errInvalidBinLogEvent
  56. }
  57. b.events = append(b.events, event)
  58. logType := uint8(event[0])
  59. switch logType {
  60. case BinLogTypePut:
  61. return l.replicatePutEvent(b, event)
  62. case BinLogTypeDeletion:
  63. return l.replicateDeleteEvent(b, event)
  64. default:
  65. return errInvalidBinLogEvent
  66. }
  67. }
  68. func (l *Nodb) replicatePutEvent(b *replBatch, event []byte) error {
  69. key, value, err := decodeBinLogPut(event)
  70. if err != nil {
  71. return err
  72. }
  73. b.wb.Put(key, value)
  74. return nil
  75. }
  76. func (l *Nodb) replicateDeleteEvent(b *replBatch, event []byte) error {
  77. key, err := decodeBinLogDelete(event)
  78. if err != nil {
  79. return err
  80. }
  81. b.wb.Delete(key)
  82. return nil
  83. }
  84. func ReadEventFromReader(rb io.Reader, f func(head *BinLogHead, event []byte) error) error {
  85. head := &BinLogHead{}
  86. var err error
  87. for {
  88. if err = head.Read(rb); err != nil {
  89. if err == io.EOF {
  90. break
  91. } else {
  92. return err
  93. }
  94. }
  95. var dataBuf bytes.Buffer
  96. if _, err = io.CopyN(&dataBuf, rb, int64(head.PayloadLen)); err != nil {
  97. return err
  98. }
  99. err = f(head, dataBuf.Bytes())
  100. if err != nil && err != ErrSkipEvent {
  101. return err
  102. }
  103. }
  104. return nil
  105. }
  106. func (l *Nodb) ReplicateFromReader(rb io.Reader) error {
  107. b := new(replBatch)
  108. b.wb = l.ldb.NewWriteBatch()
  109. b.l = l
  110. f := func(head *BinLogHead, event []byte) error {
  111. if b.lastHead == nil {
  112. b.lastHead = head
  113. } else if !b.lastHead.InSameBatch(head) {
  114. if err := b.Commit(); err != nil {
  115. log.Fatal("replication error %s, skip to next", err.Error())
  116. return ErrSkipEvent
  117. }
  118. b.lastHead = head
  119. }
  120. err := l.replicateEvent(b, event)
  121. if err != nil {
  122. log.Fatal("replication error %s, skip to next", err.Error())
  123. return ErrSkipEvent
  124. }
  125. return nil
  126. }
  127. err := ReadEventFromReader(rb, f)
  128. if err != nil {
  129. b.Rollback()
  130. return err
  131. }
  132. return b.Commit()
  133. }
  134. func (l *Nodb) ReplicateFromData(data []byte) error {
  135. rb := bytes.NewReader(data)
  136. err := l.ReplicateFromReader(rb)
  137. return err
  138. }
  139. func (l *Nodb) ReplicateFromBinLog(filePath string) error {
  140. f, err := os.Open(filePath)
  141. if err != nil {
  142. return err
  143. }
  144. rb := bufio.NewReaderSize(f, 4096)
  145. err = l.ReplicateFromReader(rb)
  146. f.Close()
  147. return err
  148. }
  149. // try to read events, if no events read, try to wait the new event singal until timeout seconds
  150. func (l *Nodb) ReadEventsToTimeout(info *BinLogAnchor, w io.Writer, timeout int) (n int, err error) {
  151. lastIndex := info.LogFileIndex
  152. lastPos := info.LogPos
  153. n = 0
  154. if l.binlog == nil {
  155. //binlog not supported
  156. info.LogFileIndex = 0
  157. info.LogPos = 0
  158. return
  159. }
  160. n, err = l.ReadEventsTo(info, w)
  161. if err == nil && info.LogFileIndex == lastIndex && info.LogPos == lastPos {
  162. //no events read
  163. select {
  164. case <-l.binlog.Wait():
  165. case <-time.After(time.Duration(timeout) * time.Second):
  166. }
  167. return l.ReadEventsTo(info, w)
  168. }
  169. return
  170. }
  171. func (l *Nodb) ReadEventsTo(info *BinLogAnchor, w io.Writer) (n int, err error) {
  172. n = 0
  173. if l.binlog == nil {
  174. //binlog not supported
  175. info.LogFileIndex = 0
  176. info.LogPos = 0
  177. return
  178. }
  179. index := info.LogFileIndex
  180. offset := info.LogPos
  181. filePath := l.binlog.FormatLogFilePath(index)
  182. var f *os.File
  183. f, err = os.Open(filePath)
  184. if os.IsNotExist(err) {
  185. lastIndex := l.binlog.LogFileIndex()
  186. if index == lastIndex {
  187. //no binlog at all
  188. info.LogPos = 0
  189. } else {
  190. //slave binlog info had lost
  191. info.LogFileIndex = -1
  192. }
  193. }
  194. if err != nil {
  195. if os.IsNotExist(err) {
  196. err = nil
  197. }
  198. return
  199. }
  200. defer f.Close()
  201. var fileSize int64
  202. st, _ := f.Stat()
  203. fileSize = st.Size()
  204. if fileSize == info.LogPos {
  205. return
  206. }
  207. if _, err = f.Seek(offset, os.SEEK_SET); err != nil {
  208. //may be invliad seek offset
  209. return
  210. }
  211. var lastHead *BinLogHead = nil
  212. head := &BinLogHead{}
  213. batchNum := 0
  214. for {
  215. if err = head.Read(f); err != nil {
  216. if err == io.EOF {
  217. //we will try to use next binlog
  218. if index < l.binlog.LogFileIndex() {
  219. info.LogFileIndex += 1
  220. info.LogPos = 0
  221. }
  222. err = nil
  223. return
  224. } else {
  225. return
  226. }
  227. }
  228. if lastHead == nil {
  229. lastHead = head
  230. batchNum++
  231. } else if !lastHead.InSameBatch(head) {
  232. lastHead = head
  233. batchNum++
  234. if batchNum > maxReplBatchNum || n > maxReplLogSize {
  235. return
  236. }
  237. }
  238. if err = head.Write(w); err != nil {
  239. return
  240. }
  241. if _, err = io.CopyN(w, f, int64(head.PayloadLen)); err != nil {
  242. return
  243. }
  244. n += (head.Len() + int(head.PayloadLen))
  245. info.LogPos = info.LogPos + int64(head.Len()) + int64(head.PayloadLen)
  246. }
  247. return
  248. }
上海开阖软件有限公司 沪ICP备12045867号-1