func (conn *vtgateConn) GetSrvKeyspace(ctx context.Context, keyspace string) (*topo.SrvKeyspace, error) { request := &pb.GetSrvKeyspaceRequest{ Keyspace: keyspace, } response := &pb.GetSrvKeyspaceResponse{} if err := conn.rpcConn.Call(ctx, "VTGateP3.GetSrvKeyspace", request, response); err != nil { return nil, err } return topo.ProtoToSrvKeyspace(response.SrvKeyspace), nil }
func (conn *vtgateConn) GetSrvKeyspace(ctx context.Context, keyspace string) (*topo.SrvKeyspace, error) { request := &pb.GetSrvKeyspaceRequest{ Keyspace: keyspace, } response, err := conn.c.GetSrvKeyspace(ctx, request) if err != nil { return nil, vterrors.FromGRPCError(err) } return topo.ProtoToSrvKeyspace(response.SrvKeyspace), nil }
// GetSrvKeyspace is part of the topo.Server interface func (zkts *Server) GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*topo.SrvKeyspace, error) { path := zkPathForVtKeyspace(cell, keyspace) data, _, err := zkts.zconn.Get(path) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { err = topo.ErrNoNode } return nil, err } srvKeyspace := &pb.SrvKeyspace{} if len(data) > 0 { if err := json.Unmarshal([]byte(data), srvKeyspace); err != nil { return nil, fmt.Errorf("SrvKeyspace unmarshal failed: %v %v", data, err) } } return topo.ProtoToSrvKeyspace(srvKeyspace), nil }
// GetSrvKeyspace implements topo.Server. func (s *Server) GetSrvKeyspace(ctx context.Context, cellName, keyspace string) (*topo.SrvKeyspace, error) { cell, err := s.getCell(cellName) if err != nil { return nil, err } resp, err := cell.Get(srvKeyspaceFilePath(keyspace), false /* sort */, false /* recursive */) if err != nil { return nil, convertError(err) } if resp.Node == nil { return nil, ErrBadResponse } value := &pb.SrvKeyspace{} if err := json.Unmarshal([]byte(resp.Node.Value), value); err != nil { return nil, fmt.Errorf("bad serving keyspace data (%v): %q", err, resp.Node.Value) } return topo.ProtoToSrvKeyspace(value), nil }
// WatchSrvKeyspace is part of the topo.Server interface func (s *Server) WatchSrvKeyspace(ctx context.Context, cellName, keyspace string) (<-chan *topo.SrvKeyspace, chan<- struct{}, error) { cell, err := s.getCell(cellName) if err != nil { return nil, nil, fmt.Errorf("WatchSrvKeyspace cannot get cell: %v", err) } filePath := srvKeyspaceFilePath(keyspace) notifications := make(chan *topo.SrvKeyspace, 10) stopWatching := make(chan struct{}) // The watch go routine will stop if the 'stop' channel is closed. // Otherwise it will try to watch everything in a loop, and send events // to the 'watch' channel. watch := make(chan *etcd.Response) stop := make(chan bool) go func() { var srvKeyspace *topo.SrvKeyspace var modifiedVersion int64 resp, err := cell.Get(filePath, false /* sort */, false /* recursive */) if err != nil || resp.Node == nil { // node doesn't exist } else { if resp.Node.Value != "" { sk := &pb.SrvKeyspace{} if err := json.Unmarshal([]byte(resp.Node.Value), sk); err != nil { log.Warningf("bad SrvKeyspace data (%v): %q", err, resp.Node.Value) } else { srvKeyspace = topo.ProtoToSrvKeyspace(sk) modifiedVersion = int64(resp.Node.ModifiedIndex) } } } // re-check for stop here to be safe, in case the // getEndPoints took a long time select { case <-stop: return case notifications <- srvKeyspace: } for { if _, err := cell.Client.Watch(filePath, uint64(modifiedVersion+1), false /* recursive */, watch, stop); err != nil { log.Errorf("Watch on %v failed, waiting for %v to retry: %v", filePath, WatchSleepDuration, err) timer := time.After(WatchSleepDuration) select { case <-stop: return case <-timer: } } } }() // This go routine is the main event handling routine: // - it will stop if stopWatching is closed. // - if it receives a notification from the watch, it will forward it // to the notifications channel. go func() { for { select { case resp := <-watch: var srvKeyspace *topo.SrvKeyspace if resp.Node != nil && resp.Node.Value != "" { sk := &pb.SrvKeyspace{} if err := json.Unmarshal([]byte(resp.Node.Value), sk); err != nil { log.Errorf("failed to Unmarshal EndPoints for %v: %v", filePath, err) continue } srvKeyspace = topo.ProtoToSrvKeyspace(sk) } notifications <- srvKeyspace case <-stopWatching: close(stop) close(notifications) return } } }() return notifications, stopWatching, nil }
// WatchSrvKeyspace is part of the topo.Server interface func (zkts *Server) WatchSrvKeyspace(ctx context.Context, cell, keyspace string) (<-chan *topo.SrvKeyspace, chan<- struct{}, error) { filePath := zkPathForVtKeyspace(cell, keyspace) notifications := make(chan *topo.SrvKeyspace, 10) stopWatching := make(chan struct{}) // waitOrInterrupted will return true if stopWatching is triggered waitOrInterrupted := func() bool { timer := time.After(WatchSleepDuration) select { case <-stopWatching: close(notifications) return true case <-timer: } return false } go func() { for { // set the watch data, _, watch, err := zkts.zconn.GetW(filePath) if err != nil { if zookeeper.IsError(err, zookeeper.ZNONODE) { // the parent directory doesn't exist notifications <- nil } log.Errorf("Cannot set watch on %v, waiting for %v to retry: %v", filePath, WatchSleepDuration, err) if waitOrInterrupted() { return } continue } // get the initial value, send it, or send nil if no // data var srvKeyspace *topo.SrvKeyspace sendIt := true if len(data) > 0 { sk := &pb.SrvKeyspace{} if err := json.Unmarshal([]byte(data), sk); err != nil { log.Errorf("SrvKeyspace unmarshal failed: %v %v", data, err) sendIt = false } else { srvKeyspace = topo.ProtoToSrvKeyspace(sk) } } if sendIt { notifications <- srvKeyspace } // now act on the watch select { case event, ok := <-watch: if !ok { log.Warningf("watch on %v was closed, waiting for %v to retry", filePath, WatchSleepDuration) if waitOrInterrupted() { return } continue } if !event.Ok() { log.Warningf("received a non-OK event for %v, waiting for %v to retry", filePath, WatchSleepDuration) if waitOrInterrupted() { return } } case <-stopWatching: // user is not interested any more close(notifications) return } } }() return notifications, stopWatching, nil }