func BecomeMaster()

in quorum/quorum.go [84:169]


func BecomeMaster(uri string, db string) error {

	retry := 30
	for retry != 0 {
		if conn, err := makeSession(uri); err == nil {
			masterCollection := conn.Client.Database(db).Collection(QUORUM_COLLECTION)

			status := STATUS_LOOKASIDE
			entry := new(ElectionEntry)

			// keep quorum
		Keep:
			for {
				if status == STATUS_LOOKASIDE || status == STATUS_MASTER {
					wait(HeartBeatPeriod)
				}

				switch status {
				case STATUS_LOOKASIDE:
					// take from database firstly
					err = masterCollection.FindOne(context.Background(),
						bson.M{"_id": electionObjectId}).Decode(entry)

					switch err {
					case nil:
						if entry.Host == getNetAddr() && entry.PID == os.Getpid() {
							// master is me. just update heartbeat
							status = STATUS_MASTER
						} else {
							status = STATUS_FOLLOW
						}
					case mongo.ErrNoDocuments:
						LOG.Debug("No master node found. we elect myself")
						status = STATUS_COMPETE_MASTER
					default:
						LOG.Warn("Fetch master election info %s failed. %v", electionObjectId, err)
						status = STATUS_SESSION_CLOSE
					}

				case STATUS_MASTER:
					if _, err := masterCollection.UpdateOne(context.Background(),
						bson.D{{"_id", electionObjectId}, {"pid", os.Getpid()}},
						bson.M{"$set": promotion()}); err == nil {
						masterChanged(PromoteMaster)
					} else {
						LOG.Warn("Update master election info failed. %v", err)
						status = STATUS_LOOKASIDE
					}

				case STATUS_COMPETE_MASTER:
					// there is no one master
					competeMaster(masterCollection)
					status = STATUS_LOOKASIDE

				case STATUS_FOLLOW:
					if master {
						masterChanged(DescendMaster)
					}

					// there has been already another master. check its heartbeat
					heartbeat := entry.Heartbeat
					if time.Now().Unix()-heartbeat >= int64(HeartBeatTimeoutInSeconds) {
						// I wanna be the master. DON'T care about the success of update
						masterCollection.UpdateOne(context.Background(),
							bson.D{{"_id", electionObjectId}},bson.M{"$set": promotion()})
						LOG.Info("Expired master found. compete to become master")
						// wait random time. just disrupt others compete
						wait(time.Millisecond * time.Duration(rand.Uint32()%2500+1))
					} else {
						// follow current master
						LOG.Info("Follow current master %v", entry)
					}
					status = STATUS_LOOKASIDE

				case STATUS_SESSION_CLOSE:
					conn.Close()
					break Keep
				}
			}
		}

		retry--
	}

	return fmt.Errorf("unreachable master election mongo %s", uri)
}