func (t *traverser) readFile(sq *seq.Sequencer, fid *g9pc.NsFile, path string) { t.printf("readFile %s", path) sq, results := sq.Subsequencer("readFile") go func() { _, ok := <-results // open if !ok { t.printf("cannot open %s: %v", path, sq.Error()) return } <-results // stream _, ok = <-results if ok { panic("expected closed") } sq.Result(seq.StringResult("readFile"), sq.Error()) }() sq.Do(fid.File(), seq.OpenReq{g9p.OREAD}) rd := fid.SeqReadStream(sq, 20, 8192) tot, _ := io.Copy(nullWriter{}, rd) t.printf("%10d %s", tot, path) sq.Do(nil, nil) }
func (nsf *NsFile) SeqReadStream(sq *seq.Sequencer, nreqs, iounit int) io.ReadCloser { cr := &streamReader{ c: make(chan readResult, 1), reply: make(chan bool), } sq, results := sq.Subsequencer("stream reader") buf := make([]byte, nreqs*iounit) bufs := make(chan []byte, nreqs) for i := 0; i < nreqs; i++ { bufs <- buf[0:iounit] buf = buf[iounit:] } buf = nil var q safeQueue done := make(chan bool) // Stream requests. go func() { f := nsf.File() offset := int64(0) for { b, ok := <-bufs if !ok { break } q.Put(b) log.Printf("stream doer: read %v", offset) sq.Do(f, seq.ReadReq{b, offset}) offset += int64(len(b)) } log.Printf("stream doer: do(nil, nil)") sq.Do(nil, nil) done <- true }() // Stream replies on demand from the streamReader. go func() { readerClosed := false for r := range results { log.Printf("stream: got result %#v (chan %p)\n", r, results) b := q.Get().([]byte) cr.c <- readResult{b[0:r.(seq.ReadResult).Count], nil} if !<-cr.reply { readerClosed = true break } bufs <- b } log.Printf("stream: closed") // Stop as many requests as possible from being sent. // If we implemented flush, we would flush the request now. loop: for { select { case <-bufs: default: break loop } } close(bufs) // Absorb and ignore any extra replies. for r := range results { log.Printf("stream: aborbing extra: %#v\n", r) } <-done err := sq.Error() if !readerClosed { log.Printf("stream: sending error to reader") if err == nil { err = io.EOF } cr.c <- readResult{nil, err} } log.Printf("stream: yielding result, err %#v\n", err) sq.Result(seq.StringResult("SeqReadStream"), err) }() return cr }