code.vegaprotocol.io/vega@v0.79.0/datanode/broker/buffer_files_event_source.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package broker 17 18 import ( 19 "context" 20 "fmt" 21 "io/fs" 22 "os" 23 "path/filepath" 24 "sort" 25 "strings" 26 "sync" 27 "time" 28 29 "code.vegaprotocol.io/vega/core/events" 30 "code.vegaprotocol.io/vega/libs/proto" 31 eventspb "code.vegaprotocol.io/vega/protos/vega/events/v1" 32 ) 33 34 type bufferFileEventSource struct { 35 mu sync.Mutex 36 bufferFilesDir string 37 timeBetweenBlocks time.Duration 38 sendChannelBufferSize int 39 chainID string 40 archiveFiles []fs.FileInfo 41 currentBlock string 42 } 43 44 //revive:disable:unexported-return 45 func NewBufferFilesEventSource(bufferFilesDir string, timeBetweenBlocks time.Duration, 46 sendChannelBufferSize int, chainID string) (*bufferFileEventSource, error, 47 ) { 48 var archiveFiles []fs.FileInfo 49 err := filepath.Walk(bufferFilesDir, func(path string, info fs.FileInfo, err error) error { 50 if err != nil || (info != nil && info.IsDir()) { 51 return nil //nolint:nilerr 52 } 53 archiveFiles = append(archiveFiles, info) 54 return nil 55 }) 56 if err != nil { 57 return nil, fmt.Errorf("failed to walk directory: %w", err) 58 } 59 60 // We rely on the name to sort the files in age order, oldest first 61 sort.Slice(archiveFiles, func(i, j int) bool { 62 return strings.Compare(archiveFiles[i].Name(), archiveFiles[j].Name()) < 0 63 }) 64 65 return &bufferFileEventSource{ 66 bufferFilesDir: bufferFilesDir, 67 timeBetweenBlocks: timeBetweenBlocks, 68 sendChannelBufferSize: sendChannelBufferSize, 69 chainID: chainID, 70 archiveFiles: archiveFiles, 71 }, nil 72 } 73 74 func (e *bufferFileEventSource) Listen() error { 75 return nil 76 } 77 78 func (e *bufferFileEventSource) Send(events.Event) error { 79 return nil 80 } 81 82 func (e *bufferFileEventSource) Receive(ctx context.Context) (<-chan []byte, <-chan error) { 83 eventsCh := make(chan []byte, e.sendChannelBufferSize) 84 errorCh := make(chan error, 1) 85 86 go func() { 87 for _, eventFile := range e.archiveFiles { 88 err := e.sendAllRawEventsInFile(ctx, eventsCh, filepath.Join(e.bufferFilesDir, eventFile.Name()), 89 e.timeBetweenBlocks) 90 if err != nil { 91 errorCh <- fmt.Errorf("failed to send events in buffer file: %w", err) 92 } 93 } 94 }() 95 96 return eventsCh, errorCh 97 } 98 99 func (e *bufferFileEventSource) sendAllRawEventsInFile(ctx context.Context, out chan<- []byte, file string, 100 timeBetweenBlocks time.Duration, 101 ) error { 102 eventFile, err := os.Open(file) 103 defer func() { 104 _ = eventFile.Close() 105 }() 106 107 if err != nil { 108 return fmt.Errorf("failed to open file: %w", err) 109 } 110 111 var offset int64 112 113 for { 114 select { 115 case <-ctx.Done(): 116 return nil 117 default: 118 rawEvent, _, read, err := ReadRawEvent(eventFile, offset) 119 if err != nil { 120 return fmt.Errorf("failed to read buffered event:%w", err) 121 } 122 123 if read == 0 { 124 return nil 125 } 126 127 offset += int64(read) 128 129 // We have to deserialize the busEvent here (even though we output the raw busEvent) 130 // to be able to skip the first few events before we get a BeginBlock and to be 131 // able to sleep between blocks. 132 busEvent := &eventspb.BusEvent{} 133 if err := proto.Unmarshal(rawEvent, busEvent); err != nil { 134 return fmt.Errorf("failed to unmarshal bus event: %w", err) 135 } 136 137 // Buffer files do not necessarily start on block boundaries, to prevent sending part of a block 138 // events are ignored until an initial begin block event is encountered 139 e.mu.Lock() 140 if len(e.currentBlock) == 0 { 141 if busEvent.Type == eventspb.BusEventType_BUS_EVENT_TYPE_BEGIN_BLOCK { 142 e.currentBlock = busEvent.Block 143 } else { 144 e.mu.Unlock() 145 continue 146 } 147 } 148 149 // Optional sleep between blocks to mimic running against core 150 if busEvent.Block != e.currentBlock { 151 time.Sleep(timeBetweenBlocks) 152 e.currentBlock = busEvent.Block 153 } 154 e.mu.Unlock() 155 156 err = sendRawEvent(ctx, out, rawEvent) 157 if err != nil { 158 return fmt.Errorf("send event failed:%w", err) 159 } 160 } 161 } 162 } 163 164 func sendRawEvent(ctx context.Context, out chan<- []byte, rawEvent []byte) error { 165 select { 166 case out <- rawEvent: 167 case <-ctx.Done(): 168 return ctx.Err() 169 } 170 return nil 171 }