// result is PathWalkResult func (f *NsFile) SeqWalk(sq *seq.Sequencer, path ...string) *NsFile { subseq, results := sq.Subsequencer(fmt.Sprintf("seqwalk(%#v)", ([]string)(path))) go func() { var qids PathWalkResult //log.Printf("seqwalk waiting on result chan %p", results) <-results for r := range results { qids = append(qids, r.(seq.WalkResult).Q) } //log.Printf("seqwalk got result eof") //log.Printf("seqwalk %p, %q, error %#v", subseq, subseq.name, subseq.Error()) if err := subseq.Error(); err != nil { subseq.Result(nil, err) return } subseq.Result(qids, nil) }() nfile, err := f.f.FileSys().NewFile() if err != nil { panic("out of files") } //log.Printf("NewFile -> %#v\n", nfile) subseq.Do(f.f, seq.CloneReq{nfile}) for _, name := range path { subseq.Do(nfile, seq.WalkReq{name}) } subseq.Do(nil, nil) return NewNsFile(nfile) }
func (f *NsFile) seqops(sq *seq.Sequencer, ops ...seq.Req) { //log.Printf("file.seqops %#v", ([]seq.Req)(ops)) subseq, results := sq.Subsequencer(fmt.Sprintf("nsfile.seqops(%#v)", ([]seq.Req)(ops))) go func() { result := make(OpResults, len(ops)) i := 0 for result[i] = range results { i++ } //log.Printf("seqops [%#v] got eof, error %#v\n", ([]seq.Req)(ops), subseq.Error()) // TODO(?): replies will be lost on error. subseq.Result(result, subseq.Error()) }() for _, op := range ops { subseq.Do(f.f, op) } subseq.Do(nil, nil) }
func (ns *Ns) seqops(sq *seq.Sequencer, name string, ops ...seq.Req) *NsFile { subseq, results := sq.Subsequencer(fmt.Sprintf("ns.seqops(%#v)", ([]seq.Req)(ops))) go func() { <-results // walk result r := <-results _, ok := <-results if ok { panic("expected closed") } subseq.Result(r, subseq.Error()) }() f, elem := ns.path(name) f = f.SeqWalk(subseq, elem...) f.seqops(subseq, ops...) subseq.Do(nil, nil) return f }
func (ns *Ns) SeqCreate(sq *seq.Sequencer, path string, mode uint8, perm plan9.Perm) *NsFile { f, elem := ns.path(path) if len(elem) == 0 { panic("no path elements") // TODO more sensible error handling } subseq, results := sq.Subsequencer("seqcreate") go func() { <-results // walk result <-results // create result _, ok := <-results if ok { panic("expected closed") } subseq.Result(nil, subseq.Error()) }() elem, name := elem[0:len(elem)-1], elem[len(elem)-1] f = f.SeqWalk(subseq, elem...) f.seqops(subseq, seq.CreateReq{name, perm, mode}) subseq.Do(nil, nil) return f }
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 }
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 (t *traverser) readDir(pseq *seq.Sequencer, fid *g9pc.NsFile, path string) { t.printf("readDir %s", path) sq, results := pseq.Subsequencer("readDir") errc := make(chan error, 1) go func() { <-results // SeqWalk (clone) _, ok := <-results // OpenReq if !ok { errc <- fmt.Errorf("cannot open %q: %#v", path, sq.Error()) return } <-results // NonseqReq <-results // ReadStream errc <- nil _, ok = <-results // eof if ok { panic("expected closed") } errc <- nil }() rfid := fid.SeqWalk(sq) // defer rfid.Close() TODO something better! sq.Do(rfid.File(), seq.OpenReq{g9p.OREAD}) sq.Do(fid.File(), seq.NonseqReq{}) rd := rfid.SeqReadStream(sq, 5, 8192) defer rd.Close() buf, _ := ioutil.ReadAll(rd) t.printf("read %d bytes from %q", len(buf), path) err := <-errc sq.Do(nil, nil) <-errc //we get here but fid still can be part of the sequence. //maybe that means that subsequence has not terminated //correctly. no it doesn't. it means that the overall sequence //has not terminated correctly. // //question: should files opened as part of a subsequence be //ratified by the subsequence finishing? //only if err != nil && len(buf) == 0 { sq.Result(nil, err) t.printf("error on %s: %v\n", path, err) return } d, err := g9p.UnmarshalDirs(buf) if err != nil { t.printf("cannot unpack directory %s: %v\n", path, err) return } sync := make(chan bool) for i, dir := range d { t.printf("%q[%d]: %v", path, i, dir) go t.traverse(fid, path, dir.Name, sync) } for i := 0; i < len(d); i++ { <-sync } t.printf("%s: %d entries", path, len(d)) sq.Result(seq.StringResult("readDir"), nil) }