Update request.go to fix concurrency nonce issues (#285)

* Updates nonce generation to adhere to fifo channel buffer before request executes by routine

* removed unused variables, lns etc

* Fix requested changes and added in timer that disengages lock if out of scope error occurs

* Fixed woopsy daisy issue

* Add benchmark, reduce time in force to unlock before stack insertion, add nil check for edge case

* Remove unusued waitgroup field

* use return nonce.Value and method, rm redundant nonce code, fix tests.

* Fix linter issue: unnecessary conversion
This commit is contained in:
Ryan O'Hara-Reid
2019-05-06 13:46:34 +10:00
committed by Adrian Gallagher
parent 1967507d40
commit 35b94268e0
46 changed files with 312 additions and 258 deletions

View File

@@ -2,18 +2,12 @@ package nonce
import (
"strconv"
"sync"
"sync/atomic"
"time"
)
// Nonce struct holds the nonce value
type Nonce struct {
// Standard nonce
n int64
// Hash table exclusive exchange specific nonce values
boundedCall map[string]int64
boundedMtx sync.Mutex
}
// Inc increments the nonce value
@@ -22,12 +16,12 @@ func (n *Nonce) Inc() {
}
// Get retrives the nonce value
func (n *Nonce) Get() int64 {
return atomic.LoadInt64(&n.n)
func (n *Nonce) Get() Value {
return Value(atomic.LoadInt64(&n.n))
}
// GetInc increments and returns the value of the nonce
func (n *Nonce) GetInc() int64 {
func (n *Nonce) GetInc() Value {
n.Inc()
return n.Get()
}
@@ -39,34 +33,12 @@ func (n *Nonce) Set(val int64) {
// String returns a string version of the nonce
func (n *Nonce) String() string {
return strconv.FormatInt(n.Get(), 10)
return n.Get().String()
}
// Value is a return type for GetValue
type Value int64
// GetValue returns a nonce value and can be set as a higher precision. Values
// stored in an exchange specific hash table using a single locked call.
func (n *Nonce) GetValue(exchName string, nanoPrecision bool) Value {
n.boundedMtx.Lock()
defer n.boundedMtx.Unlock()
if n.boundedCall == nil {
n.boundedCall = make(map[string]int64)
}
if n.boundedCall[exchName] == 0 {
if nanoPrecision {
n.boundedCall[exchName] = time.Now().UnixNano()
return Value(n.boundedCall[exchName])
}
n.boundedCall[exchName] = time.Now().Unix()
return Value(n.boundedCall[exchName])
}
n.boundedCall[exchName]++
return Value(n.boundedCall[exchName])
}
// String is a Value method that changes format to a string
func (v Value) String() string {
return strconv.FormatInt(int64(v), 10)

View File

@@ -1,7 +1,6 @@
package nonce
import (
"strconv"
"testing"
"time"
)
@@ -10,7 +9,7 @@ func TestInc(t *testing.T) {
var nonce Nonce
nonce.Set(1)
nonce.Inc()
expected := int64(2)
expected := Value(2)
result := nonce.Get()
if result != expected {
t.Errorf("Test failed. Expected %d got %d", expected, result)
@@ -20,7 +19,7 @@ func TestInc(t *testing.T) {
func TestGet(t *testing.T) {
var nonce Nonce
nonce.Set(112321313)
expected := int64(112321313)
expected := Value(112321313)
result := nonce.Get()
if expected != result {
t.Errorf("Test failed. Expected %d got %d", expected, result)
@@ -30,7 +29,7 @@ func TestGet(t *testing.T) {
func TestGetInc(t *testing.T) {
var nonce Nonce
nonce.Set(1)
expected := int64(2)
expected := Value(2)
result := nonce.GetInc()
if expected != result {
t.Errorf("Test failed. Expected %d got %d", expected, result)
@@ -40,7 +39,7 @@ func TestGetInc(t *testing.T) {
func TestSet(t *testing.T) {
var nonce Nonce
nonce.Set(1)
expected := int64(1)
expected := Value(1)
result := nonce.Get()
if expected != result {
t.Errorf("Test failed. Expected %d got %d", expected, result)
@@ -55,30 +54,10 @@ func TestString(t *testing.T) {
if expected != result {
t.Errorf("Test failed. Expected %s got %s", expected, result)
}
}
func TestGetValue(t *testing.T) {
var nonce Nonce
timeNowNano := strconv.FormatInt(time.Now().UnixNano(), 10)
time.Sleep(time.Millisecond * 100)
nValue := nonce.GetValue("dingdong", true).String()
if timeNowNano == nValue {
t.Error("Test failed - GetValue() error, incorrect values")
}
if len(nValue) != 19 {
t.Error("Test failed - GetValue() error, incorrect values")
}
timeNowUnix := nonce.GetValue("dongding", false)
if len(timeNowUnix.String()) != 10 {
t.Error("Test failed - GetValue() error, incorrect values")
}
n := nonce.GetValue("dongding", false)
if n != timeNowUnix+1 {
t.Error("Test failed - GetValue() error, incorrect values")
v := nonce.Get()
if expected != v.String() {
t.Errorf("Test failed. Expected %s got %s", expected, result)
}
}
@@ -94,7 +73,7 @@ func TestNonceConcurrency(t *testing.T) {
time.Sleep(time.Second)
result := nonce.Get()
expected := int64(12312 + 1000)
expected := Value(12312 + 1000)
if expected != result {
t.Errorf("Test failed. Expected %d got %d", expected, result)
}