func (s *Simulator) Depose(args []string) { cs := s.discoverd.ClusterState() if cs.State == nil { s.log.Error("cluster is not yet configured (try `bootstrap`)") return } if len(cs.State.Async) == 0 { s.log.Error("cannot depose with no asyncs") return } newWAL, err := xlog.Increment(cs.State.InitWAL, 10) if err != nil { panic(err) } cs.State = &state.State{ Generation: cs.State.Generation + 1, Deposed: append(cs.State.Deposed, cs.State.Primary), Primary: cs.State.Sync, Sync: cs.State.Async[0], Async: cs.State.Async[1:], InitWAL: newWAL, } s.discoverd.SetClusterState(cs) s.jsonDump(cs) }
func (p *postgresSimulatorClient) catchUp() { if p.XLogWaiting == "" { p.p.log.Error("catchUp when not sync or not currently waiting") } var err error p.XLog, err = xlog.Increment(p.XLogWaiting, 10) if err != nil { panic(err) } p.XLogWaiting = "" }
// Given the current state, figure out our current role and update our xlog // position accordingly. This is used when we assume a new role or when postgres // comes online in order to simulate client writes to the primary, synchronous // replication (and catch-up) on the sync, and asynchronous replication on the // other peers. func (p *postgresSimulatorClient) updateXlog(ds *state.DiscoverdState) { if ds.State == nil || !p.Online || p.Config == nil { return } s := ds.State var role state.Role switch { case s.Primary.ID == p.inst.ID: role = state.RolePrimary case s.Sync.ID == p.inst.ID: role = state.RoleSync case p.Config.Role == state.RoleAsync: role = state.RoleAsync default: role = state.RoleNone } // If the peer we're testing is an async or unassigned, we don't modify the // transaction log position at all. We act as though these are getting // arbitrarily far behind (since that should be fine). if role == state.RoleAsync || role == state.RoleNone { return } // If the peer we're testing is a primary, we act as though the sync // instantly connected and caught up, and we start taking writes immediately // and bump the transaction log position. if role == state.RolePrimary { if cmp, err := xlog.Compare(s.InitWAL, p.XLog); err != nil { panic(err) } else if cmp > 0 { panic("primary is behind the generation's initial xlog") } var err error p.XLog, err = xlog.Increment(p.XLog, 10) if err != nil { panic(err) } return } // The most complicated case is the sync, for which we need to schedule the // wal position to catch up to the primary's. if role != state.RoleSync { panic("unexpected role") } if cmp, err := xlog.Compare(s.InitWAL, p.XLog); err != nil { panic(err) } else if cmp < 0 { panic("sync is ahead of primary") } p.XLogWaiting = s.InitWAL }