mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 23:16:49 +00:00
* golangci-lint/CI: Bump versions
Fix remaining linter issues
* Specifically set AppVeyor version
* Fix the infamous typos 👀
* Add go env cmd to AppVeyor
* Add go version cmd to AppVeyor
* Specify AppVeyor image, adjust linters
* Update go get to go install due to deprecation
* Bump golangci-lint timeout time for AppVeyor
* Change NW contract to NQ
* Address nitters
* GetRandomPair -> Pair{}
* Address nits
* Address time nitterinos plus additional tweaks
* More time inception upgrades!
* Bending time and space
135 lines
3.6 KiB
Go
135 lines
3.6 KiB
Go
package orderbook
|
|
|
|
import (
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
neutral uint32 = iota
|
|
active
|
|
)
|
|
|
|
var (
|
|
defaultInterval = time.Minute
|
|
defaultAllowance = time.Second * 30
|
|
)
|
|
|
|
// Node defines a linked list node for an orderbook item
|
|
type Node struct {
|
|
Value Item
|
|
Next *Node
|
|
Prev *Node
|
|
// Denotes time pushed to stack, this will influence cleanup routine when
|
|
// there is a pause or minimal actions during period
|
|
shelved time.Time
|
|
}
|
|
|
|
// stack defines a FILO list of reusable nodes
|
|
type stack struct {
|
|
nodes []*Node
|
|
sema uint32
|
|
count int32
|
|
}
|
|
|
|
// newStack returns a ptr to a new stack instance, also starts the cleaning
|
|
// service
|
|
func newStack() *stack {
|
|
s := &stack{}
|
|
go s.cleaner()
|
|
return s
|
|
}
|
|
|
|
// now defines a time which is now to ensure no other values get passed in
|
|
type now time.Time
|
|
|
|
// getNow returns the time at which it is called
|
|
func getNow() now {
|
|
return now(time.Now())
|
|
}
|
|
|
|
// Push pushes a node pointer into the stack to be reused the time is passed in
|
|
// to allow for inlining which sets the time at which the node is theoretically
|
|
// pushed to a stack.
|
|
func (s *stack) Push(n *Node, tn now) {
|
|
if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) {
|
|
// Stack is in use, for now we can dereference pointer
|
|
return
|
|
}
|
|
// Adds a time when its placed back on to stack.
|
|
n.shelved = time.Time(tn)
|
|
n.Next = nil
|
|
n.Prev = nil
|
|
n.Value = Item{}
|
|
|
|
// Allows for resize when overflow TODO: rethink this
|
|
s.nodes = append(s.nodes[:s.count], n)
|
|
s.count++
|
|
atomic.StoreUint32(&s.sema, neutral)
|
|
}
|
|
|
|
// Pop returns the last pointer off the stack and reduces the count and if empty
|
|
// will produce a lovely fresh node
|
|
func (s *stack) Pop() *Node {
|
|
if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) {
|
|
// Stack is in use, for now we can allocate a new node pointer
|
|
return &Node{}
|
|
}
|
|
|
|
if s.count == 0 {
|
|
// Create an empty node when no nodes are in slice or when cleaning
|
|
// service is running
|
|
atomic.StoreUint32(&s.sema, neutral)
|
|
return &Node{}
|
|
}
|
|
s.count--
|
|
n := s.nodes[s.count]
|
|
atomic.StoreUint32(&s.sema, neutral)
|
|
return n
|
|
}
|
|
|
|
// cleaner (POC) runs to the defaultTimer to clean excess nodes (nodes not being
|
|
// utilised) TODO: Couple time parameters to check for a reduction in activity.
|
|
// Add in counter per second function (?) so if there is a lot of activity don't
|
|
// inhibit stack performance.
|
|
func (s *stack) cleaner() {
|
|
tt := time.NewTimer(defaultInterval)
|
|
sleeperino:
|
|
for range tt.C {
|
|
if !atomic.CompareAndSwapUint32(&s.sema, neutral, active) {
|
|
// Stack is in use, reset timer to zero to recheck for neutral state.
|
|
tt.Reset(0)
|
|
continue
|
|
}
|
|
// As the old nodes are going to be left justified on this slice we
|
|
// should just be able to shift the nodes that are still within time
|
|
// allowance all the way to the left. Not going to resize capacity
|
|
// because if it can get this big, it might as well stay this big.
|
|
// TODO: Test and rethink if sizing is an issue
|
|
for x := int32(0); x < s.count; x++ {
|
|
if time.Since(s.nodes[x].shelved) > defaultAllowance {
|
|
// Old node found continue
|
|
continue
|
|
}
|
|
// First good node found, everything to the left of this on the
|
|
// slice can be reassigned
|
|
var counter int32
|
|
for y := int32(0); y+x < s.count; y++ { // Go through good nodes
|
|
// Reassign
|
|
s.nodes[y] = s.nodes[y+x]
|
|
// Add to the changed counter to remove from main
|
|
// counter
|
|
counter++
|
|
}
|
|
s.count -= counter
|
|
atomic.StoreUint32(&s.sema, neutral)
|
|
tt.Reset(defaultInterval)
|
|
continue sleeperino
|
|
}
|
|
// Nodes are old, flush entirety.
|
|
s.count = 0
|
|
atomic.StoreUint32(&s.sema, neutral)
|
|
tt.Reset(defaultInterval)
|
|
}
|
|
}
|