currency: boost retrieval speed when calling currency.NewCode() (#1014)

* currency: optimization pass

* currency: reimplement and fix tests and run benchmark comparison

* Update currency/code_test.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: nits

* glorious: nits

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
This commit is contained in:
Ryan O'Hara-Reid
2022-08-31 10:45:45 +10:00
committed by GitHub
parent 42291fbbfe
commit 7b958d2c05
4 changed files with 225 additions and 135 deletions

View File

@@ -27,6 +27,8 @@ var (
errRoleUnset = errors.New("role unset")
)
// String implements the stringer interface and returns a string representation
// of the underlying role.
func (r Role) String() string {
switch r {
case Fiat:
@@ -89,22 +91,24 @@ func (b *BaseCodes) GetFullCurrencyData() (File, error) {
var file File
b.mtx.Lock()
defer b.mtx.Unlock()
for i := range b.Items {
switch b.Items[i].Role {
case Unset:
file.UnsetCurrency = append(file.UnsetCurrency, b.Items[i])
case Fiat:
file.FiatCurrency = append(file.FiatCurrency, b.Items[i])
case Cryptocurrency:
file.Cryptocurrency = append(file.Cryptocurrency, b.Items[i])
case Token:
file.Token = append(file.Token, b.Items[i])
case Contract:
file.Contracts = append(file.Contracts, b.Items[i])
case Stable:
file.Stable = append(file.Stable, b.Items[i])
default:
return file, errors.New("role undefined")
for _, stored := range b.Items {
for x := range stored {
switch stored[x].Role {
case Unset:
file.UnsetCurrency = append(file.UnsetCurrency, stored[x])
case Fiat:
file.FiatCurrency = append(file.FiatCurrency, stored[x])
case Cryptocurrency:
file.Cryptocurrency = append(file.Cryptocurrency, stored[x])
case Token:
file.Token = append(file.Token, stored[x])
case Contract:
file.Contracts = append(file.Contracts, stored[x])
case Stable:
file.Stable = append(file.Stable, stored[x])
default:
return file, errors.New("role undefined")
}
}
}
file.LastMainUpdate = b.LastMainUpdate.Unix()
@@ -116,47 +120,60 @@ func (b *BaseCodes) GetFullCurrencyData() (File, error) {
func (b *BaseCodes) GetCurrencies() Currencies {
b.mtx.Lock()
currencies := make(Currencies, len(b.Items))
for i := range b.Items {
currencies[i] = Code{Item: b.Items[i]}
var target int
for _, stored := range b.Items {
if len(stored) == 0 {
continue
}
currencies[target] = Code{Item: stored[0]}
target++
}
b.mtx.Unlock()
return currencies
}
// UpdateCurrency updates or registers a currency/contract
func (b *BaseCodes) UpdateCurrency(fullName, symbol, blockchain string, id int, r Role) error {
if r == Unset {
return fmt.Errorf("cannot update currency %w for %s", errRoleUnset, symbol)
func (b *BaseCodes) UpdateCurrency(update *Item) error {
if update == nil {
return errItemIsNil
}
if update.Symbol == "" {
return errSymbolEmpty
}
if update.Role == Unset {
return fmt.Errorf("cannot update currency %w for %s", errRoleUnset, update.Symbol)
}
update.Symbol = strings.ToUpper(update.Symbol)
update.Lower = strings.ToLower(update.Symbol)
b.mtx.Lock()
defer b.mtx.Unlock()
for i := range b.Items {
if b.Items[i].Symbol != symbol || (b.Items[i].Role != Unset && b.Items[i].Role != r) {
continue
}
if fullName != "" {
b.Items[i].FullName = fullName
stored, ok := b.Items[update.Symbol]
if ok {
for x := range stored {
if stored[x].Role != Unset && stored[x].Role != update.Role {
continue
}
stored[x].Role = update.Role // NOTE: Update role is checked above.
if update.FullName != "" {
stored[x].FullName = update.FullName
}
if update.AssocChain != "" {
stored[x].AssocChain = update.AssocChain
}
if update.ID != 0 {
stored[x].ID = update.ID
}
return nil
}
if r != Unset {
b.Items[i].Role = r
}
if blockchain != "" {
b.Items[i].AssocChain = blockchain
}
if id != 0 {
b.Items[i].ID = id
}
return nil
}
b.Items = append(b.Items, &Item{
Symbol: symbol,
FullName: fullName,
Role: r,
AssocChain: blockchain,
ID: id,
})
b.Items[update.Symbol] = append(b.Items[update.Symbol], update)
return nil
}
@@ -181,26 +198,30 @@ func (b *BaseCodes) Register(c string, newRole Role) Code {
b.mtx.Lock()
defer b.mtx.Unlock()
for i := range b.Items {
if b.Items[i].Symbol != c {
continue
}
if newRole != Unset {
if b.Items[i].Role == Unset {
b.Items[i].Role = newRole
} else if b.Items[i].Role != newRole {
// This will duplicate item with same name but different role.
// TODO: This will need a specific update to NewCode to add in
// a specific param to find the exact name and role.
continue
}
}
return Code{Item: b.Items[i], UpperCase: format}
if b.Items == nil {
b.Items = make(map[string][]*Item)
}
stored, ok := b.Items[c]
if ok {
for x := range stored {
if newRole != Unset {
if stored[x].Role != Unset && stored[x].Role != newRole {
// This will duplicate item with same name but different
// role if not matched in stored list.
// TODO: This will need a specific update to NewCode() or
// new function to find the exact name and role.
continue
}
stored[x].Role = newRole
}
return Code{Item: stored[x], UpperCase: format}
}
}
newItem := &Item{Symbol: c, Lower: strings.ToLower(c), Role: newRole}
b.Items = append(b.Items, newItem)
b.Items[c] = append(b.Items[c], newItem)
return Code{Item: newItem, UpperCase: format}
}
@@ -219,14 +240,21 @@ func (b *BaseCodes) LoadItem(item *Item) error {
b.mtx.Lock()
defer b.mtx.Unlock()
for i := range b.Items {
if b.Items[i].Symbol != item.Symbol ||
(b.Items[i].Role != Unset && item.Role != Unset && b.Items[i].Role != item.Role) {
continue
stored, ok := b.Items[item.Symbol]
if ok {
for x := range stored {
if stored[x].Role == item.Role {
return nil
}
if stored[x].Role == Unset && item.Role != Unset {
stored[x].Role = item.Role
return nil
}
}
return nil
}
b.Items = append(b.Items, item)
b.Items[item.Symbol] = append(b.Items[item.Symbol], item)
return nil
}