Orderbook/RPCServer: Fix GetOrderbook/Retrieve race condition (refactored and sped up) (#555)

* Kraken - wsProcessOrderBook, the method was returning wrong bids data

* additional  map check to prevent panic

* linter issue fix

* The RPC method GetOrderbook has a race condition and causes panic - refactored and speed up

* The method Retrieve (package orderbook) now return pointer of a copy of s.Books[exchange][p.Base.Item][p.Quote.Item][a].b

* using extra var to optomize code

* bids and asks slices filling optimisation

Co-authored-by: Vazha Bezhanishvili <vazha.bezhanishvili@elegro.eu>
This commit is contained in:
Vazha
2020-09-18 08:09:41 +03:00
committed by GitHub
parent b9aa2bcc2c
commit 73ac8b90dc
2 changed files with 39 additions and 16 deletions

View File

@@ -400,21 +400,27 @@ func (s *RPCServer) GetOrderbook(_ context.Context, r *gctrpc.GetOrderbookReques
return nil, err
}
var bids []*gctrpc.OrderbookItem
for x := range ob.Bids {
bids = append(bids, &gctrpc.OrderbookItem{
Amount: ob.Bids[x].Amount,
Price: ob.Bids[x].Price,
})
}
bids := make([]*gctrpc.OrderbookItem, 0, len(ob.Bids))
asks := make([]*gctrpc.OrderbookItem, 0, len(ob.Asks))
ch := make(chan bool)
var asks []*gctrpc.OrderbookItem
for x := range ob.Asks {
go func() {
for _, b := range ob.Bids {
bids = append(bids, &gctrpc.OrderbookItem{
Amount: b.Amount,
Price: b.Price,
})
}
ch <- true
}()
for _, a := range ob.Asks {
asks = append(asks, &gctrpc.OrderbookItem{
Amount: ob.Asks[x].Amount,
Price: ob.Asks[x].Price,
Amount: a.Amount,
Price: a.Price,
})
}
<-ch
resp := &gctrpc.OrderbookResponse{
Pair: r.Pair,

View File

@@ -140,26 +140,43 @@ func (s *Service) Retrieve(exchange string, p currency.Pair, a asset.Item) (*Bas
exchange = strings.ToLower(exchange)
s.RLock()
defer s.RUnlock()
if s.Books[exchange] == nil {
if _, ok := s.Books[exchange]; !ok {
return nil, fmt.Errorf("no orderbooks for %s exchange", exchange)
}
if s.Books[exchange][p.Base.Item] == nil {
if _, ok := s.Books[exchange][p.Base.Item]; !ok {
return nil, fmt.Errorf("no orderbooks associated with base currency %s",
p.Base)
}
if s.Books[exchange][p.Base.Item][p.Quote.Item] == nil {
if _, ok := s.Books[exchange][p.Base.Item][p.Quote.Item]; !ok {
return nil, fmt.Errorf("no orderbooks associated with quote currency %s",
p.Quote)
}
if s.Books[exchange][p.Base.Item][p.Quote.Item][a] == nil {
var liveOrderBook *Book
var ok bool
if liveOrderBook, ok = s.Books[exchange][p.Base.Item][p.Quote.Item][a]; !ok {
return nil, fmt.Errorf("no orderbooks associated with asset type %s",
a)
}
return s.Books[exchange][p.Base.Item][p.Quote.Item][a].b, nil
localCopyOfAsks := make([]Item, len(s.Books[exchange][p.Base.Item][p.Quote.Item][a].b.Asks))
localCopyOfBids := make([]Item, len(s.Books[exchange][p.Base.Item][p.Quote.Item][a].b.Bids))
copy(localCopyOfBids, liveOrderBook.b.Bids)
copy(localCopyOfAsks, liveOrderBook.b.Asks)
ob := Base{
Pair: liveOrderBook.b.Pair,
Bids: localCopyOfBids,
Asks: localCopyOfAsks,
LastUpdated: liveOrderBook.b.LastUpdated,
LastUpdateID: liveOrderBook.b.LastUpdateID,
AssetType: liveOrderBook.b.AssetType,
ExchangeName: liveOrderBook.b.ExchangeName,
}
return &ob, nil
}
// TotalBidsAmount returns the total amount of bids and the total orderbook