vitess.io/vitess@v0.16.2/go/vt/topo/srv_vschema.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package topo 18 19 import ( 20 "context" 21 "fmt" 22 "sync" 23 24 "google.golang.org/protobuf/proto" 25 26 "vitess.io/vitess/go/vt/log" 27 "vitess.io/vitess/go/vt/vterrors" 28 29 vschemapb "vitess.io/vitess/go/vt/proto/vschema" 30 ) 31 32 // This file contains the utility methods to manage SrvVSchema objects. 33 34 // WatchSrvVSchemaData is returned / streamed by WatchSrvVSchema. 35 // The WatchSrvVSchema API guarantees exactly one of Value or Err will be set. 36 type WatchSrvVSchemaData struct { 37 Value *vschemapb.SrvVSchema 38 Err error 39 } 40 41 // WatchSrvVSchema will set a watch on the SrvVSchema object. 42 // It has the same contract as Conn.Watch, but it also unpacks the 43 // contents into a SrvVSchema object. 44 func (ts *Server) WatchSrvVSchema(ctx context.Context, cell string) (*WatchSrvVSchemaData, <-chan *WatchSrvVSchemaData, error) { 45 conn, err := ts.ConnForCell(ctx, cell) 46 if err != nil { 47 return nil, nil, err 48 } 49 50 ctx, cancel := context.WithCancel(ctx) 51 current, wdChannel, err := conn.Watch(ctx, SrvVSchemaFile) 52 if err != nil { 53 cancel() 54 return nil, nil, err 55 } 56 value := &vschemapb.SrvVSchema{} 57 if err := proto.Unmarshal(current.Contents, value); err != nil { 58 // Cancel the watch, drain channel. 59 cancel() 60 for range wdChannel { 61 } 62 return nil, nil, vterrors.Wrapf(err, "error unpacking initial SrvVSchema object") 63 } 64 65 changes := make(chan *WatchSrvVSchemaData, 10) 66 67 // The background routine reads any event from the watch channel, 68 // translates it, and sends it to the caller. 69 // If cancel() is called, the underlying Watch() code will 70 // send an ErrInterrupted and then close the channel. We'll 71 // just propagate that back to our caller. 72 go func() { 73 defer cancel() 74 defer close(changes) 75 76 for wd := range wdChannel { 77 if wd.Err != nil { 78 // Last error value, we're done. 79 // wdChannel will be closed right after 80 // this, no need to do anything. 81 changes <- &WatchSrvVSchemaData{Err: wd.Err} 82 return 83 } 84 85 value := &vschemapb.SrvVSchema{} 86 if err := proto.Unmarshal(wd.Contents, value); err != nil { 87 cancel() 88 for range wdChannel { 89 } 90 changes <- &WatchSrvVSchemaData{Err: vterrors.Wrapf(err, "error unpacking SrvVSchema object")} 91 return 92 } 93 changes <- &WatchSrvVSchemaData{Value: value} 94 } 95 }() 96 97 return &WatchSrvVSchemaData{Value: value}, changes, nil 98 } 99 100 // UpdateSrvVSchema updates the SrvVSchema file for a cell. 101 func (ts *Server) UpdateSrvVSchema(ctx context.Context, cell string, srvVSchema *vschemapb.SrvVSchema) error { 102 conn, err := ts.ConnForCell(ctx, cell) 103 if err != nil { 104 return err 105 } 106 107 nodePath := SrvVSchemaFile 108 data, err := proto.Marshal(srvVSchema) 109 if err != nil { 110 return err 111 } 112 _, err = conn.Update(ctx, nodePath, data, nil) 113 return err 114 } 115 116 // GetSrvVSchema returns the SrvVSchema for a cell. 117 func (ts *Server) GetSrvVSchema(ctx context.Context, cell string) (*vschemapb.SrvVSchema, error) { 118 conn, err := ts.ConnForCell(ctx, cell) 119 if err != nil { 120 return nil, err 121 } 122 123 nodePath := SrvVSchemaFile 124 data, _, err := conn.Get(ctx, nodePath) 125 if err != nil { 126 return nil, err 127 } 128 srvVSchema := &vschemapb.SrvVSchema{} 129 if err := proto.Unmarshal(data, srvVSchema); err != nil { 130 return nil, vterrors.Wrapf(err, "SrvVSchema unmarshal failed: %v", data) 131 } 132 return srvVSchema, nil 133 } 134 135 // DeleteSrvVSchema deletes the SrvVSchema file for a cell. 136 func (ts *Server) DeleteSrvVSchema(ctx context.Context, cell string) error { 137 conn, err := ts.ConnForCell(ctx, cell) 138 if err != nil { 139 return err 140 } 141 142 nodePath := SrvVSchemaFile 143 return conn.Delete(ctx, nodePath, nil) 144 } 145 146 // RebuildSrvVSchema rebuilds the SrvVSchema for the provided cell list 147 // (or all cells if cell list is empty). 148 func (ts *Server) RebuildSrvVSchema(ctx context.Context, cells []string) error { 149 // get the actual list of cells 150 if len(cells) == 0 { 151 var err error 152 cells, err = ts.GetKnownCells(ctx) 153 if err != nil { 154 return fmt.Errorf("GetKnownCells failed: %v", err) 155 } 156 } 157 158 // get the keyspaces 159 keyspaces, err := ts.GetKeyspaces(ctx) 160 if err != nil { 161 return fmt.Errorf("GetKeyspaces failed: %v", err) 162 } 163 164 // build the SrvVSchema in parallel, protected by mu 165 wg := sync.WaitGroup{} 166 mu := sync.Mutex{} 167 var finalErr error 168 srvVSchema := &vschemapb.SrvVSchema{ 169 Keyspaces: map[string]*vschemapb.Keyspace{}, 170 } 171 for _, keyspace := range keyspaces { 172 wg.Add(1) 173 go func(keyspace string) { 174 defer wg.Done() 175 176 k, err := ts.GetVSchema(ctx, keyspace) 177 if IsErrType(err, NoNode) { 178 err = nil 179 k = &vschemapb.Keyspace{} 180 } 181 182 mu.Lock() 183 defer mu.Unlock() 184 if err != nil { 185 log.Errorf("%v: GetVSchema(%v) failed", err, keyspace) 186 finalErr = err 187 return 188 } 189 srvVSchema.Keyspaces[keyspace] = k 190 }(keyspace) 191 } 192 wg.Wait() 193 if finalErr != nil { 194 return finalErr 195 } 196 197 rr, err := ts.GetRoutingRules(ctx) 198 if err != nil { 199 return fmt.Errorf("GetRoutingRules failed: %v", err) 200 } 201 srvVSchema.RoutingRules = rr 202 203 srr, err := ts.GetShardRoutingRules(ctx) 204 if err != nil { 205 return fmt.Errorf("GetShardRoutingRules failed: %v", err) 206 } 207 srvVSchema.ShardRoutingRules = srr 208 209 // now save the SrvVSchema in all cells in parallel 210 for _, cell := range cells { 211 wg.Add(1) 212 go func(cell string) { 213 defer wg.Done() 214 if err := ts.UpdateSrvVSchema(ctx, cell, srvVSchema); err != nil { 215 log.Errorf("%v: UpdateSrvVSchema(%v) failed", err, cell) 216 mu.Lock() 217 finalErr = err 218 mu.Unlock() 219 } 220 }(cell) 221 } 222 wg.Wait() 223 224 return finalErr 225 }