func MaybeCreateRoot(topology *server.Topology, conns map[common.RMId]paxos.Connection, cm *ConnectionManager, lc *client.LocalConnection) error { if topology.RootVarUUId != nil { return nil } requiredKnownRMs := int(topology.TwoFInc) if len(topology.AllRMs) < requiredKnownRMs { return nil } activeRMs := make([]common.RMId, 0, int(topology.FInc)) passiveRMs := make([]common.RMId, 0, int(topology.F)) for _, rmId := range topology.AllRMs[:requiredKnownRMs] { if _, found := conns[rmId]; found && len(activeRMs) < cap(activeRMs) { activeRMs = append(activeRMs, rmId) } else { passiveRMs = append(passiveRMs, rmId) } } if len(activeRMs) < cap(activeRMs) { return nil } server.Log("Creating Root. Actives:", activeRMs, "; Passives:", passiveRMs) for { seg := capn.NewBuffer(nil) txn := msgs.NewTxn(seg) txn.SetSubmitter(uint32(cm.RMId)) txn.SetSubmitterBootCount(cm.BootCount) actions := msgs.NewActionList(seg, 1) txn.SetActions(actions) action := actions.At(0) vUUId := lc.NextVarUUId() action.SetVarId(vUUId[:]) action.SetCreate() create := action.Create() positions := seg.NewUInt8List(int(topology.MaxRMCount)) create.SetPositions(positions) for idx, l := 0, positions.Len(); idx < l; idx++ { positions.Set(idx, uint8(idx)) } create.SetValue([]byte{}) create.SetReferences(msgs.NewVarIdPosList(seg, 0)) allocs := msgs.NewAllocationList(seg, requiredKnownRMs) txn.SetAllocations(allocs) idx := 0 for listIdx, rmIds := range [][]common.RMId{activeRMs, passiveRMs} { for _, rmId := range rmIds { alloc := allocs.At(idx) idx++ alloc.SetRmId(uint32(rmId)) if listIdx == 0 { alloc.SetActive(conns[rmId].BootCount()) } else { alloc.SetActive(0) } indices := seg.NewUInt16List(1) alloc.SetActionIndices(indices) indices.Set(0, 0) } } txn.SetFInc(topology.FInc) txn.SetTopologyVersion(topology.Version) result, err := lc.RunTransaction(&txn, true, activeRMs...) if err != nil { return err } if result == nil { return nil } if result.Which() == msgs.OUTCOME_COMMIT { server.Log("Root created in", vUUId) topology.RootVarUUId = vUUId topology.RootPositions = (*common.Positions)(&positions) return nil } abort := result.Abort() if abort.Which() == msgs.OUTCOMEABORT_RESUBMIT { continue } return fmt.Errorf("Internal error: creation of root gave rerun outcome") } }