private void ReceiveReservationYes(Message m, string src, List<string> userlist, int reservationSequenceNumber, string messageSubType) { int s = Int32.Parse (m.PopString ()); DebugLogic ("Received YES for slot {0}, reservation number {1}",s,reservationSequenceNumber); Slot slot = m_numberToSlotMap[s]; Reservation res = m_activeReservationSessions[reservationSequenceNumber]; int ackcount; if (res.m_acksForSlot.ContainsKey (s)) { res.m_acksForSlot[s]++; ackcount = res.m_acksForSlot[s]; } else { ackcount = 1; res.m_acksForSlot[s] = ackcount; } if (ackcount == res.m_userList.Count // the below two conditions are sanity checks. && res.m_reservationState != CalendarServiceClient.ReservationState.COMMITTED && m_numberToSlotMap[s].m_calendarState != CalendarServiceClient.CalendarState.ASSIGNED) { DebugLogic ("Woopee! I can haz slot! {0}", s); //send DoCommit Message docommitMsg = new Message (); docommitMsg.SetSourceUserName (m_client.UserName); docommitMsg.SetDestinationUsers (res.m_userList); docommitMsg.SetMessageType ("calendar"); docommitMsg.PushString (s.ToString ()); docommitMsg.PushString (reservationSequenceNumber.ToString ()); docommitMsg.PushString ("docommit"); SendMessage (docommitMsg); // If you have to send this, then you can commit. // TODO: Handle 2/1, 1/2 deadlock. slot.m_calendarState = CalendarServiceClient.CalendarState.ASSIGNED; res.m_reservationState = CalendarServiceClient.ReservationState.COMMITTED; } }
private void UnPackUserTable(Message ack) { int size = Int32.Parse (ack.PopString ()); for (int i = 0; i < size; i++) { string[] tuple = ack.PopString ().Split (','); m_server.m_userTableService.UserConnect (tuple[0], tuple[1]); } }
private void ReceiveReservationRequest(Message m, string src, List<string> userlist, int reservationSequenceNumber, string messageSubType) { /* If I get a reservation request for a slot * that is either FREE or ACKNOWLEDGED, then * respond with an ACK, else if it is either * BOOKED, or ASSIGNED, then respond with a NACK */ int numSlots = Int32.Parse (m.PopString ()); // number of slots List<int> slotlist = new List<int> (); // unpack all the slots for (int i = 0; i < numSlots; i++) { slotlist.Add (Int32.Parse (m.PopString ())); } string description = m.PopString (); // description DebugLogic ("Received Message:" + "[{0}, {1}, {2}, {3}, {4}, {5}, {6}]", src, userlist.ToString (), messageSubType, reservationSequenceNumber, numSlots, slotlist.ToString (), description); /* Message unpacked, now create a reservation object */ if (m_activeReservationSessions.ContainsKey (reservationSequenceNumber)) { DebugFatal ("Duplicate reservation request received {0}", reservationSequenceNumber); } /* Create reservation object */ Reservation reservation = new Reservation (); reservation.m_description = description; reservation.m_sequenceNumber = reservationSequenceNumber; reservation.m_userList = userlist; reservation.m_slotNumberList = slotlist; reservation.m_initiator = src; /* * check if slots are free * and proceed to respond with an ACK or NACK. */ List<int> availableslots = new List<int> (); foreach (int i in slotlist) { // If slot is being encountered for the // first time... if (!m_numberToSlotMap.ContainsKey (i)) { DebugLogic ("Creating new slot instance for slot-number: {0}", i); // Then create new slot. // TODO: Probably need internal methods for this Slot tempslot = new Slot (); tempslot.m_calendarState = CalendarState.FREE; tempslot.m_slotNumber = i; tempslot.m_reservationsForThisSlot = new List<Reservation> (); tempslot.m_preCommitList = new SortedList<int, Reservation> (); tempslot.m_lockedReservation = -1; // Add to int-to-slot-object map m_numberToSlotMap.Add (i, tempslot); } // Get the concerned slot Slot slot = m_numberToSlotMap[i]; if (slot.m_calendarState == CalendarServiceClient.CalendarState.FREE || slot.m_calendarState == CalendarServiceClient.CalendarState.ACKNOWLEDGED) { // Update the slot's reservation list slot.m_reservationsForThisSlot.Add (reservation); // Append to list of slots. availableslots.Add (i); // Update slot state slot.m_calendarState = CalendarServiceClient.CalendarState.ACKNOWLEDGED; DebugLogic ("Slot {0} is now in ACKNOWLEDGED state", i); } } // Respond with ACK/NACK if (availableslots.Count > 0) { // We do have at least one free slot, so respond with an ACK Message ack = new Message (); ack.SetSourceUserName (m_client.UserName); ack.SetDestinationUsers (src); ack.SetMessageType ("calendar"); /* * ACK Message format, data part * * - Number of Slots * - Slot 1 * - Slot 2 * ... * - Slot N */ availableslots.Reverse (); foreach (int i in availableslots) { ack.PushString (i.ToString ()); DebugInfo ("Slot {0} is available", i); } ack.PushString (availableslots.Count.ToString ()); ack.PushString (reservationSequenceNumber.ToString ()); ack.PushString ("reservationack"); DebugLogic ("Sending an ack to: {0}", src); SendMessage (ack); m_activeReservationSessions.Add (reservationSequenceNumber, reservation); } else { Message nack = new Message (); // No free slots, so respond with a NACK nack.SetSourceUserName (m_client.UserName); nack.SetDestinationUsers (src); nack.SetMessageType ("calendar"); nack.PushString ("reservationnack"); DebugLogic ("Sending a nack to: {0}", src); SendMessage (nack); } }
private void ReceiveReservationPreCommit(Message m, string src, List<string> userlist, int reservationSequenceNumber, string messageSubType) { /* If I get a PRECOMMIT update for a slot, * and it is still in ACKNOWLEDGED state, then * respond with YES!. Else, respond with a NO! * * If I responded with a YES, then * move into PRECOMMIT state and begin * verification and commit timers. * * When verification timer fires, verify * your neighbours. TODO: Might need ping * utility * * If verification fails, ABORT, else do nothing. * * When commit timer fires, commit. * * If I responded with a NO, then move * into ABORT. * * If between any of the above, the coordinator * sends an ABORT message, then ABORT. DUH! */ int s = Int32.Parse (m.PopString ()); DebugLogic ("Received precommit for slot {0}, reservation number {1}",s,reservationSequenceNumber); Slot slot = m_numberToSlotMap[s]; Reservation res = m_activeReservationSessions[reservationSequenceNumber]; if (slot.m_calendarState == CalendarServiceClient.CalendarState.ACKNOWLEDGED || slot.m_calendarState == CalendarServiceClient.CalendarState.BOOKED) { if (slot.m_preCommitList.Count == 0 && slot.m_lockedReservation == -1) { res.m_reservationState = CalendarServiceClient.ReservationState.TENTATIVELY_BOOKED; slot.m_calendarState = CalendarServiceClient.CalendarState.BOOKED; // No one has a lock, so this reservation gets it. Message yes = new Message (); yes.SetDestinationUsers (src); yes.SetMessageType ("calendar"); yes.SetSourceUserName (m_client.UserName); yes.PushString (s.ToString ()); yes.PushString (reservationSequenceNumber.ToString ()); yes.PushString ("yes"); slot.m_lockedReservation = reservationSequenceNumber; SendMessage (yes); } else if (slot.m_lockedReservation != -1 && slot.m_lockedReservation < s) { // Some reservation older is already locked, so wait. slot.m_preCommitList.Add (reservationSequenceNumber, res); } else { // Add older reservation to queue, we may upgrade or abort this // depending on the result of the next step slot.m_preCommitList.Add (reservationSequenceNumber, res); // A newer reservation has been locked. For now, // we try and ABORT the newer one in favour of the older one. // But the optimisation here would be for coordinators to // initiate an is-there-a-deadlock check, which the cohort // would ask the coordinator to initiate. Message abortmsg = new Message (); abortmsg.SetDestinationUsers (m_activeReservationSessions[reservationSequenceNumber].m_initiator); abortmsg.SetMessageType ("calendar"); abortmsg.SetSourceUserName (m_client.UserName); abortmsg.PushString (s.ToString ()); // we need to mention the slot that is being aborted abortmsg.PushString (slot.m_lockedReservation.ToString ()); abortmsg.PushString ("abort"); SendMessage (abortmsg); ReservationAbortCohort (slot.m_lockedReservation, s); } } }
private void ReceiveReservationDoCommit(Message m, string src, List<string> userlist, int reservationSequenceNumber, string messageSubType) { int s = Int32.Parse (m.PopString ()); DebugLogic ("Received docommit for slot {0}, reservation number {1}",s,reservationSequenceNumber); Slot slot = m_numberToSlotMap[s]; Reservation res = m_activeReservationSessions[reservationSequenceNumber]; slot.m_calendarState = CalendarServiceClient.CalendarState.ASSIGNED; res.m_reservationState = CalendarServiceClient.ReservationState.COMMITTED; DebugLogic ("Reservation ID: {0}, Slot: {1} has COMMITTED", reservationSequenceNumber, s); if (m_client.m_isPuppetControlled) { m_client.m_puppetService.SendInfoMsgToPuppetMaster ("Reservation ID: {0}, Slot: {1} has COMMITTED", reservationSequenceNumber, s); } // Perform cleanup of all reservation objects foreach (int i in res.m_slotNumberList) { if (i != s) { m_numberToSlotMap[i].m_reservationsForThisSlot.Remove (res); } } foreach (int i in slot.m_preCommitList.Keys) { Message abortmsg = new Message (); abortmsg.SetDestinationUsers (m_activeReservationSessions[reservationSequenceNumber].m_initiator); abortmsg.SetMessageType ("calendar"); abortmsg.SetSourceUserName (m_client.UserName); abortmsg.PushString (s.ToString ()); // we need to mention the slot that is being aborted abortmsg.PushString (reservationSequenceNumber.ToString ()); abortmsg.PushString ("abort"); SendMessage (abortmsg); ReservationAbortCohort (i, s); } }
private void ReceiveReservationAckNack(Message m, string src, List<string> userlist, int reservationSequenceNumber, string messageSubType) { /* If I am the initiator of the reservation, * then keep collecting ACKS/NACKS from all participants * * If ACK rcvd, then update received ACK counter. * * If all ACKS rcvd, move reservation state to * TENTATIVELY_BOOKED for those slots. * Then inform all nodes about decision with a * PRECOMMIT message and move to PRECOMMIT state. * * If at least one NACK, move reservation state * to ABORTED. TODO: Should we notify others? */ DebugLogic ("Received {0} from {1} for reservation ID: {2}", messageSubType, src, reservationSequenceNumber); // obtain reservation objects Reservation res = m_activeReservationSessions[reservationSequenceNumber]; int slotCount = Int32.Parse (m.PopString ()); if (messageSubType.Equals ("reservationack") && res.m_reservationState != CalendarServiceClient.ReservationState.ABORTED) { List<int> validSlots = new List<int> (); int ackcount = 0; while (slotCount > 0) { int s = Int32.Parse (m.PopString ()); if (m_numberToSlotMap[s].m_calendarState != CalendarServiceClient.CalendarState.BOOKED && m_numberToSlotMap[s].m_lockedReservation == -1) { validSlots.Add (s); DebugInfo ("Adding {0} to validslot list", s); if (res.m_acksForSlot.ContainsKey (s)) { res.m_acksForSlot[s]++; ackcount = res.m_acksForSlot[s]; } else { ackcount = 1; res.m_acksForSlot[s] = ackcount; } } slotCount--; } // If there are slots which were not part of // the ack, then we do some cleanup. if (validSlots.Count != res.m_slotNumberList.Count) { foreach (int i in res.m_slotNumberList) { bool isPresent = false; foreach (int j in validSlots) { if (i == j) { isPresent = true; } } if (!isPresent) { m_numberToSlotMap[i].m_reservationsForThisSlot.Remove (res); } } } res.m_slotNumberList = validSlots; // If enough ACKS, then proceed with precommit for // each valid slot, one by one. if (res.m_userList.Count == ackcount) { res.m_reservationState = CalendarServiceClient.ReservationState.TENTATIVELY_BOOKED; m_numberToSlotMap[res.m_slotNumberList[0]].m_calendarState = CalendarServiceClient.CalendarState.BOOKED; m_numberToSlotMap[res.m_slotNumberList[0]].m_lockedReservation = reservationSequenceNumber; SendPreCommitMessage (res, res.m_slotNumberList[0]); res.m_acksForSlot.Clear (); } } else if (messageSubType.Equals ("reservationnack")) { res.m_reservationState = CalendarServiceClient.ReservationState.ABORTED; DebugLogic ("Send NACK to {0}", src); foreach (int i in res.m_slotNumberList) { m_numberToSlotMap[i].m_reservationsForThisSlot.Remove (res); } } }
private void ReceiveReservationAbort(Message m, string src, List<string> userlist, int reservationSequenceNumber, string messageSubType) { int s = Int32.Parse (m.PopString ()); DebugLogic ("Received ABORT for slot {0}, reservation number {1}",s,reservationSequenceNumber); Slot slot = m_numberToSlotMap[s]; Reservation res = m_activeReservationSessions[reservationSequenceNumber]; // if i am the initiator, and the reservation has not already committed, // or has not already been aborted by someone else, // then send every1 aborts. if (res.m_initiator.Equals (m_client.UserName) && res.m_reservationState != CalendarServiceClient.ReservationState.COMMITTED && res.m_reservationState != CalendarServiceClient.ReservationState.ABORTED) { //Perform my own cleanup, res.m_slotNumberList.Remove (s); // The earlier reservation is now removed from this slot slot.m_reservationsForThisSlot.Remove (res); // If this was the last slot in contention for // the reservation... if (res.m_slotNumberList.Count == 0) { // ... then the reservation should be in ABORTED state. Sigh. res.m_reservationState = CalendarServiceClient.ReservationState.ABORTED; } else { // Pick next tentatively booked slot and send out precommit messages SendPreCommitMessage (res, res.m_slotNumberList[0]); } // TODO:send everyone abort messages. } else { // Abort the reservation entry for this particular slot. ReservationAbortCohort (reservationSequenceNumber, s); } }