code.vegaprotocol.io/vega@v0.79.0/datanode/service/market_data.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 service 17 18 import ( 19 "context" 20 "fmt" 21 "sync" 22 "time" 23 24 "code.vegaprotocol.io/vega/datanode/entities" 25 "code.vegaprotocol.io/vega/datanode/utils" 26 "code.vegaprotocol.io/vega/logging" 27 ) 28 29 type MarketDataStore interface { 30 Add(data *entities.MarketData) error 31 Flush(ctx context.Context) ([]*entities.MarketData, error) 32 GetMarketDataByID(ctx context.Context, marketID string) (entities.MarketData, error) 33 GetMarketsData(ctx context.Context) ([]entities.MarketData, error) 34 GetHistoricMarketData(ctx context.Context, marketID string, start, end *time.Time, pagination entities.Pagination) ([]entities.MarketData, entities.PageInfo, error) 35 } 36 37 type MarketData struct { 38 store MarketDataStore 39 observer utils.Observer[*entities.MarketData] 40 cache map[entities.MarketID]*entities.MarketData 41 cacheLock sync.RWMutex 42 } 43 44 func NewMarketData(store MarketDataStore, log *logging.Logger) *MarketData { 45 return &MarketData{ 46 store: store, 47 observer: utils.NewObserver[*entities.MarketData]("market_data", log, 0, 0), 48 cache: make(map[entities.MarketID]*entities.MarketData), 49 } 50 } 51 52 func (m *MarketData) Add(data *entities.MarketData) error { 53 if err := m.store.Add(data); err != nil { 54 return err 55 } 56 m.cacheLock.Lock() 57 m.cache[data.Market] = data 58 m.cacheLock.Unlock() 59 return nil 60 } 61 62 func (m *MarketData) Flush(ctx context.Context) error { 63 flushed, err := m.store.Flush(ctx) 64 if err != nil { 65 return err 66 } 67 m.observer.Notify(flushed) 68 return nil 69 } 70 71 func (m *MarketData) Initialise(ctx context.Context) error { 72 m.cacheLock.Lock() 73 defer m.cacheLock.Unlock() 74 75 all, err := m.store.GetMarketsData(ctx) 76 if err != nil { 77 return err 78 } 79 for i := 0; i < len(all); i++ { 80 m.cache[all[i].Market] = &all[i] 81 } 82 return nil 83 } 84 85 func (m *MarketData) GetMarketDataByID(ctx context.Context, marketID string) (entities.MarketData, error) { 86 m.cacheLock.RLock() 87 defer m.cacheLock.RUnlock() 88 89 data, ok := m.cache[entities.MarketID(marketID)] 90 if !ok { 91 return entities.MarketData{}, fmt.Errorf("no market data for market: %v", marketID) 92 } 93 return *data, nil 94 } 95 96 func (m *MarketData) GetMarketsData(ctx context.Context) ([]entities.MarketData, error) { 97 m.cacheLock.RLock() 98 defer m.cacheLock.RUnlock() 99 100 data := make([]entities.MarketData, 0, len(m.cache)) 101 for _, v := range m.cache { 102 data = append(data, *v) 103 } 104 return data, nil 105 } 106 107 func (m *MarketData) GetHistoricMarketData(ctx context.Context, marketID string, start, end *time.Time, pagination entities.Pagination) ([]entities.MarketData, entities.PageInfo, error) { 108 return m.store.GetHistoricMarketData(ctx, marketID, start, end, pagination) 109 } 110 111 func (m *MarketData) ObserveMarketData( 112 ctx context.Context, retries int, marketID []string, 113 ) (<-chan []*entities.MarketData, uint64) { 114 markets := map[string]bool{} 115 for _, id := range marketID { 116 markets[id] = true 117 } 118 119 ch, ref := m.observer.Observe(ctx, 120 retries, 121 func(md *entities.MarketData) bool { return markets[md.Market.String()] }) 122 return ch, ref 123 }