github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/cdclog/puller.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package cdclog 15 16 import ( 17 "context" 18 19 "github.com/pingcap/errors" 20 "github.com/pingcap/log" 21 22 "github.com/pingcap/br/pkg/storage" 23 ) 24 25 // EventPuller pulls next event in ts order. 26 type EventPuller struct { 27 ddlDecoder *JSONEventBatchMixedDecoder 28 rowChangedDecoder *JSONEventBatchMixedDecoder 29 currentDDLItem *SortItem 30 currentRowChangedItem *SortItem 31 32 schema string 33 table string 34 35 storage storage.ExternalStorage 36 ddlFiles []string 37 rowChangedFiles []string 38 39 ddlFileIndex int 40 rowChangedFileIndex int 41 } 42 43 // NewEventPuller create eventPuller by given log files, we assume files come in ts order. 44 func NewEventPuller( 45 ctx context.Context, 46 schema string, 47 table string, 48 ddlFiles []string, 49 rowChangedFiles []string, 50 storage storage.ExternalStorage) (*EventPuller, error) { 51 var ( 52 ddlDecoder *JSONEventBatchMixedDecoder 53 ddlFileIndex int 54 rowChangedDecoder *JSONEventBatchMixedDecoder 55 rowFileIndex int 56 ) 57 if len(ddlFiles) == 0 { 58 log.Info("There is no ddl file to restore") 59 } else { 60 data, err := storage.ReadFile(ctx, ddlFiles[0]) 61 if err != nil { 62 return nil, errors.Trace(err) 63 } 64 if len(data) != 0 { 65 ddlFileIndex++ 66 ddlDecoder, err = NewJSONEventBatchDecoder(data) 67 if err != nil { 68 return nil, errors.Trace(err) 69 } 70 } 71 } 72 73 if len(rowChangedFiles) == 0 { 74 log.Info("There is no row changed file to restore") 75 } else { 76 data, err := storage.ReadFile(ctx, rowChangedFiles[0]) 77 if err != nil { 78 return nil, errors.Trace(err) 79 } 80 if len(data) != 0 { 81 rowFileIndex++ 82 rowChangedDecoder, err = NewJSONEventBatchDecoder(data) 83 if err != nil { 84 return nil, errors.Trace(err) 85 } 86 } 87 } 88 89 return &EventPuller{ 90 schema: schema, 91 table: table, 92 93 ddlDecoder: ddlDecoder, 94 rowChangedDecoder: rowChangedDecoder, 95 96 ddlFiles: ddlFiles, 97 rowChangedFiles: rowChangedFiles, 98 ddlFileIndex: ddlFileIndex, 99 rowChangedFileIndex: rowFileIndex, 100 101 storage: storage, 102 }, nil 103 } 104 105 // PullOneEvent pulls one event in ts order. 106 // The Next event which can be DDL item or Row changed Item depends on next commit ts. 107 func (e *EventPuller) PullOneEvent(ctx context.Context) (*SortItem, error) { 108 var ( 109 err error 110 data []byte 111 ) 112 // ddl exists 113 if e.ddlDecoder != nil { 114 // current file end, read next file if next file exists 115 if !e.ddlDecoder.HasNext() && e.ddlFileIndex < len(e.ddlFiles) { 116 path := e.ddlFiles[e.ddlFileIndex] 117 data, err = e.storage.ReadFile(ctx, path) 118 if err != nil { 119 return nil, errors.Trace(err) 120 } 121 if len(data) > 0 { 122 e.ddlFileIndex++ 123 e.ddlDecoder, err = NewJSONEventBatchDecoder(data) 124 if err != nil { 125 return nil, errors.Trace(err) 126 } 127 } 128 } 129 // set current DDL item first 130 if e.currentDDLItem == nil { 131 e.currentDDLItem, err = e.ddlDecoder.NextEvent(DDL) 132 if err != nil { 133 return nil, errors.Trace(err) 134 } 135 } 136 } 137 // dml exists 138 if e.rowChangedDecoder != nil { 139 // current file end, read next file if next file exists 140 if !e.rowChangedDecoder.HasNext() && e.rowChangedFileIndex < len(e.rowChangedFiles) { 141 path := e.rowChangedFiles[e.rowChangedFileIndex] 142 data, err = e.storage.ReadFile(ctx, path) 143 if err != nil { 144 return nil, errors.Trace(err) 145 } 146 if len(data) != 0 { 147 e.rowChangedFileIndex++ 148 e.rowChangedDecoder, err = NewJSONEventBatchDecoder(data) 149 if err != nil { 150 return nil, errors.Trace(err) 151 } 152 } 153 } 154 if e.currentRowChangedItem == nil { 155 e.currentRowChangedItem, err = e.rowChangedDecoder.NextEvent(RowChanged) 156 if err != nil { 157 return nil, errors.Trace(err) 158 } 159 } 160 } 161 162 var returnItem *SortItem 163 switch { 164 case e.currentDDLItem != nil: 165 if e.currentDDLItem.LessThan(e.currentRowChangedItem) { 166 returnItem = e.currentDDLItem 167 e.currentDDLItem, err = e.ddlDecoder.NextEvent(DDL) 168 if err != nil { 169 return nil, errors.Trace(err) 170 } 171 break 172 } 173 fallthrough 174 case e.currentRowChangedItem != nil: 175 returnItem = e.currentRowChangedItem 176 e.currentRowChangedItem, err = e.rowChangedDecoder.NextEvent(RowChanged) 177 if err != nil { 178 return nil, errors.Trace(err) 179 } 180 default: 181 log.Info("puller finished") 182 } 183 return returnItem, nil 184 }