// LoadVSchema loads the VSchema from the topo. The function does // not return an error. It instead logs warnings on failure. func (plr *Planner) LoadVSchema(ctx context.Context) { formal := &vindexes.VSchemaFormal{ Keyspaces: make(map[string]vindexes.KeyspaceFormal), } keyspaces, err := plr.serv.GetSrvKeyspaceNames(ctx, plr.cell) if err != nil { log.Warningf("Error loading vschema: could not read keyspaces: %v", err) return } for _, keyspace := range keyspaces { formal.Keyspaces[keyspace] = vindexes.KeyspaceFormal{} kschema, err := plr.serv.GetVSchema(context.TODO(), keyspace) if err != nil { log.Warningf("Error loading vschema for keyspace: %s: %v", keyspace, err) continue } var kformal vindexes.KeyspaceFormal err = json.Unmarshal([]byte(kschema), &kformal) if err != nil { log.Warningf("Error unmarshalling vschema for keyspace: %s: %v", keyspace, err) continue } formal.Keyspaces[keyspace] = kformal } vschema, err := vindexes.BuildVSchema(formal) if err != nil { log.Warningf("Error creating VSchema: %v", err) return } plr.mu.Lock() plr.vschema = vschema plr.mu.Unlock() }
func loadSchema(t *testing.T, filename string) *vindexes.VSchema { formal, err := vindexes.LoadFormal(locateFile(filename)) if err != nil { t.Fatal(err) } vschema, err := vindexes.BuildVSchema(formal) if err != nil { t.Fatal(err) } return vschema }
// WatchSrvVSchema watches the SrvVSchema from the topo. The function does // not return an error. It instead logs warnings on failure. // The SrvVSchema object is roll-up of all the Keyspace information, // so when a keyspace is added or removed, it will be properly updated. // // This function will wait until the first value has either been processed // or triggered an error before returning. func (plr *Planner) WatchSrvVSchema(ctx context.Context, cell string) { wg := sync.WaitGroup{} wg.Add(1) go func() { foundFirstValue := false // Create a closure to save the vschema. If the value // passed is nil, it means we encountered an error and // we don't know the real value. In this case, we want // to use the previous value if it was set, or an // empty vschema if it wasn't. saveVSchema := func(v *vschemapb.SrvVSchema, errorMessage string) { // transform the provided SrvVSchema into a VSchema var vschema *vindexes.VSchema if v != nil { var err error vschema, err = vindexes.BuildVSchema(v) if err != nil { log.Warningf("Error creating VSchema for cell %v (will try again next update): %v", cell, err) v = nil errorMessage = fmt.Sprintf("Error creating VSchema for cell %v: %v", cell, err) if vschemaCounters != nil { vschemaCounters.Add("Parsing", 1) } } } if v == nil { // we encountered an error, build an // empty vschema vschema, _ = vindexes.BuildVSchema(&vschemapb.SrvVSchema{}) } // Build the display version. stats := NewVSchemaStats(vschema, errorMessage) // save our value plr.mu.Lock() if v != nil { // no errors, we can save our schema plr.vschema = vschema } else { // we had an error, use the empty vschema // if we had nothing before. if plr.vschema == nil { plr.vschema = vschema } } plr.vschemaStats = stats plr.mu.Unlock() plr.plans.Clear() if vschemaCounters != nil { vschemaCounters.Add("Reload", 1) } // notify the listener if !foundFirstValue { foundFirstValue = true wg.Done() } } for { current, changes, _ := plr.serv.WatchSrvVSchema(ctx, cell) if current.Err != nil { // Don't log if there is no VSchema to start with. if current.Err != topo.ErrNoNode { log.Warningf("Error watching vschema for cell %s (will wait 5s before retrying): %v", cell, current.Err) } saveVSchema(nil, fmt.Sprintf("Error watching SvrVSchema: %v", current.Err.Error())) if vschemaCounters != nil { vschemaCounters.Add("WatchError", 1) } time.Sleep(5 * time.Second) continue } saveVSchema(current.Value, "") for c := range changes { if c.Err != nil { // If the SrvVschema disappears, we need to clear our record. // Otherwise, keep what we already had before. if c.Err == topo.ErrNoNode { saveVSchema(nil, "SrvVSchema object was removed from topology.") } log.Warningf("Error while watching vschema for cell %s (will wait 5s before retrying): %v", cell, c.Err) if vschemaCounters != nil { vschemaCounters.Add("WatchError", 1) } break } saveVSchema(c.Value, "") } // Sleep a bit before trying again. time.Sleep(5 * time.Second) } }() // wait for the first value to have been processed wg.Wait() }
// WatchSrvVSchema watches the SrvVSchema from the topo. The function does // not return an error. It instead logs warnings on failure. // The SrvVSchema object is roll-up of all the Keyspace information, // so when a keyspace is added or removed, it will be properly updated. // // This function will wait until the first value has either been processed // or triggered an error before returning. func (plr *Planner) WatchSrvVSchema(ctx context.Context, cell string) { wg := sync.WaitGroup{} wg.Add(1) go func() { foundFirstValue := false // Create a closure to save the vschema. If the value // passed is nil, it means we encountered an error and // we don't know the real value. In this case, we want // to use the previous value if it was set, or an // empty vschema if it wasn't. saveVSchema := func(v *vschemapb.SrvVSchema) { // transform the provided SrvVSchema into a VSchema var vschema *vindexes.VSchema if v != nil { var err error vschema, err = vindexes.BuildVSchema(v) if err != nil { log.Warningf("Error creating VSchema for cell %v (will try again next update): %v", cell, err) v = nil } } if v == nil { // we encountered an error, build an // empty vschema vschema, _ = vindexes.BuildVSchema(&vschemapb.SrvVSchema{}) } // save our value plr.mu.Lock() if v != nil { // no errors, we can save our schema plr.vschema = vschema } else { // we had an error, use the empty vschema // if we had nothing before. if plr.vschema == nil { plr.vschema = vschema } } plr.mu.Unlock() plr.plans.Clear() // notify the listener if !foundFirstValue { foundFirstValue = true wg.Done() } } for { n, err := plr.serv.WatchSrvVSchema(ctx, cell) if err != nil { log.Warningf("Error watching vschema for cell %s (will wait 5s before retrying): %v", cell, err) saveVSchema(nil) time.Sleep(5 * time.Second) continue } for value := range n { if value == nil { log.Warningf("Got an empty vschema for cell %v", cell) saveVSchema(&vschemapb.SrvVSchema{}) continue } saveVSchema(value) } log.Warningf("Watch on vschema for cell %v ended, will wait 5s before retrying", cell) saveVSchema(nil) time.Sleep(5 * time.Second) } }() // wait for the first value to have been processed wg.Wait() }