func loadLeaderLease(eng engine.Engine, raftID proto.RaftID) (*proto.Lease, error) { lease := &proto.Lease{} if _, err := engine.MVCCGetProto(eng, keys.RaftLeaderLeaseKey(raftID), proto.ZeroTimestamp, true, nil, lease); err != nil { return nil, err } return lease, nil }
// InternalLeaderLease sets the leader lease for this range. The command fails // only if the desired start timestamp collides with a previous lease. // Otherwise, the start timestamp is wound back to right after the expiration // of the previous lease (or zero). After a lease has been set, calls to // HasLeaderLease() will return true if this replica is the lease holder and // the lease has not yet expired. If this range replica is already the lease // holder, the expiration will be extended or shortened as indicated. For a new // lease, all duties required of the range leader are commenced, including // clearing the command queue and timestamp cache. func (r *Range) InternalLeaderLease(batch engine.Engine, ms *engine.MVCCStats, args *proto.InternalLeaderLeaseRequest, reply *proto.InternalLeaderLeaseResponse) { r.Lock() defer r.Unlock() prevLease := r.getLease() isExtension := prevLease.RaftNodeID == args.Lease.RaftNodeID effectiveStart := args.Lease.Start // We return this error in "normal" lease-overlap related failures. rErr := &proto.LeaseRejectedError{ Existing: *prevLease, Requested: args.Lease, } // Verify details of new lease request. The start of this lease must // obviously precede its expiration. if !args.Lease.Start.Less(args.Lease.Expiration) { reply.SetGoError(rErr) return } // Wind the start timestamp back as far to the previous lease's expiration // as we can. That'll make sure that when multiple leases are requested out // of order at the same replica (after all, they use the request timestamp, // which isn't straight out of our local clock), they all succeed unless // they have a "real" issue with a previous lease. Example: Assuming no // previous lease, one request for [5, 15) followed by one for [0, 15) // would fail without this optimization. With it, the first request // effectively gets the lease for [0, 15), which the second one can commit // again (even extending your own lease is possible; see below). // // If no old lease exists or this is our lease, we don't need to add an // extra tick. This allows multiple requests from the same replica to // merge without ticking away from the minimal common start timestamp. if prevLease.RaftNodeID == 0 || isExtension { // TODO(tschottdorf) Think about whether it'd be better to go all the // way back to prevLease.Start(), so that whenever the last lease is // the own one, the original start is preserved. effectiveStart.Backward(prevLease.Expiration) } else { effectiveStart.Backward(prevLease.Expiration.Next()) } if isExtension { if effectiveStart.Less(prevLease.Start) { reply.SetGoError(rErr) return } // Note that the lease expiration can be shortened by the holder. // This could be used to effect a faster lease handoff. } else if effectiveStart.Less(prevLease.Expiration) { reply.SetGoError(rErr) return } args.Lease.Start = effectiveStart // Store the lease to disk & in-memory. if err := engine.MVCCPutProto(batch, ms, keys.RaftLeaderLeaseKey(r.Desc().RaftID), proto.ZeroTimestamp, nil, &args.Lease); err != nil { reply.SetGoError(err) return } atomic.StorePointer(&r.lease, unsafe.Pointer(&args.Lease)) // If this replica is a new holder of the lease, update the // low water mark in the timestamp cache. We add the maximum // clock offset to account for any difference in clocks // between the expiration (set by a remote node) and this // node. if r.getLease().RaftNodeID == r.rm.RaftNodeID() && prevLease.RaftNodeID != r.getLease().RaftNodeID { r.tsCache.SetLowWater(prevLease.Expiration.Add(int64(r.rm.Clock().MaxOffset()), 0)) log.Infof("range %d: new leader lease %s", r.Desc().RaftID, args.Lease) } // Gossip configs in the event this range contains config info. r.maybeGossipConfigsLocked(func(configPrefix proto.Key) bool { return r.ContainsKey(configPrefix) }) }