veyron2/ipc/model.go: Normalize the Glob interfaces

With this change, the Glob__ and GlobChildren__ methods both take a
ServerContext as first argument and return a channel.

All the Glob() implementations are updated to use the AllGlobber
interface from ipc/model.go. This means that the mounttable.Globbable
interface is no longer needed and can now be removed.

The VGlob interface is renamed to Globber.

Change-Id: Idf1cd4663375eb3f1fc3baf7ca7606f59f7ded19
diff --git a/runtimes/google/ipc/benchmarks/service.vdl.go b/runtimes/google/ipc/benchmarks/service.vdl.go
index 117fbe6..117bb1e 100644
--- a/runtimes/google/ipc/benchmarks/service.vdl.go
+++ b/runtimes/google/ipc/benchmarks/service.vdl.go
@@ -254,7 +254,7 @@
 	return s.impl.EchoStream(ctx)
 }
 
-func (s implBenchmarkServerStub) VGlob() *__ipc.GlobState {
+func (s implBenchmarkServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/runtimes/google/ipc/glob.go b/runtimes/google/ipc/glob.go
index 33c897c..c320a82 100644
--- a/runtimes/google/ipc/glob.go
+++ b/runtimes/google/ipc/glob.go
@@ -131,7 +131,7 @@
 	return objectToInvoker(obj).MethodSignature(ctx, ctx.Method())
 }
 
-func (r *reservedMethods) Glob(ctx *ipc.GlobContextStub, pattern string) error {
+func (r *reservedMethods) Glob(ctx ipc.ServerCall, pattern string) error {
 	// Copy the original call to shield ourselves from changes the flowServer makes.
 	glob := globInternal{r.dispNormal, r.dispReserved, ctx.Suffix()}
 	return glob.Glob(copyMutableCall(ctx), pattern)
@@ -232,7 +232,7 @@
 
 		// If the object implements both AllGlobber and ChildrenGlobber, we'll
 		// use AllGlobber.
-		gs := objectToInvoker(obj).VGlob()
+		gs := objectToInvoker(obj).Globber()
 		if gs == nil || (gs.AllGlobber == nil && gs.ChildrenGlobber == nil) {
 			if state.glob.Len() == 0 {
 				call.Send(naming.VDLMountEntry{Name: state.name})
@@ -241,12 +241,22 @@
 		}
 		if gs.AllGlobber != nil {
 			vlog.VI(3).Infof("ipc Glob: %q implements AllGlobber", call.Suffix())
-			childCtx := &ipc.GlobContextStub{&localServerCall{call, state.name}}
-			gs.AllGlobber.Glob(childCtx, state.glob.String())
+			ch, err := gs.AllGlobber.Glob__(call, state.glob.String())
+			if err != nil {
+				vlog.VI(3).Infof("ipc Glob: %q.Glob(%q) failed: %v", call.Suffix(), state.glob, err)
+				continue
+			}
+			if ch == nil {
+				continue
+			}
+			for me := range ch {
+				me.Name = naming.Join(state.name, me.Name)
+				call.Send(me)
+			}
 			continue
 		}
 		vlog.VI(3).Infof("ipc Glob: %q implements ChildrenGlobber", call.Suffix())
-		children, err := gs.ChildrenGlobber.GlobChildren__()
+		children, err := gs.ChildrenGlobber.GlobChildren__(call)
 		// The requested object doesn't exist.
 		if err != nil {
 			continue
@@ -278,24 +288,6 @@
 	return nil
 }
 
-// An ipc.ServerCall that prepends a name to all the names in the streamed
-// MountEntry objects.
-type localServerCall struct {
-	ipc.ServerCall
-	basename string
-}
-
-var _ ipc.ServerCall = (*localServerCall)(nil)
-
-func (c *localServerCall) Send(v interface{}) error {
-	me, ok := v.(naming.VDLMountEntry)
-	if !ok {
-		return verror.BadArgf("unexpected stream type. Got %T, want MountEntry", v)
-	}
-	me.Name = naming.Join(c.basename, me.Name)
-	return c.ServerCall.Send(me)
-}
-
 // copyMutableCall returns a new mutableCall copied from call.  Changes to the
 // original call don't affect the mutable fields in the returned object.
 func copyMutableCall(call ipc.ServerCall) *mutableCall {
diff --git a/runtimes/google/ipc/glob_test.go b/runtimes/google/ipc/glob_test.go
index 79e9859..cf2c0e4 100644
--- a/runtimes/google/ipc/glob_test.go
+++ b/runtimes/google/ipc/glob_test.go
@@ -197,29 +197,33 @@
 	suffix []string
 }
 
-func (o *globObject) Glob(ctx *ipc.GlobContextStub, pattern string) error {
+func (o *globObject) Glob__(ctx ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
 	g, err := glob.Parse(pattern)
 	if err != nil {
-		return err
+		return nil, err
 	}
 	n := o.n.find(o.suffix, false)
 	if n == nil {
-		return nil
+		return nil, nil
 	}
-	o.globLoop(ctx, "", g, n)
-	return nil
+	ch := make(chan naming.VDLMountEntry)
+	go func() {
+		o.globLoop(ch, "", g, n)
+		close(ch)
+	}()
+	return ch, nil
 }
 
-func (o *globObject) globLoop(ctx *ipc.GlobContextStub, name string, g *glob.Glob, n *node) {
+func (o *globObject) globLoop(ch chan<- naming.VDLMountEntry, name string, g *glob.Glob, n *node) {
 	if g.Len() == 0 {
-		ctx.SendStream().Send(naming.VDLMountEntry{Name: name})
+		ch <- naming.VDLMountEntry{Name: name}
 	}
 	if g.Finished() {
 		return
 	}
 	for leaf, child := range n.children {
 		if ok, _, left := g.MatchInitialSegment(leaf); ok {
-			o.globLoop(ctx, naming.Join(name, leaf), left, child)
+			o.globLoop(ch, naming.Join(name, leaf), left, child)
 		}
 	}
 }
@@ -229,7 +233,7 @@
 	suffix []string
 }
 
-func (o *vChildrenObject) GlobChildren__() (<-chan string, error) {
+func (o *vChildrenObject) GlobChildren__(ipc.ServerContext) (<-chan string, error) {
 	n := o.n.find(o.suffix, false)
 	if n == nil {
 		return nil, fmt.Errorf("object does not exist")
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index 4043d3a..272bbfe 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -16,11 +16,9 @@
 	"veyron.io/veyron/veyron2/options"
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/security"
-	"veyron.io/veyron/veyron2/services/mounttable"
 	verror "veyron.io/veyron/veyron2/verror2"
 	"veyron.io/veyron/veyron2/vlog"
 
-	"veyron.io/veyron/veyron/lib/glob"
 	"veyron.io/veyron/veyron/lib/testutil"
 	"veyron.io/veyron/veyron/lib/websocket"
 	_ "veyron.io/veyron/veyron/profiles"
@@ -108,40 +106,20 @@
 	return "Who's there?"
 }
 
-// Glob applies pattern to the following tree:
+// testServer has the following namespace:
 // "" -> {level1} -> {level2}
-// "".Glob("*") returns "level1"
-// "".Glob("...") returns "level1" and "level1/level2"
-// "level1".Glob("*") returns "level2"
-func (t *testServer) Glob(ctx *ipc.GlobContextStub, pattern string) error {
-	g, err := glob.Parse(pattern)
-	if err != nil {
-		return err
+func (t *testServer) GlobChildren__(ipc.ServerContext) (<-chan string, error) {
+	ch := make(chan string, 1)
+	switch t.suffix {
+	case "":
+		ch <- "level1"
+	case "level1":
+		ch <- "level2"
+	default:
+		return nil, nil
 	}
-	tree := []string{"", "level1", "level2"}
-	for i, leaf := range tree {
-		if leaf == t.suffix {
-			return t.globLoop(ctx, "", g, tree[i+1:])
-		}
-	}
-	return nil
-}
-
-func (t *testServer) globLoop(ctx *ipc.GlobContextStub, prefix string, g *glob.Glob, tree []string) error {
-	if g.Len() == 0 {
-		if err := ctx.SendStream().Send(naming.VDLMountEntry{Name: prefix}); err != nil {
-			return err
-		}
-	}
-	if g.Finished() || len(tree) == 0 {
-		return nil
-	}
-	if ok, _, left := g.MatchInitialSegment(tree[0]); ok {
-		if err := t.globLoop(ctx, naming.Join(prefix, tree[0]), left, tree[1:]); err != nil {
-			return err
-		}
-	}
-	return nil
+	close(ch)
+	return ch, nil
 }
 
 type allowEveryoneAuthorizer struct{}
@@ -504,11 +482,11 @@
 	mu        sync.Mutex
 }
 
-func (g *GlobbableServer) Glob(ipc.GlobContext, string) error {
+func (g *GlobbableServer) Glob__(ipc.ServerContext, string) (<-chan naming.VDLMountEntry, error) {
 	g.mu.Lock()
 	defer g.mu.Unlock()
 	g.callCount++
-	return nil
+	return nil, nil
 }
 
 func (g *GlobbableServer) GetAndResetCount() int {
@@ -531,7 +509,7 @@
 
 	globServer := &GlobbableServer{}
 	name := naming.JoinAddressName(mts["mt4/foo/bar"].name, "glob")
-	runningGlobServer := runServer(t, r, ipc.LeafDispatcher(mounttable.GlobbableServer(globServer), nil), name)
+	runningGlobServer := runServer(t, r, ipc.LeafDispatcher(globServer, nil), name)
 	defer runningGlobServer.server.Stop()
 
 	ns := r.Namespace()
diff --git a/security/agent/pingpong/wire.vdl.go b/security/agent/pingpong/wire.vdl.go
index 256a030..690f928 100644
--- a/security/agent/pingpong/wire.vdl.go
+++ b/security/agent/pingpong/wire.vdl.go
@@ -125,7 +125,7 @@
 	return s.impl.Ping(ctx, i0)
 }
 
-func (s implPingPongServerStub) VGlob() *__ipc.GlobState {
+func (s implPingPongServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/security/agent/server/wire.vdl.go b/security/agent/server/wire.vdl.go
index 6f8475b..fa5832b 100644
--- a/security/agent/server/wire.vdl.go
+++ b/security/agent/server/wire.vdl.go
@@ -344,7 +344,7 @@
 	return s.impl.BlessingRootsDebugString(ctx)
 }
 
-func (s implAgentServerStub) VGlob() *__ipc.GlobState {
+func (s implAgentServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/services/identity/identity.vdl.go b/services/identity/identity.vdl.go
index 6dda7f3..0546020 100644
--- a/services/identity/identity.vdl.go
+++ b/services/identity/identity.vdl.go
@@ -156,7 +156,7 @@
 	return s.impl.BlessUsingAccessToken(ctx, i0)
 }
 
-func (s implOAuthBlesserServerStub) VGlob() *__ipc.GlobState {
+func (s implOAuthBlesserServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
@@ -346,7 +346,7 @@
 	return s.impl.Bless(ctx, i0)
 }
 
-func (s implMacaroonBlesserServerStub) VGlob() *__ipc.GlobState {
+func (s implMacaroonBlesserServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/services/mgmt/application/impl/service.go b/services/mgmt/application/impl/service.go
index a42dcab..dd44662 100644
--- a/services/mgmt/application/impl/service.go
+++ b/services/mgmt/application/impl/service.go
@@ -176,7 +176,7 @@
 	return versions, nil
 }
 
-func (i *appRepoService) GlobChildren__() (<-chan string, error) {
+func (i *appRepoService) GlobChildren__(ipc.ServerContext) (<-chan string, error) {
 	vlog.VI(0).Infof("%v.GlobChildren__()", i.suffix)
 	i.store.Lock()
 	defer i.store.Unlock()
diff --git a/services/mgmt/binary/impl/service.go b/services/mgmt/binary/impl/service.go
index a1999c6..e88028d 100644
--- a/services/mgmt/binary/impl/service.go
+++ b/services/mgmt/binary/impl/service.go
@@ -325,7 +325,7 @@
 	return nil
 }
 
-func (i *binaryService) GlobChildren__() (<-chan string, error) {
+func (i *binaryService) GlobChildren__(ipc.ServerContext) (<-chan string, error) {
 	elems := strings.Split(i.suffix, "/")
 	if len(elems) == 1 && elems[0] == "" {
 		elems = nil
diff --git a/services/mgmt/logreader/impl/logfile.go b/services/mgmt/logreader/impl/logfile.go
index 0011fa8..cbf4606 100644
--- a/services/mgmt/logreader/impl/logfile.go
+++ b/services/mgmt/logreader/impl/logfile.go
@@ -112,7 +112,7 @@
 
 // GlobChildren__ returns the list of files in a directory streamed on a
 // channel. The list is empty if the object is a file.
-func (i *logfileService) GlobChildren__() (<-chan string, error) {
+func (i *logfileService) GlobChildren__(ipc.ServerContext) (<-chan string, error) {
 	vlog.VI(1).Infof("%v.GlobChildren__()", i.suffix)
 	dirName, err := translateNameToFilename(i.root, i.suffix)
 	if err != nil {
diff --git a/services/mgmt/node/config.vdl.go b/services/mgmt/node/config.vdl.go
index 212ab5d..42bb189 100644
--- a/services/mgmt/node/config.vdl.go
+++ b/services/mgmt/node/config.vdl.go
@@ -127,7 +127,7 @@
 	return s.impl.Set(ctx, i0, i1)
 }
 
-func (s implConfigServerStub) VGlob() *__ipc.GlobState {
+func (s implConfigServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/services/mgmt/node/impl/app_service.go b/services/mgmt/node/impl/app_service.go
index b5ab1ab..4c4d43e 100644
--- a/services/mgmt/node/impl/app_service.go
+++ b/services/mgmt/node/impl/app_service.go
@@ -1194,7 +1194,7 @@
 	}
 }
 
-func (i *appService) GlobChildren__() (<-chan string, error) {
+func (i *appService) GlobChildren__(ipc.ServerContext) (<-chan string, error) {
 	tree := newTreeNode()
 	switch len(i.suffix) {
 	case 0:
diff --git a/services/mgmt/node/impl/proxy_invoker.go b/services/mgmt/node/impl/proxy_invoker.go
index 1f8cf98..a7ab7c4 100644
--- a/services/mgmt/node/impl/proxy_invoker.go
+++ b/services/mgmt/node/impl/proxy_invoker.go
@@ -5,6 +5,7 @@
 	"io"
 
 	"veyron.io/veyron/veyron2/ipc"
+	"veyron.io/veyron/veyron2/naming"
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/services/security/access"
 )
@@ -184,27 +185,31 @@
 	return res, nil
 }
 
-func (p *proxyInvoker) VGlob() *ipc.GlobState {
+func (p *proxyInvoker) Globber() *ipc.GlobState {
 	return &ipc.GlobState{AllGlobber: p}
 }
 
-func (p *proxyInvoker) Glob(ctx *ipc.GlobContextStub, pattern string) error {
-	argptrs := []interface{}{&pattern}
-	results, err := p.Invoke(ipc.GlobMethod, ctx, argptrs)
-	if err != nil {
-		return err
-	}
-	if len(results) != 1 {
-		return fmt.Errorf("unexpected number of result values. Got %d, want 1.", len(results))
-	}
-	if results[0] == nil {
-		return nil
-	}
-	err, ok := results[0].(error)
-	if !ok {
-		return fmt.Errorf("unexpected result value type. Got %T, want error.", err)
-	}
-	return err
+type call struct {
+	ipc.ServerContext
+	ch chan<- naming.VDLMountEntry
+}
+
+func (c *call) Recv(v interface{}) error {
+	return io.EOF
+}
+
+func (c *call) Send(v interface{}) error {
+	c.ch <- v.(naming.VDLMountEntry)
+	return nil
+}
+
+func (p *proxyInvoker) Glob__(ctx ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
+	ch := make(chan naming.VDLMountEntry)
+	go func() {
+		p.Invoke(ipc.GlobMethod, &call{ctx, ch}, []interface{}{&pattern})
+		close(ch)
+	}()
+	return ch, nil
 }
 
 // numResults returns the number of result values for the given method.
diff --git a/services/mgmt/node/impl/proxy_invoker_test.go b/services/mgmt/node/impl/proxy_invoker_test.go
index b729d10..813e868 100644
--- a/services/mgmt/node/impl/proxy_invoker_test.go
+++ b/services/mgmt/node/impl/proxy_invoker_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"reflect"
-	"sort"
 	"testing"
 
 	"veyron.io/veyron/veyron2/ipc"
@@ -10,8 +9,9 @@
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/security"
 	"veyron.io/veyron/veyron2/services/mgmt/stats"
-	"veyron.io/veyron/veyron2/services/mounttable"
 	"veyron.io/veyron/veyron2/services/security/access"
+
+	"veyron.io/veyron/veyron/lib/testutil"
 )
 
 // TODO(toddw): Add tests of Signature and MethodSignature.
@@ -60,7 +60,10 @@
 	}
 
 	// Call Glob()
-	results := doGlob(t, naming.JoinAddressName(ep2.String(), "system"), "start-time-*")
+	results, err := testutil.GlobName(r.NewContext(), naming.JoinAddressName(ep2.String(), "system"), "start-time-*")
+	if err != nil {
+		t.Fatalf("Glob failed: %v", err)
+	}
 	expected := []string{
 		"start-time-rfc1123",
 		"start-time-unix",
@@ -70,27 +73,6 @@
 	}
 }
 
-func doGlob(t *testing.T, name, pattern string) []string {
-	c := mounttable.GlobbableClient(name)
-	stream, err := c.Glob(rt.R().NewContext(), pattern)
-	if err != nil {
-		t.Fatalf("Glob failed: %v", err)
-	}
-	results := []string{}
-	iterator := stream.RecvStream()
-	for iterator.Advance() {
-		results = append(results, iterator.Value().Name)
-	}
-	if err := iterator.Err(); err != nil {
-		t.Errorf("unexpected stream error: %v", err)
-	}
-	if err := stream.Finish(); err != nil {
-		t.Errorf("Finish failed: %v", err)
-	}
-	sort.Strings(results)
-	return results
-}
-
 type dummy struct{}
 
 func (*dummy) Method(_ ipc.ServerContext) error { return nil }
diff --git a/services/mgmt/repository/repository.vdl.go b/services/mgmt/repository/repository.vdl.go
index 48541ae..e1202c7 100644
--- a/services/mgmt/repository/repository.vdl.go
+++ b/services/mgmt/repository/repository.vdl.go
@@ -202,7 +202,7 @@
 	return s.impl.Remove(ctx, i0)
 }
 
-func (s implApplicationServerStub) VGlob() *__ipc.GlobState {
+func (s implApplicationServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
@@ -509,7 +509,7 @@
 	return s.impl.Remove(ctx)
 }
 
-func (s implProfileServerStub) VGlob() *__ipc.GlobState {
+func (s implProfileServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/services/mgmt/root/root.vdl.go b/services/mgmt/root/root.vdl.go
index 081e7ba..5fdd66c 100644
--- a/services/mgmt/root/root.vdl.go
+++ b/services/mgmt/root/root.vdl.go
@@ -133,7 +133,7 @@
 	return s.impl.Reset(ctx, i0)
 }
 
-func (s implRootServerStub) VGlob() *__ipc.GlobState {
+func (s implRootServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/services/mgmt/stats/impl/stats.go b/services/mgmt/stats/impl/stats.go
index b398ee8..f51b12b 100644
--- a/services/mgmt/stats/impl/stats.go
+++ b/services/mgmt/stats/impl/stats.go
@@ -35,21 +35,22 @@
 	return stats.StatsServer(&statsService{suffix, watchFreq})
 }
 
-// Glob returns the name of all objects that match pattern.
-func (i *statsService) Glob(ctx ipc.GlobContext, pattern string) error {
-	vlog.VI(1).Infof("%v.Glob(%q)", i.suffix, pattern)
+// Glob__ returns the name of all objects that match pattern.
+func (i *statsService) Glob__(ctx ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
+	vlog.VI(1).Infof("%v.Glob__(%q)", i.suffix, pattern)
 
-	it := libstats.Glob(i.suffix, pattern, time.Time{}, false)
-	for it.Advance() {
-		ctx.SendStream().Send(naming.VDLMountEntry{Name: it.Value().Key})
-	}
-	if err := it.Err(); err != nil {
-		if err == libstats.ErrNotFound {
-			return errNotFound
+	ch := make(chan naming.VDLMountEntry)
+	go func() {
+		defer close(ch)
+		it := libstats.Glob(i.suffix, pattern, time.Time{}, false)
+		for it.Advance() {
+			ch <- naming.VDLMountEntry{Name: it.Value().Key}
 		}
-		return errOperationFailed
-	}
-	return nil
+		if err := it.Err(); err != nil {
+			vlog.VI(1).Infof("libstats.Glob(%q, %q) failed: %v", i.suffix, pattern, err)
+		}
+	}()
+	return ch, nil
 }
 
 // WatchGlob returns the name and value of the objects that match the request,
diff --git a/services/mgmt/stats/impl/stats_test.go b/services/mgmt/stats/impl/stats_test.go
index fe502c4..661f6f4 100644
--- a/services/mgmt/stats/impl/stats_test.go
+++ b/services/mgmt/stats/impl/stats_test.go
@@ -6,6 +6,7 @@
 	"testing"
 	"time"
 
+	"veyron.io/veyron/veyron2"
 	"veyron.io/veyron/veyron2/naming"
 	"veyron.io/veyron/veyron2/rt"
 	"veyron.io/veyron/veyron2/security"
@@ -14,6 +15,7 @@
 
 	libstats "veyron.io/veyron/veyron/lib/stats"
 	"veyron.io/veyron/veyron/lib/stats/histogram"
+	"veyron.io/veyron/veyron/lib/testutil"
 	"veyron.io/veyron/veyron/profiles"
 	istats "veyron.io/veyron/veyron/services/mgmt/stats"
 	"veyron.io/veyron/veyron/services/mgmt/stats/impl"
@@ -26,9 +28,9 @@
 	return impl.NewStatsService(suffix, 100*time.Millisecond), nil, nil
 }
 
-func startServer(t *testing.T) (string, func()) {
+func startServer(t *testing.T, runtime veyron2.Runtime) (string, func()) {
 	disp := &statsDispatcher{}
-	server, err := rt.R().NewServer()
+	server, err := runtime.NewServer()
 	if err != nil {
 		t.Fatalf("NewServer failed: %v", err)
 		return "", nil
@@ -46,9 +48,10 @@
 }
 
 func TestStatsImpl(t *testing.T) {
-	rt.Init()
+	runtime, _ := rt.New()
+	defer runtime.Cleanup()
 
-	endpoint, stop := startServer(t)
+	endpoint, stop := startServer(t, runtime)
 	defer stop()
 
 	counter := libstats.NewCounter("testing/foo/bar")
@@ -64,29 +67,14 @@
 		histogram.Add(int64(i))
 	}
 
-	c := stats.StatsClient(naming.JoinAddressName(endpoint, ""))
+	name := naming.JoinAddressName(endpoint, "")
+	c := stats.StatsClient(name)
 
 	// Test Glob()
 	{
-		stream, err := c.Glob(rt.R().NewContext(), "testing/foo/...")
+		results, err := testutil.GlobName(runtime.NewContext(), name, "testing/foo/...")
 		if err != nil {
-			t.Fatalf("c.Glob failed: %v", err)
-		}
-		iterator := stream.RecvStream()
-		results := []string{}
-		for iterator.Advance() {
-			me := iterator.Value()
-			if len(me.Servers) > 0 {
-				t.Errorf("unexpected servers. Got %v, want none", me.Servers)
-			}
-			results = append(results, me.Name)
-		}
-		if err := iterator.Err(); err != nil {
-			t.Errorf("unexpected stream error: %v", err)
-		}
-		err = stream.Finish()
-		if err != nil {
-			t.Errorf("gstream.Finish failed: %v", err)
+			t.Fatalf("testutil.GlobName failed: %v", err)
 		}
 		expected := []string{
 			"testing/foo",
@@ -109,7 +97,7 @@
 	{
 		noRM := types.ResumeMarker{}
 		_ = noRM
-		stream, err := c.WatchGlob(rt.R().NewContext(), types.GlobRequest{Pattern: "testing/foo/bar"})
+		stream, err := c.WatchGlob(runtime.NewContext(), types.GlobRequest{Pattern: "testing/foo/bar"})
 		if err != nil {
 			t.Fatalf("c.WatchGlob failed: %v", err)
 		}
@@ -160,7 +148,7 @@
 	// Test Value()
 	{
 		c := stats.StatsClient(naming.JoinAddressName(endpoint, "testing/foo/bar"))
-		value, err := c.Value(rt.R().NewContext())
+		value, err := c.Value(runtime.NewContext())
 		if err != nil {
 			t.Errorf("unexpected error: %v", err)
 		}
@@ -172,7 +160,7 @@
 	// Test Value() with Histogram
 	{
 		c := stats.StatsClient(naming.JoinAddressName(endpoint, "testing/hist/foo"))
-		value, err := c.Value(rt.R().NewContext())
+		value, err := c.Value(runtime.NewContext())
 		if err != nil {
 			t.Errorf("unexpected error: %v", err)
 		}
diff --git a/services/mounttable/lib/collection_test_interface.vdl.go b/services/mounttable/lib/collection_test_interface.vdl.go
index 55d4de0..40ae1fe 100644
--- a/services/mounttable/lib/collection_test_interface.vdl.go
+++ b/services/mounttable/lib/collection_test_interface.vdl.go
@@ -150,7 +150,7 @@
 	return s.impl.Lookup(ctx)
 }
 
-func (s implCollectionServerStub) VGlob() *__ipc.GlobState {
+func (s implCollectionServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/services/mounttable/lib/mounttable.go b/services/mounttable/lib/mounttable.go
index ed5d57b..4d63067 100644
--- a/services/mounttable/lib/mounttable.go
+++ b/services/mounttable/lib/mounttable.go
@@ -361,7 +361,7 @@
 	name string
 }
 
-func (mt *mountTable) globStep(n *node, name string, pattern *glob.Glob, context ipc.GlobContext) {
+func (mt *mountTable) globStep(n *node, name string, pattern *glob.Glob, context ipc.ServerContext, ch chan<- naming.VDLMountEntry) {
 	vlog.VI(2).Infof("globStep(%s, %s)", name, pattern)
 
 	if mt.acls != nil {
@@ -374,7 +374,6 @@
 		}
 	}
 
-	sender := context.SendStream()
 	// If this is a mount point, we're done.
 	if m := n.mount; m != nil {
 		// Garbage-collect if expired.
@@ -382,11 +381,11 @@
 			n.removeUseless()
 			return
 		}
-		sender.Send(
-			naming.VDLMountEntry{
-				Name: name, Servers: m.servers.copyToSlice(),
-				MT: n.mount.mt,
-			})
+		ch <- naming.VDLMountEntry{
+			Name:    name,
+			Servers: m.servers.copyToSlice(),
+			MT:      n.mount.mt,
+		}
 		return
 	}
 
@@ -396,7 +395,7 @@
 			n.removeUseless()
 			return
 		}
-		sender.Send(naming.VDLMountEntry{Name: name})
+		ch <- naming.VDLMountEntry{Name: name}
 	}
 
 	if pattern.Finished() {
@@ -406,7 +405,7 @@
 	// Recurse through the children.
 	for k, c := range n.children {
 		if ok, _, suffix := pattern.MatchInitialSegment(k); ok {
-			mt.globStep(c, naming.Join(name, k), suffix, context)
+			mt.globStep(c, naming.Join(name, k), suffix, context, ch)
 		}
 	}
 }
@@ -414,36 +413,40 @@
 // Glob finds matches in the namespace.  If we reach a mount point before matching the
 // whole pattern, return that mount point.
 // pattern is a glob pattern as defined by the veyron/lib/glob package.
-func (ms *mountContext) Glob(context ipc.GlobContext, pattern string) error {
+func (ms *mountContext) Glob__(context ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
 	vlog.VI(2).Infof("mt.Glob %v", ms.elems)
 
 	g, err := glob.Parse(pattern)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	mt := ms.mt
 
-	// TODO(caprita): we need to grab a write lock because globStep may
-	// garbage-collect expired servers.  Rework this to avoid this potential
-	// bottleneck.
-	mt.Lock()
-	defer mt.Unlock()
+	ch := make(chan naming.VDLMountEntry)
+	go func() {
+		defer close(ch)
+		// TODO(caprita): we need to grab a write lock because globStep may
+		// garbage-collect expired servers.  Rework this to avoid this potential
+		// bottleneck.
+		mt.Lock()
+		defer mt.Unlock()
 
-	// If the current name is not fully resolvable on this nameserver we
-	// don't need to evaluate the glob expression. Send a partially resolved
-	// name back to the client.
-	n := mt.findNode(ms.cleanedElems, false)
-	if n == nil {
-		ms.linkToLeaf(context)
-		return nil
-	}
+		// If the current name is not fully resolvable on this nameserver we
+		// don't need to evaluate the glob expression. Send a partially resolved
+		// name back to the client.
+		n := mt.findNode(ms.cleanedElems, false)
+		if n == nil {
+			ms.linkToLeaf(ch)
+			return
+		}
 
-	mt.globStep(n, "", g, context)
-	return nil
+		mt.globStep(n, "", g, context, ch)
+	}()
+	return ch, nil
 }
 
-func (ms *mountContext) linkToLeaf(stream ipc.GlobServerStream) {
+func (ms *mountContext) linkToLeaf(ch chan<- naming.VDLMountEntry) {
 	n, elems := ms.mt.walk(ms.mt.root, ms.cleanedElems)
 	if n == nil {
 		return
@@ -452,5 +455,5 @@
 	for i, s := range servers {
 		servers[i].Server = naming.Join(s.Server, strings.Join(elems, "/"))
 	}
-	stream.SendStream().Send(naming.VDLMountEntry{Name: "", Servers: servers})
+	ch <- naming.VDLMountEntry{Name: "", Servers: servers}
 }
diff --git a/services/mounttable/lib/mounttable_test.go b/services/mounttable/lib/mounttable_test.go
index ee79761..c0b8494 100644
--- a/services/mounttable/lib/mounttable_test.go
+++ b/services/mounttable/lib/mounttable_test.go
@@ -275,7 +275,7 @@
 	name := naming.JoinAddressName(ep, suffix)
 	ctx := as.NewContext()
 	client := as.Client()
-	call, err := client.StartCall(ctx, name, "Glob", []interface{}{pattern}, options.NoResolve(true))
+	call, err := client.StartCall(ctx, name, ipc.GlobMethod, []interface{}{pattern}, options.NoResolve(true))
 	if err != nil {
 		boom(t, "Glob.StartCall %s %s: %s", name, pattern, err)
 	}
diff --git a/services/mounttable/lib/neighborhood.go b/services/mounttable/lib/neighborhood.go
index 278b0f4..e307143 100644
--- a/services/mounttable/lib/neighborhood.go
+++ b/services/mounttable/lib/neighborhood.go
@@ -255,35 +255,39 @@
 	return errors.New("this server does not implement Unmount")
 }
 
-// Glob implements Glob
-func (ns *neighborhoodService) Glob(ctx ipc.GlobContext, pattern string) error {
+// Glob__ implements ipc.AllGlobber
+func (ns *neighborhoodService) Glob__(ctx ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
 	g, err := glob.Parse(pattern)
 	if err != nil {
-		return err
+		return nil, err
 	}
 
 	// return all neighbors that match the first element of the pattern.
 	nh := ns.nh
 
-	sender := ctx.SendStream()
 	switch len(ns.elems) {
 	case 0:
-		for k, n := range nh.neighbors() {
-			if ok, _, _ := g.MatchInitialSegment(k); !ok {
-				continue
+		ch := make(chan naming.VDLMountEntry)
+		go func() {
+			defer close(ch)
+			for k, n := range nh.neighbors() {
+				if ok, _, _ := g.MatchInitialSegment(k); !ok {
+					continue
+				}
+				ch <- naming.VDLMountEntry{Name: k, Servers: n, MT: true}
 			}
-			if err := sender.Send(naming.VDLMountEntry{Name: k, Servers: n, MT: true}); err != nil {
-				return err
-			}
-		}
-		return nil
+		}()
+		return ch, nil
 	case 1:
 		neighbor := nh.neighbor(ns.elems[0])
 		if neighbor == nil {
-			return verror.Make(naming.ErrNoSuchName, ctx, ns.elems[0])
+			return nil, verror.Make(naming.ErrNoSuchName, ctx, ns.elems[0])
 		}
-		return sender.Send(naming.VDLMountEntry{Name: "", Servers: neighbor, MT: true})
+		ch := make(chan naming.VDLMountEntry, 1)
+		ch <- naming.VDLMountEntry{Name: "", Servers: neighbor, MT: true}
+		close(ch)
+		return ch, nil
 	default:
-		return verror.Make(naming.ErrNoSuchName, ctx, ns.elems)
+		return nil, verror.Make(naming.ErrNoSuchName, ctx, ns.elems)
 	}
 }
diff --git a/services/mounttable/mounttabled/test.sh b/services/mounttable/mounttabled/test.sh
index 2ebdc7f..76bdd25 100755
--- a/services/mounttable/mounttabled/test.sh
+++ b/services/mounttable/mounttabled/test.sh
@@ -51,8 +51,7 @@
   GOT=$(${MOUNTTABLE_BIN} glob "${EP}" '*' | \
 	  sed -e 's/ \/@.@ws@[^ ]* (TTL .m..s)//' -e 's/TTL [^)]*/TTL XmXXs/' | sort) \
     || shell_test::fail "line ${LINENO}: failed to run mounttable"
-  WANT="[${EP}]
-google /www.google.com:80 (TTL XmXXs)
+  WANT="google /www.google.com:80 (TTL XmXXs)
 myself ${EP} (TTL XmXXs)
 nh ${NHEP} (TTL XmXXs)"
   shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
@@ -60,8 +59,7 @@
   # <neighborhood>.Glob('NHNAME')
   GOT=$("${MOUNTTABLE_BIN}" glob "${NHEP}" "${NHNAME}" | sed 's/TTL [^)]*/TTL XmXXs/' | sort) \
     || shell_test::fail "line ${LINENO}: failed to run mounttable"
-  WANT="[${NHEP}]
-${NHNAME} ${EP} (TTL XmXXs)"
+  WANT="${NHNAME} ${EP} (TTL XmXXs)"
   shell_test::assert_eq "${GOT}" "${WANT}" "${LINENO}"
 
   shell_test::pass
diff --git a/services/security/discharger.vdl.go b/services/security/discharger.vdl.go
index 8fbf3c6..4c914e7d 100644
--- a/services/security/discharger.vdl.go
+++ b/services/security/discharger.vdl.go
@@ -143,7 +143,7 @@
 	return s.impl.Discharge(ctx, i0, i1)
 }
 
-func (s implDischargerServerStub) VGlob() *__ipc.GlobState {
+func (s implDischargerServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }
 
diff --git a/tools/mounttable/impl.go b/tools/mounttable/impl.go
index 6afca98..9116972 100644
--- a/tools/mounttable/impl.go
+++ b/tools/mounttable/impl.go
@@ -1,32 +1,16 @@
 package main
 
 import (
+	"errors"
 	"fmt"
 	"time"
 
 	"veyron.io/lib/cmdline"
-	"veyron.io/veyron/veyron2/context"
+	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/naming"
 	"veyron.io/veyron/veyron2/options"
-	"veyron.io/veyron/veyron2/services/mounttable"
 )
 
-func bindMT(ctx context.T, name string) (mounttable.MountTableClientMethods, error) {
-	e, err := runtime.Namespace().ResolveToMountTableX(ctx, name)
-	if err != nil {
-		return nil, err
-	}
-	if len(e.Servers) == 0 {
-		return nil, fmt.Errorf("Failed to find any mount tables at %q", name)
-	}
-	var servers []string
-	for _, s := range e.Servers {
-		servers = append(servers, naming.JoinAddressName(s.Server, e.Name))
-	}
-	fmt.Println(servers)
-	return mounttable.MountTableClient(servers[0]), nil
-}
-
 var cmdGlob = &cmdline.Command{
 	Run:      runGlob,
 	Name:     "glob",
@@ -42,40 +26,37 @@
 
 func runGlob(cmd *cmdline.Command, args []string) error {
 	if len(args) == 1 {
-		args = append([]string{""}, args...)
+		roots := runtime.Namespace().Roots()
+		if len(roots) == 0 {
+			return errors.New("no namespace root")
+		}
+		args = append([]string{roots[0]}, args...)
 	}
 	if expected, got := 2, len(args); expected != got {
 		return cmd.UsageErrorf("glob: incorrect number of arguments, expected %d, got %d", expected, got)
 	}
 	ctx, cancel := runtime.NewContext().WithTimeout(time.Minute)
 	defer cancel()
-	c, err := bindMT(ctx, args[0])
-	if err != nil {
-		return fmt.Errorf("bind error: %v", err)
-	}
-	stream, err := c.Glob(ctx, args[1])
+	name, pattern := args[0], args[1]
+	call, err := runtime.Client().StartCall(ctx, name, ipc.GlobMethod, []interface{}{pattern}, options.NoResolve(true))
 	if err != nil {
 		return err
 	}
-	rStream := stream.RecvStream()
-	for rStream.Advance() {
-		buf := rStream.Value()
-
-		fmt.Fprint(cmd.Stdout(), buf.Name)
-		for _, s := range buf.Servers {
+	for {
+		var me naming.VDLMountEntry
+		if err := call.Recv(&me); err != nil {
+			break
+		}
+		fmt.Fprint(cmd.Stdout(), me.Name)
+		for _, s := range me.Servers {
 			fmt.Fprintf(cmd.Stdout(), " %s (TTL %s)", s.Server, time.Duration(s.TTL)*time.Second)
 		}
 		fmt.Fprintln(cmd.Stdout())
 	}
-
-	if err := rStream.Err(); err != nil {
-		return fmt.Errorf("advance error: %v", err)
+	if ferr := call.Finish(&err); ferr != nil {
+		err = ferr
 	}
-	err = stream.Finish()
-	if err != nil {
-		return fmt.Errorf("finish error: %v", err)
-	}
-	return nil
+	return err
 }
 
 var cmdMount = &cmdline.Command{
@@ -123,7 +104,10 @@
 		return err
 	}
 	if ierr := call.Finish(&err); ierr != nil {
-		return ierr
+		err = ierr
+	}
+	if err != nil {
+		return err
 	}
 
 	fmt.Fprintln(cmd.Stdout(), "Name mounted successfully.")
@@ -153,11 +137,14 @@
 		return err
 	}
 	if ierr := call.Finish(&err); ierr != nil {
-		return ierr
+		err = ierr
+	}
+	if err != nil {
+		return err
 	}
 
 	fmt.Fprintln(cmd.Stdout(), "Name unmounted successfully.")
-	return nil
+	return err
 }
 
 var cmdResolveStep = &cmdline.Command{
@@ -183,7 +170,7 @@
 	}
 	var entry naming.VDLMountEntry
 	if ierr := call.Finish(&entry, &err); ierr != nil {
-		return ierr
+		err = ierr
 	}
 	if err != nil {
 		return err
diff --git a/tools/mounttable/impl_test.go b/tools/mounttable/impl_test.go
index 9c59eb6..ae9fa48 100644
--- a/tools/mounttable/impl_test.go
+++ b/tools/mounttable/impl_test.go
@@ -20,12 +20,13 @@
 	suffix string
 }
 
-func (s *server) Glob(ctx ipc.GlobContext, pattern string) error {
+func (s *server) Glob__(ctx ipc.ServerContext, pattern string) (<-chan naming.VDLMountEntry, error) {
 	vlog.VI(2).Infof("Glob() was called. suffix=%v pattern=%q", s.suffix, pattern)
-	sender := ctx.SendStream()
-	sender.Send(naming.VDLMountEntry{"name1", []naming.VDLMountedServer{{"server1", 123}}, false})
-	sender.Send(naming.VDLMountEntry{"name2", []naming.VDLMountedServer{{"server2", 456}, {"server3", 789}}, false})
-	return nil
+	ch := make(chan naming.VDLMountEntry, 2)
+	ch <- naming.VDLMountEntry{"name1", []naming.VDLMountedServer{{"server1", 123}}, false}
+	ch <- naming.VDLMountEntry{"name2", []naming.VDLMountedServer{{"server2", 456}, {"server3", 789}}, false}
+	close(ch)
+	return ch, nil
 }
 
 func (s *server) Mount(_ ipc.ServerContext, server string, ttl uint32, flags naming.MountFlag) error {
diff --git a/tools/vrpc/test_base/test_base.vdl.go b/tools/vrpc/test_base/test_base.vdl.go
index a411da3..3a8e3ab 100644
--- a/tools/vrpc/test_base/test_base.vdl.go
+++ b/tools/vrpc/test_base/test_base.vdl.go
@@ -565,7 +565,7 @@
 	return s.impl.StreamingOutput(ctx, i0, i1)
 }
 
-func (s implTypeTesterServerStub) VGlob() *__ipc.GlobState {
+func (s implTypeTesterServerStub) Globber() *__ipc.GlobState {
 	return s.gs
 }