swarm/network: measure time of messages in priority queue (#19250)

This commit is contained in:
Anton Evangelatov 2019-03-20 21:30:34 +01:00 committed by GitHub
parent c53c5e616f
commit baded64d88
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 87 additions and 60 deletions

View File

@ -40,6 +40,7 @@ var (
allhosts string allhosts string
hosts []string hosts []string
filesize int filesize int
inputSeed int
syncDelay int syncDelay int
httpPort int httpPort int
wsPort int wsPort int
@ -74,6 +75,12 @@ func main() {
Usage: "ws port", Usage: "ws port",
Destination: &wsPort, Destination: &wsPort,
}, },
cli.IntFlag{
Name: "seed",
Value: 0,
Usage: "input seed in case we need deterministic upload",
Destination: &inputSeed,
},
cli.IntFlag{ cli.IntFlag{
Name: "filesize", Name: "filesize",
Value: 1024, Value: 1024,

View File

@ -39,6 +39,11 @@ import (
) )
func uploadAndSyncCmd(ctx *cli.Context, tuid string) error { func uploadAndSyncCmd(ctx *cli.Context, tuid string) error {
// use input seed if it has been set
if inputSeed != 0 {
seed = inputSeed
}
randomBytes := testutil.RandomBytes(seed, filesize*1000) randomBytes := testutil.RandomBytes(seed, filesize*1000)
errc := make(chan error) errc := make(chan error)
@ -47,37 +52,28 @@ func uploadAndSyncCmd(ctx *cli.Context, tuid string) error {
errc <- uploadAndSync(ctx, randomBytes, tuid) errc <- uploadAndSync(ctx, randomBytes, tuid)
}() }()
var err error
select { select {
case err := <-errc: case err = <-errc:
if err != nil { if err != nil {
metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1) metrics.GetOrRegisterCounter(fmt.Sprintf("%s.fail", commandName), nil).Inc(1)
} }
return err
case <-time.After(time.Duration(timeout) * time.Second): case <-time.After(time.Duration(timeout) * time.Second):
metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1) metrics.GetOrRegisterCounter(fmt.Sprintf("%s.timeout", commandName), nil).Inc(1)
e := fmt.Errorf("timeout after %v sec", timeout) err = fmt.Errorf("timeout after %v sec", timeout)
// trigger debug functionality on randomBytes
err := trackChunks(randomBytes[:])
if err != nil {
e = fmt.Errorf("%v; triggerChunkDebug failed: %v", e, err)
}
return e
} }
// trigger debug functionality on randomBytes even on successful runs // trigger debug functionality on randomBytes
err := trackChunks(randomBytes[:]) e := trackChunks(randomBytes[:])
if err != nil { if e != nil {
log.Error(err.Error()) log.Error(e.Error())
} }
return nil return err
} }
func trackChunks(testData []byte) error { func trackChunks(testData []byte) error {
log.Warn("Test timed out, running chunk debug sequence")
addrs, err := getAllRefs(testData) addrs, err := getAllRefs(testData)
if err != nil { if err != nil {
return err return err
@ -94,14 +90,14 @@ func trackChunks(testData []byte) error {
rpcClient, err := rpc.Dial(httpHost) rpcClient, err := rpc.Dial(httpHost)
if err != nil { if err != nil {
log.Error("Error dialing host", "err", err) log.Error("error dialing host", "err", err, "host", httpHost)
continue continue
} }
var hasInfo []api.HasInfo var hasInfo []api.HasInfo
err = rpcClient.Call(&hasInfo, "bzz_has", addrs) err = rpcClient.Call(&hasInfo, "bzz_has", addrs)
if err != nil { if err != nil {
log.Error("Error calling host", "err", err) log.Error("error calling rpc client", "err", err, "host", httpHost)
continue continue
} }
@ -125,7 +121,6 @@ func trackChunks(testData []byte) error {
} }
func getAllRefs(testData []byte) (storage.AddressCollection, error) { func getAllRefs(testData []byte) (storage.AddressCollection, error) {
log.Trace("Getting all references for given root hash")
datadir, err := ioutil.TempDir("", "chunk-debug") datadir, err := ioutil.TempDir("", "chunk-debug")
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to create temp dir: %v", err) return nil, fmt.Errorf("unable to create temp dir: %v", err)

View File

@ -91,6 +91,7 @@ func (r *reporter) makeClient() (err error) {
URL: r.url, URL: r.url,
Username: r.username, Username: r.username,
Password: r.password, Password: r.password,
Timeout: 10 * time.Second,
}) })
return return

View File

@ -204,24 +204,24 @@ func (f *Fetcher) run(peers *sync.Map) {
// incoming request // incoming request
case hopCount = <-f.requestC: case hopCount = <-f.requestC:
log.Trace("new request", "request addr", f.addr)
// 2) chunk is requested, set requested flag // 2) chunk is requested, set requested flag
// launch a request iff none been launched yet // launch a request iff none been launched yet
doRequest = !requested doRequest = !requested
log.Trace("new request", "request addr", f.addr, "doRequest", doRequest)
requested = true requested = true
// peer we requested from is gone. fall back to another // peer we requested from is gone. fall back to another
// and remove the peer from the peers map // and remove the peer from the peers map
case id := <-gone: case id := <-gone:
log.Trace("peer gone", "peer id", id.String(), "request addr", f.addr)
peers.Delete(id.String()) peers.Delete(id.String())
doRequest = requested doRequest = requested
log.Trace("peer gone", "peer id", id.String(), "request addr", f.addr, "doRequest", doRequest)
// search timeout: too much time passed since the last request, // search timeout: too much time passed since the last request,
// extend the search to a new peer if we can find one // extend the search to a new peer if we can find one
case <-waitC: case <-waitC:
log.Trace("search timed out: requesting", "request addr", f.addr)
doRequest = requested doRequest = requested
log.Trace("search timed out: requesting", "request addr", f.addr, "doRequest", doRequest)
// all Fetcher context closed, can quit // all Fetcher context closed, can quit
case <-f.ctx.Done(): case <-f.ctx.Done():
@ -288,6 +288,7 @@ func (f *Fetcher) doRequest(gone chan *enode.ID, peersToSkip *sync.Map, sources
for i = 0; i < len(sources); i++ { for i = 0; i < len(sources); i++ {
req.Source = sources[i] req.Source = sources[i]
var err error var err error
log.Trace("fetcher.doRequest", "request addr", f.addr, "peer", req.Source.String())
sourceID, quit, err = f.protoRequestFunc(f.ctx, req) sourceID, quit, err = f.protoRequestFunc(f.ctx, req)
if err == nil { if err == nil {
// remove the peer from known sources // remove the peer from known sources

View File

@ -28,8 +28,9 @@ package priorityqueue
import ( import (
"context" "context"
"errors" "errors"
"time"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics"
) )
var ( var (
@ -69,13 +70,16 @@ READ:
case <-ctx.Done(): case <-ctx.Done():
return return
case x := <-q: case x := <-q:
log.Trace("priority.queue f(x)", "p", p, "len(Queues[p])", len(pq.Queues[p])) val := x.(struct {
f(x) v interface{}
t time.Time
})
f(val.v)
metrics.GetOrRegisterResettingTimer("pq.run", nil).UpdateSince(val.t)
p = top p = top
default: default:
if p > 0 { if p > 0 {
p-- p--
log.Trace("priority.queue p > 0", "p", p)
continue READ continue READ
} }
p = top p = top
@ -83,7 +87,6 @@ READ:
case <-ctx.Done(): case <-ctx.Done():
return return
case <-pq.wakeup: case <-pq.wakeup:
log.Trace("priority.queue wakeup", "p", p)
} }
} }
} }
@ -95,9 +98,15 @@ func (pq *PriorityQueue) Push(x interface{}, p int) error {
if p < 0 || p >= len(pq.Queues) { if p < 0 || p >= len(pq.Queues) {
return errBadPriority return errBadPriority
} }
log.Trace("priority.queue push", "p", p, "len(Queues[p])", len(pq.Queues[p])) val := struct {
v interface{}
t time.Time
}{
x,
time.Now(),
}
select { select {
case pq.Queues[p] <- x: case pq.Queues[p] <- val:
default: default:
return ErrContention return ErrContention
} }

View File

@ -185,6 +185,7 @@ func (d *Delivery) handleRetrieveRequestMsg(ctx context.Context, sp *Peer, req *
if err != nil { if err != nil {
log.Warn("ERROR in handleRetrieveRequestMsg", "err", err) log.Warn("ERROR in handleRetrieveRequestMsg", "err", err)
} }
osp.LogFields(olog.Bool("delivered", true))
return return
} }
osp.LogFields(olog.Bool("skipCheck", false)) osp.LogFields(olog.Bool("skipCheck", false))
@ -216,6 +217,10 @@ type ChunkDeliveryMsgSyncing ChunkDeliveryMsg
// chunk delivery msg is response to retrieverequest msg // chunk delivery msg is response to retrieverequest msg
func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error { func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *ChunkDeliveryMsg) error {
var osp opentracing.Span
ctx, osp = spancontext.StartSpan(
ctx,
"handle.chunk.delivery")
processReceivedChunksCount.Inc(1) processReceivedChunksCount.Inc(1)
@ -223,13 +228,18 @@ func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *Ch
spanId := fmt.Sprintf("stream.send.request.%v.%v", sp.ID(), req.Addr) spanId := fmt.Sprintf("stream.send.request.%v.%v", sp.ID(), req.Addr)
span := tracing.ShiftSpanByKey(spanId) span := tracing.ShiftSpanByKey(spanId)
log.Trace("handle.chunk.delivery", "ref", req.Addr, "from peer", sp.ID())
go func() { go func() {
defer osp.Finish()
if span != nil { if span != nil {
span.LogFields(olog.String("finish", "from handleChunkDeliveryMsg")) span.LogFields(olog.String("finish", "from handleChunkDeliveryMsg"))
defer span.Finish() defer span.Finish()
} }
req.peer = sp req.peer = sp
log.Trace("handle.chunk.delivery", "put", req.Addr)
err := d.chunkStore.Put(ctx, storage.NewChunk(req.Addr, req.SData)) err := d.chunkStore.Put(ctx, storage.NewChunk(req.Addr, req.SData))
if err != nil { if err != nil {
if err == storage.ErrChunkInvalid { if err == storage.ErrChunkInvalid {
@ -239,6 +249,7 @@ func (d *Delivery) handleChunkDeliveryMsg(ctx context.Context, sp *Peer, req *Ch
req.peer.Drop(err) req.peer.Drop(err)
} }
} }
log.Trace("handle.chunk.delivery", "done put", req.Addr, "err", err)
}() }()
return nil return nil
} }
@ -284,6 +295,7 @@ func (d *Delivery) RequestFromPeers(ctx context.Context, req *network.Request) (
// this span will finish only when delivery is handled (or times out) // this span will finish only when delivery is handled (or times out)
ctx = context.WithValue(ctx, tracing.StoreLabelId, "stream.send.request") ctx = context.WithValue(ctx, tracing.StoreLabelId, "stream.send.request")
ctx = context.WithValue(ctx, tracing.StoreLabelMeta, fmt.Sprintf("%v.%v", sp.ID(), req.Addr)) ctx = context.WithValue(ctx, tracing.StoreLabelMeta, fmt.Sprintf("%v.%v", sp.ID(), req.Addr))
log.Trace("request.from.peers", "peer", sp.ID(), "ref", req.Addr)
err := sp.SendPriority(ctx, &RetrieveRequestMsg{ err := sp.SendPriority(ctx, &RetrieveRequestMsg{
Addr: req.Addr, Addr: req.Addr,
SkipCheck: req.SkipCheck, SkipCheck: req.SkipCheck,

View File

@ -910,7 +910,7 @@ func (r *Registry) APIs() []rpc.API {
Namespace: "stream", Namespace: "stream",
Version: "3.0", Version: "3.0",
Service: r.api, Service: r.api,
Public: true, Public: false,
}, },
} }
} }

View File

@ -536,7 +536,6 @@ func (r *LazyChunkReader) join(ctx context.Context, b []byte, off int64, eoff in
chunkData, err := r.getter.Get(ctx, Reference(childAddress)) chunkData, err := r.getter.Get(ctx, Reference(childAddress))
if err != nil { if err != nil {
metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime) metrics.GetOrRegisterResettingTimer("lcr.getter.get.err", nil).UpdateSince(startTime)
log.Debug("lazychunkreader.join", "key", fmt.Sprintf("%x", childAddress), "err", err)
select { select {
case errC <- fmt.Errorf("chunk %v-%v not found; key: %s", off, off+treeSize, fmt.Sprintf("%x", childAddress)): case errC <- fmt.Errorf("chunk %v-%v not found; key: %s", off, off+treeSize, fmt.Sprintf("%x", childAddress)):
case <-quitC: case <-quitC:
@ -561,12 +560,12 @@ func (r *LazyChunkReader) join(ctx context.Context, b []byte, off int64, eoff in
// Read keeps a cursor so cannot be called simulateously, see ReadAt // Read keeps a cursor so cannot be called simulateously, see ReadAt
func (r *LazyChunkReader) Read(b []byte) (read int, err error) { func (r *LazyChunkReader) Read(b []byte) (read int, err error) {
log.Debug("lazychunkreader.read", "key", r.addr) log.Trace("lazychunkreader.read", "key", r.addr)
metrics.GetOrRegisterCounter("lazychunkreader.read", nil).Inc(1) metrics.GetOrRegisterCounter("lazychunkreader.read", nil).Inc(1)
read, err = r.ReadAt(b, r.off) read, err = r.ReadAt(b, r.off)
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
log.Debug("lazychunkreader.readat", "read", read, "err", err) log.Trace("lazychunkreader.readat", "read", read, "err", err)
metrics.GetOrRegisterCounter("lazychunkreader.read.err", nil).Inc(1) metrics.GetOrRegisterCounter("lazychunkreader.read.err", nil).Inc(1)
} }

View File

@ -87,7 +87,9 @@ func (n *NetStore) Put(ctx context.Context, ch Chunk) error {
// if chunk is now put in the store, check if there was an active fetcher and call deliver on it // if chunk is now put in the store, check if there was an active fetcher and call deliver on it
// (this delivers the chunk to requestors via the fetcher) // (this delivers the chunk to requestors via the fetcher)
log.Trace("n.getFetcher", "ref", ch.Address())
if f := n.getFetcher(ch.Address()); f != nil { if f := n.getFetcher(ch.Address()); f != nil {
log.Trace("n.getFetcher deliver", "ref", ch.Address())
f.deliver(ctx, ch) f.deliver(ctx, ch)
} }
return nil return nil
@ -341,5 +343,6 @@ func (f *fetcher) deliver(ctx context.Context, ch Chunk) {
f.chunk = ch f.chunk = ch
// closing the deliveredC channel will terminate ongoing requests // closing the deliveredC channel will terminate ongoing requests
close(f.deliveredC) close(f.deliveredC)
log.Trace("n.getFetcher close deliveredC", "ref", ch.Address())
}) })
} }

View File

@ -522,6 +522,8 @@ func (s *Swarm) APIs() []rpc.API {
apis = append(apis, s.bzz.APIs()...) apis = append(apis, s.bzz.APIs()...)
apis = append(apis, s.streamer.APIs()...)
if s.ps != nil { if s.ps != nil {
apis = append(apis, s.ps.APIs()...) apis = append(apis, s.ps.APIs()...)
} }

View File

@ -10,5 +10,5 @@ Changes by Version
1.0.0 (2016-09-26) 1.0.0 (2016-09-26)
------------------- -------------------
- This release implements OpenTracing Specification 1.0 (http://opentracing.io/spec) - This release implements OpenTracing Specification 1.0 (https://opentracing.io/spec)

View File

@ -1,26 +1,15 @@
PACKAGES := . ./mocktracer/... ./ext/...
.DEFAULT_GOAL := test-and-lint .DEFAULT_GOAL := test-and-lint
.PHONE: test-and-lint .PHONY: test-and-lint
test-and-lint: test lint test-and-lint: test lint
.PHONY: test .PHONY: test
test: test:
go test -v -cover -race ./... go test -v -cover -race ./...
.PHONY: cover
cover: cover:
@rm -rf cover-all.out go test -v -coverprofile=coverage.txt -covermode=atomic -race ./...
$(foreach pkg, $(PACKAGES), $(MAKE) cover-pkg PKG=$(pkg) || true;)
@grep mode: cover.out > coverage.out
@cat cover-all.out >> coverage.out
go tool cover -html=coverage.out -o cover.html
@rm -rf cover.out cover-all.out coverage.out
cover-pkg:
go test -coverprofile cover.out $(PKG)
@grep -v mode: cover.out >> cover-all.out
.PHONY: lint .PHONY: lint
lint: lint:
@ -29,4 +18,3 @@ lint:
@# Run again with magic to exit non-zero if golint outputs anything. @# Run again with magic to exit non-zero if golint outputs anything.
@! (golint ./... | read dummy) @! (golint ./... | read dummy)
go vet ./... go vet ./...

View File

@ -8,8 +8,8 @@ This package is a Go platform API for OpenTracing.
## Required Reading ## Required Reading
In order to understand the Go platform API, one must first be familiar with the In order to understand the Go platform API, one must first be familiar with the
[OpenTracing project](http://opentracing.io) and [OpenTracing project](https://opentracing.io) and
[terminology](http://opentracing.io/documentation/pages/spec.html) more specifically. [terminology](https://opentracing.io/specification/) more specifically.
## API overview for those adding instrumentation ## API overview for those adding instrumentation

View File

@ -1,7 +1,12 @@
package opentracing package opentracing
type registeredTracer struct {
tracer Tracer
isRegistered bool
}
var ( var (
globalTracer Tracer = NoopTracer{} globalTracer = registeredTracer{NoopTracer{}, false}
) )
// SetGlobalTracer sets the [singleton] opentracing.Tracer returned by // SetGlobalTracer sets the [singleton] opentracing.Tracer returned by
@ -11,22 +16,27 @@ var (
// Prior to calling `SetGlobalTracer`, any Spans started via the `StartSpan` // Prior to calling `SetGlobalTracer`, any Spans started via the `StartSpan`
// (etc) globals are noops. // (etc) globals are noops.
func SetGlobalTracer(tracer Tracer) { func SetGlobalTracer(tracer Tracer) {
globalTracer = tracer globalTracer = registeredTracer{tracer, true}
} }
// GlobalTracer returns the global singleton `Tracer` implementation. // GlobalTracer returns the global singleton `Tracer` implementation.
// Before `SetGlobalTracer()` is called, the `GlobalTracer()` is a noop // Before `SetGlobalTracer()` is called, the `GlobalTracer()` is a noop
// implementation that drops all data handed to it. // implementation that drops all data handed to it.
func GlobalTracer() Tracer { func GlobalTracer() Tracer {
return globalTracer return globalTracer.tracer
} }
// StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`. // StartSpan defers to `Tracer.StartSpan`. See `GlobalTracer()`.
func StartSpan(operationName string, opts ...StartSpanOption) Span { func StartSpan(operationName string, opts ...StartSpanOption) Span {
return globalTracer.StartSpan(operationName, opts...) return globalTracer.tracer.StartSpan(operationName, opts...)
} }
// InitGlobalTracer is deprecated. Please use SetGlobalTracer. // InitGlobalTracer is deprecated. Please use SetGlobalTracer.
func InitGlobalTracer(tracer Tracer) { func InitGlobalTracer(tracer Tracer) {
SetGlobalTracer(tracer) SetGlobalTracer(tracer)
} }
// IsGlobalTracerRegistered returns a `bool` to indicate if a tracer has been globally registered
func IsGlobalTracerRegistered() bool {
return globalTracer.isRegistered
}

View File

@ -160,7 +160,7 @@ type HTTPHeadersCarrier http.Header
// Set conforms to the TextMapWriter interface. // Set conforms to the TextMapWriter interface.
func (c HTTPHeadersCarrier) Set(key, val string) { func (c HTTPHeadersCarrier) Set(key, val string) {
h := http.Header(c) h := http.Header(c)
h.Add(key, val) h.Set(key, val)
} }
// ForeachKey conforms to the TextMapReader interface. // ForeachKey conforms to the TextMapReader interface.

6
vendor/vendor.json vendored
View File

@ -352,10 +352,10 @@
"revisionTime": "2017-01-28T05:05:32Z" "revisionTime": "2017-01-28T05:05:32Z"
}, },
{ {
"checksumSHA1": "wIcN7tZiF441h08RHAm4NV8cYO4=", "checksumSHA1": "a/DHmc9bdsYlZZcwp6i3xhvV7Pk=",
"path": "github.com/opentracing/opentracing-go", "path": "github.com/opentracing/opentracing-go",
"revision": "bd9c3193394760d98b2fa6ebb2291f0cd1d06a7d", "revision": "25a84ff92183e2f8ac018ba1db54f8a07b3c0e04",
"revisionTime": "2018-06-06T20:41:48Z" "revisionTime": "2019-02-18T02:30:34Z"
}, },
{ {
"checksumSHA1": "uhDxBvLEqRAMZKgpTZ8MFuLIIM8=", "checksumSHA1": "uhDxBvLEqRAMZKgpTZ8MFuLIIM8=",