commit 50a8a16a89824975e76df0c5fd2202ea54ef345e from: French Ben date: Thu May 26 01:28:49 2016 UTC Merged master Signed-off-by: French Ben commit - db96364a86ef8eec2d65c3968f638e5d547dd150 commit + 50a8a16a89824975e76df0c5fd2202ea54ef345e blob - /dev/null blob + 16e148eaaa58c36a4f86250a8bc46dc489bbf9f4 (mode 644) --- /dev/null +++ .travis.yml @@ -0,0 +1,11 @@ +language: go + +go: + - 1.6 + +script: + - go test -coverprofile=coverage.txt -covermode=atomic -race + +# CODECOV_TOKEN set in travisCI ENV +after_success: + - bash <(curl -s https://codecov.io/bash) blob - 1bdd1dad5480d8885448ed2e0bff49d513b8679d blob + 6e52d0f1dfbcab2138a49cf9059b9dda62652e67 --- README.md +++ README.md @@ -1,4 +1,5 @@ -# p9p [![GoDoc](https://godoc.org/github.com/docker/go-p9p?status.svg)](https://godoc.org/github.com/docker/go-p9p) [![CircleCI](https://circleci.com/gh/docker/go-p9p.svg?style=shield)](https://circleci.com/gh/docker/go-p9p) [![Go Report Card](https://goreportcard.com/badge/github.com/docker/go-p9p)](https://goreportcard.com/report/github.com/docker/go-p9p) [![Badge Badge](http://badge-server.badge-validate.80d2e13b.svc.dockerapp.io:8088/github.com/docker/go-p9p)](https://github.com/docker/go-p9p) +# p9p [![GoDoc](https://godoc.org/github.com/docker/go-p9p?status.svg)](https://godoc.org/github.com/docker/go-p9p) [![Apache licensed](https://img.shields.io/badge/license-Apache-blue.svg)](https://raw.githubusercontent.com/docker/go-p9p/master/LICENSE) [![CircleCI](https://circleci.com/gh/docker/go-p9p.svg?style=shield)](https://circleci.com/gh/docker/go-p9p) [![TravisCI](https://travis-ci.org/docker/go-p9p.svg?branch=master)](https://travis-ci.org/docker/go-p9p) [![Go Report Card](https://goreportcard.com/badge/github.com/docker/go-p9p)](https://goreportcard.com/report/github.com/docker/go-p9p) +[![Badge Badge](http://badge-server.badge-validate.80d2e13b.svc.dockerapp.io:8088/github.com/docker/go-p9p)](https://github.com/docker/go-p9p) A modern, performant 9P library for Go. blob - e17a6b70611d29e021f7791f0ef72032b4c16c27 blob + e7b76521e84d5fdbe9dc8059e923ee9cbd01f144 --- fcall.go +++ fcall.go @@ -111,11 +111,6 @@ type Fcall struct { } func newFcall(tag Tag, msg Message) *Fcall { - switch msg.Type() { - case Tversion, Rversion: - tag = NOTAG - } - return &Fcall{ Type: msg.Type(), Tag: tag, blob - 8a19e3836a0154314bf8f609fbf91e0ea0a29314 blob + 8a88fa3b9a090adadc8d61c1c98894b0c917e6d6 --- transport.go +++ transport.go @@ -1,6 +1,7 @@ package p9p import ( + "errors" "fmt" "log" "net" @@ -30,7 +31,7 @@ type transport struct { var _ roundTripper = &transport{} -func newTransport(ctx context.Context, ch *channel) roundTripper { +func newTransport(ctx context.Context, ch Channel) roundTripper { t := &transport{ ctx: ctx, ch: ch, @@ -95,6 +96,30 @@ func (t *transport) send(ctx context.Context, msg Mess } } +// allocateTag returns a valid tag given a tag pool map. It receives a hint as +// to where to start the tag search. It returns an error if the allocation is +// not possible. The provided map must not contain NOTAG as a key. +func allocateTag(r *fcallRequest, m map[Tag]*fcallRequest, hint Tag) (Tag, error) { + // The tag pool is depleted if 65535 (0xFFFF) tags are taken. + if len(m) >= 0xFFFF { + return 0, errors.New("tag pool depleted") + } + + // Look for the first tag that doesn't exist in the map and return it. + for i := 0; i < 0xFFFF; i++ { + hint++ + if hint == NOTAG { + hint = 0 + } + + if _, exists := m[hint]; !exists { + return hint, nil + } + } + + return 0, errors.New("allocateTag: unexpected error") +} + // handle takes messages off the wire and wakes up the waiting tag call. func (t *transport) handle() { defer func() { @@ -104,9 +129,9 @@ func (t *transport) handle() { // the following variable block are protected components owned by this thread. var ( responses = make(chan *Fcall) - tags Tag // outstanding provides a map of tags to outstanding requests. outstanding = map[Tag]*fcallRequest{} + selected Tag ) // loop to read messages off of the connection @@ -150,15 +175,17 @@ func (t *transport) handle() { for { select { case req := <-t.requests: - // BUG(stevvooe): This is an awful tag allocation procedure. - // Replace this with something that let's us allocate tags and - // associate data with them, returning to them to a pool when - // complete. Such a system would provide a lot of information - // about outstanding requests. - tags++ - fcall := newFcall(tags, req.message) - outstanding[fcall.Tag] = req + var err error + selected, err = allocateTag(req, outstanding, selected) + if err != nil { + req.err <- err + continue + } + + outstanding[selected] = req + fcall := newFcall(selected, req.message) + // TODO(stevvooe): Consider the case of requests that never // receive a response. We need to remove the fcall context from // the tag map and dealloc the tag. We may also want to send a