lease would either allocate ids or timestamps. This function is triggered by an RPC call. We ensure that only leader can assign new UIDs, so we can tackle any collisions that might happen with the leasemanager In essence, we just want one server to be handing out new uids.
(ctx context.Context, num *pb.Num)
| 67 | // so we can tackle any collisions that might happen with the leasemanager |
| 68 | // In essence, we just want one server to be handing out new uids. |
| 69 | func (s *Server) lease(ctx context.Context, num *pb.Num) (*pb.AssignedIds, error) { |
| 70 | typ := num.GetType() |
| 71 | node := s.Node |
| 72 | // TODO: Fix when we move to linearizable reads, need to check if we are the leader, might be |
| 73 | // based on leader leases. If this node gets partitioned and unless checkquorum is enabled, this |
| 74 | // node would still think that it's the leader. |
| 75 | if !node.AmLeader() { |
| 76 | return &emptyAssignedIds, errors.Errorf("Assigning IDs is only allowed on leader.") |
| 77 | } |
| 78 | |
| 79 | if num.Val == 0 && !num.ReadOnly { |
| 80 | return &emptyAssignedIds, errors.Errorf("Nothing to be leased") |
| 81 | } |
| 82 | if glog.V(3) { |
| 83 | glog.Infof("Got lease request for Type: %v. Num: %+v\n", typ, num) |
| 84 | } |
| 85 | |
| 86 | s.leaseLock.Lock() |
| 87 | defer s.leaseLock.Unlock() |
| 88 | |
| 89 | if typ == pb.Num_TXN_TS { |
| 90 | if num.Val == 0 && num.ReadOnly { |
| 91 | // If we're only asking for a readonly timestamp, we can potentially |
| 92 | // service it directly. |
| 93 | if glog.V(3) { |
| 94 | glog.Infof("Attempting to serve read only txn ts [%d, %d]", |
| 95 | s.readOnlyTs, s.nextUint[pb.Num_TXN_TS]) |
| 96 | } |
| 97 | if s.readOnlyTs > 0 && s.readOnlyTs == s.nextUint[pb.Num_TXN_TS]-1 { |
| 98 | return &pb.AssignedIds{ReadOnly: s.readOnlyTs}, errServedFromMemory |
| 99 | } |
| 100 | } |
| 101 | // We couldn't service it. So, let's request an extra timestamp for |
| 102 | // readonly transactions, if needed. |
| 103 | } |
| 104 | if s.nextUint[pb.Num_UID] == 0 || s.nextUint[pb.Num_TXN_TS] == 0 || |
| 105 | s.nextUint[pb.Num_NS_ID] == 0 { |
| 106 | return nil, errors.New("Server not initialized") |
| 107 | } |
| 108 | |
| 109 | // Calculate how many ids do we have available in memory, before we need to |
| 110 | // renew our lease. |
| 111 | maxLease := s.maxLease(typ) |
| 112 | available := maxLease - s.nextUint[typ] + 1 |
| 113 | |
| 114 | // If we have less available than what we need, we need to renew our lease. |
| 115 | if available < num.Val+1 { // +1 for a potential readonly ts. |
| 116 | // If we're asking for more ids than the standard lease bandwidth, then we |
| 117 | // should set howMany generously, so we can service future requests from |
| 118 | // memory, without asking for another lease. Only used if we need to renew |
| 119 | // our lease. |
| 120 | howMany := leaseBandwidth |
| 121 | if num.Val > leaseBandwidth { |
| 122 | howMany = num.Val + leaseBandwidth |
| 123 | } |
| 124 | if howMany < num.Val || maxLease+howMany < maxLease { // check for overflow. |
| 125 | return &emptyAssignedIds, errors.Errorf("Cannot lease %s as the limit has reached."+ |
| 126 | " currMax:%d", typ, s.nextUint[typ]-1) |