Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dcrpg: replace trylock import, fix pgonline test setup #1868

Merged
merged 2 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions cmd/dcrdata/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,6 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chappjc/trylock v1.0.0 h1:WR9J1cP/+h0x9RoKsxf4I0AnYg7aONYjiwYwys8nibA=
github.com/chappjc/trylock v1.0.0/go.mod h1:+FnHf7ZLQpdbR3H9QZUrMKF1jfyHmtpbZddoYhSTzvw=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
Expand Down
1 change: 0 additions & 1 deletion db/dcrpg/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ replace github.com/decred/dcrdata/v7 => ../../

require (
decred.org/dcrwallet/v2 v2.0.0-20210901150254-d3e3ef3c3c26
github.com/chappjc/trylock v1.0.0
github.com/davecgh/go-spew v1.1.1
github.com/decred/dcrd/blockchain/stake/v4 v4.0.0-20210901152745-8830d9c9cdba
github.com/decred/dcrd/chaincfg/chainhash v1.0.3-0.20210525214639-70483c835b7f
Expand Down
2 changes: 0 additions & 2 deletions db/dcrpg/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/chappjc/trylock v1.0.0 h1:WR9J1cP/+h0x9RoKsxf4I0AnYg7aONYjiwYwys8nibA=
github.com/chappjc/trylock v1.0.0/go.mod h1:+FnHf7ZLQpdbR3H9QZUrMKF1jfyHmtpbZddoYhSTzvw=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
Expand Down
4 changes: 2 additions & 2 deletions db/dcrpg/pgblockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"time"

"decred.org/dcrwallet/v2/wallet/txrules"
"github.com/chappjc/trylock"
"github.com/decred/dcrd/blockchain/stake/v4"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/chaincfg/v3"
Expand All @@ -39,6 +38,7 @@ import (
"github.com/decred/dcrdata/v7/mempool"
"github.com/decred/dcrdata/v7/rpcutils"
"github.com/decred/dcrdata/v7/stakedb"
"github.com/decred/dcrdata/v7/trylock"
"github.com/decred/dcrdata/v7/txhelpers"
)

Expand Down Expand Up @@ -102,7 +102,7 @@ func TicketPoolData(interval dbtypes.TimeBasedGrouping, height int64) (timeGraph
intervalFound = tFound && pFound && dFound

actualHeight = ticketPoolGraphsCache.Height[interval]
isStale = ticketPoolGraphsCache.Height[interval] != height
isStale = actualHeight != height

return
}
Expand Down
8 changes: 1 addition & 7 deletions db/dcrpg/pgblockchain_common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ var (
addrCacheCap int = 1e4
)

type dummyParser struct{}

func (p *dummyParser) UpdateSignal() <-chan struct{} {
return make(chan struct{})
}

func openDB() (func() error, error) {
dbi := &DBInfo{
Host: dbconfig.PGTestsHost,
Expand All @@ -70,7 +64,7 @@ func openDB() (func() error, error) {
true, false, 24, 1024, 1 << 16,
}
var err error
db, err = NewChainDB(context.Background(), cfg, nil, nil, new(dummyParser), nil, func() {})
db, err = NewChainDB(context.Background(), cfg, nil, nil, nil, func() {})
cleanUp := func() error { return nil }
if db != nil {
cleanUp = db.Close
Expand Down
75 changes: 75 additions & 0 deletions trylock/trylock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright (c) 2021, The Decred developers
// See LICENSE for details.

package trylock

import (
"math/rand"
"sync"
"time"
)

// Mutex is a "try lock" for coordinating multiple accessors, while allowing
// only a single updater. It is not very smart about queueing when there are
// multiple callers of Lock waiting.
type Mutex struct {
mtx sync.Mutex
c chan struct{}
}

// tryLock will attempt to obtain an exclusive lock or a non-nil wait channel.
// If the lock is already held, the returned channel will be non-nil and the
// caller should wait for it to be closed before trying again. There is no
// queueing. Use the Lock method to block until it is acquired.
//
// tryLock returns a bool, busy, indicating if another caller has already
// obtained the lock. When busy is false, the caller has obtained the exclusive
// lock, and Unlock should be called when ready to release the lock. When busy
// is true, the returned channel should be received from to block until the
// updater has released the lock.
func (tl *Mutex) tryLock() (busy bool, wait chan struct{}) {
tl.mtx.Lock()
defer tl.mtx.Unlock()
if tl.c == nil {
tl.c = make(chan struct{})
return false, nil
}
return true, tl.c
}

// TryLock attempts to acquire the lock. If it returns true, the caller has
// obtained it exclusively, and should call Unlock when done with it. If it
// returns false, the lock was already held.
func (tl *Mutex) TryLock() bool {
busy, _ := tl.tryLock()
return !busy // if true, caller must Unlock
}

// Unlock releases the lock. Only the caller of Lock, or TryLock when true was
// returned, should call Unlock.
func (tl *Mutex) Unlock() {
tl.mtx.Lock()
defer tl.mtx.Unlock()
close(tl.c)
tl.c = nil
}

const maxDelay int64 = 5000 // microseconds

// Lock acquires the lock. If it is already held, this blocks until it can be
// obtained.
func (tl *Mutex) Lock() {
var i int64
for { // there is no queue, just a race
busy, wait := tl.tryLock()
if !busy {
return // caller must do Unlock to close and nil out c
}
// otherwise wait and try again
<-wait
if i > 0 && i < maxDelay { // one quick retry, then randomish delay up to maxDelay retires, then priority
time.Sleep(time.Duration(rand.Int63n(maxDelay-i)) * time.Microsecond)
}
i++
}
}
61 changes: 61 additions & 0 deletions trylock/trylock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package trylock

import (
"sync"
"testing"
)

func TestTryLock(t *testing.T) {
mu := &Mutex{}
if !mu.TryLock() {
t.Fatal("mutex must be unlocked")
}
if mu.TryLock() {
t.Fatal("mutex must be locked")
}

mu.Unlock()
if !mu.TryLock() {
t.Fatal("mutex must be unlocked")
}
if mu.TryLock() {
t.Fatal("mutex must be locked")
}

mu.Unlock()
mu.Lock()
if mu.TryLock() {
t.Fatal("mutex must be locked")
}
if mu.TryLock() {
t.Fatal("mutex must be locked")
}
mu.Unlock()
}

func TestTryLockRace(t *testing.T) {
var wg sync.WaitGroup
mu := new(Mutex)
var x int
for i := 0; i < 1024; i++ {
if i%2 == 0 {
wg.Add(1)
go func() {
defer wg.Done()
if mu.TryLock() {
x++
mu.Unlock()
}
}()
continue
}
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
x++
mu.Unlock()
}()
}
wg.Wait()
}