func (s *adminServer) ClusterFreeze( ctx context.Context, req *ClusterFreezeRequest, ) (*ClusterFreezeResponse, error) { var resp ClusterFreezeResponse stores := make(map[roachpb.StoreID]roachpb.NodeID) process := func(from, to roachpb.Key) (roachpb.Key, error) { b := &client.Batch{} fa := roachpb.NewChangeFrozen(from, to, req.Freeze, build.GetInfo().Tag) b.AddRawRequest(fa) if err := s.server.db.Run(b); err != nil { return nil, err } fr := b.RawResponse().Responses[0].GetInner().(*roachpb.ChangeFrozenResponse) resp.RangesAffected += fr.RangesAffected for storeID, nodeID := range fr.Stores { stores[storeID] = nodeID } return fr.MinStartKey.AsRawKey(), nil } if req.Freeze { // When freezing, we save the meta2 and meta1 range for last to avoid // interfering with command routing. // Note that we freeze only Ranges whose StartKey is included. In // particular, a Range which contains some meta keys will not be frozen // by the request that begins at Meta2KeyMax. ChangeFreeze gives us the // leftmost covered Range back, which we use for the next request to // avoid split-related races. freezeTo := roachpb.KeyMax // updated as we go along freezeFroms := []roachpb.Key{ keys.Meta2KeyMax, // freeze userspace keys.Meta1KeyMax, // freeze all meta2 ranges keys.LocalMax, // freeze first range (meta1) } for _, freezeFrom := range freezeFroms { var err error if freezeTo, err = process(freezeFrom, freezeTo); err != nil { return nil, err } } } else { // When unfreezing, we walk in opposite order and try the first range // first. We should be able to get there if the first range manages to // gossip. From that, we can talk to the second level replicas, and // then to everyone else. Because ChangeFrozen works in forward order, // we can simply hit the whole keyspace at once. // TODO(tschottdorf): make the first range replicas gossip their // descriptor unconditionally or we won't always be able to unfreeze // (except by restarting a node which holds the first range). if _, err := process(keys.LocalMax, roachpb.KeyMax); err != nil { return nil, err } } return &resp, s.waitForStoreFrozen(stores, req.Freeze) }
// ChangeFrozen attempts to freeze or unfreeze all Ranges with StartKey // covered by the given key range. func (b *Batch) ChangeFrozen(s, e interface{}, mustVersion string, frozen bool) { begin, err := marshalKey(s) if err != nil { b.initResult(0, 0, err) return } end, err := marshalKey(e) if err != nil { b.initResult(0, 0, err) return } b.reqs = append(b.reqs, roachpb.NewChangeFrozen(roachpb.Key(begin), roachpb.Key(end), frozen, mustVersion)) b.initResult(1, 1, nil) }