/// <summary> /// Creates a new link to a sibling shard /// </summary> /// <param name="id">Remote shard ID</param> /// <param name="isActive">Actively establish the connection. If false, wait for inbound connection</param> /// <param name="linearIndex">Linear index in the neighborhood</param> /// <param name="isSibling">True if this is a link to a sibling shard (not a neighbor)</param> public Link(ShardID id, bool isActive, int linearIndex, bool isSibling) : this(BaseDB.TryGetPeerAddress(id), isActive, linearIndex, isSibling, id) { }
private void ThreadMain() { Message("Starting Read"); BinaryReader reader = new BinaryReader(netStream); try { var f = new BinaryFormatter(); byte[] header = new byte[8]; while (!closed) { reader.RemainingBytes = 8; uint channel = reader.NextUInt(); reader.RemainingBytes = reader.NextInt(); try { switch (channel) { case (uint)ChannelID.RegisterLink: ShardID remoteID = reader.NextShardID(); ShardID localID = reader.NextShardID(); if (localID != Simulation.ID) { throw new IntegrityViolation("Remote shard expected this shard to be " + localID + ", not " + Simulation.ID); } var lnk = linkLookup?.Invoke(remoteID); if (lnk == null) { throw new IntegrityViolation("Remote shard identifies as " + remoteID + ", but this is not a known neighbor of this shard " + Simulation.ID); } lnk.SetPassiveClient(client); Abandon(); break; case (uint)ChannelID.RegisterReceiver: Guid guid = reader.NextGuid(); if (!guids.Contains(guid)) { Message("Authenticating as " + guid); guids.Add(guid); while (!guidMap.TryAdd(guid, this)) { InteractionLink link; if (guidMap.TryRemove(guid, out link)) { Message("Was already registered by " + link + ". Replacing..."); } } Message("Authenticated as " + guid); OnRegisterReceiver?.Invoke(guid); } break; case (uint)ChannelID.ShardLookup: { ShardID id = reader.NextShardID(); var addr = BaseDB.TryGetAddress(id); using (MemoryStream ms = new MemoryStream()) { var str = Encoding.ASCII.GetBytes(addr.Host); ms.Write(id.AsBytes, 0, 16); ms.Write(BitConverter.GetBytes(str.Length), 0, 4); ms.Write(str, 0, str.Length); ms.Write(BitConverter.GetBytes((ushort)addr.PeerPort), 0, 2); Send(new OutPackage((uint)ChannelID.ShardLookupResponse, ms.ToArray())); } } break; case (uint)ChannelID.UnregisterReceiver: { guid = reader.NextGuid(); if (guids.Contains(guid)) { Message("De-Authenticating as " + guid); guids.Remove(guid); guidMap.TryRemove(guid); OnUnregisterReceiver?.Invoke(guid); } } break; case (uint)ChannelID.SendMessage: { Guid from = reader.NextGuid(); Guid to = reader.NextGuid(); Guid id = reader.NextGuid(); int msgChannel = reader.NextInt(); byte[] data = reader.NextBytes(); //int targetGen = Simulation.EstimateNextSuitableMessageTargetGeneration(); if (!guids.Contains(from)) { Error("Not registered as " + from + ". Ignoring message"); } else { //int gen = Simulation.Stack.NewestFinishedSDSGeneration; ClientMessage msg = new ClientMessage(new ClientMessageID(from, to, id, msgChannel, orderIndex), data); var sender = new Address(this.endPoint); Simulation.Consensus?.Dispatch(msg, sender); OnMessage?.Invoke(msg, sender); } } break; } } catch (SerializationException ex) { Error(ex); } reader.SkipRemaining(); } } catch (SocketException) {} catch (Exception ex) { Error(ex); } Close(); }
static void Main(string[] args) { //RunStupidModel(); //return; if (args.Length < 2) { Console.Error.WriteLine("Usage: shard <db url> <my addr> | shard <db url> --setup"); return; } try { int at = 0; var dbHost = new Address(args[at++]); BaseDB.Connect(dbHost); //,"admin","1234"); ShardID addr = ShardID.Decode(args[at++]); bool haveConfig = BaseDB.BeginPullConfig(addr.XYZ); if (!haveConfig) { Log.Error("Failed to establish connection to database"); Environment.Exit(-1); } Log.Message("Setting up clock"); Clock.NTPHost = BaseDB.Config.ntp; while (Clock.NumQueries < 1) { Thread.Sleep(100); } Log.Message("Starting up"); #if DRY_RUN if (addr == new ShardID()) //root { Log.Message("Resetting timer"); while (true) { Thread.Sleep(100); var t = BaseDB.Timing; if (t == null) { continue; } var n = Clock.Now + TimeSpan.FromSeconds(10); t.startTime = n.ToShortDateString() + " " + n.ToLongTimeString(); t.msGenerationBudget = 3000; //make sure we compute slowly BaseDB.Timing = t; break; } } #endif if ((addr.XYZ >= BaseDB.Config.extent).Any) { throw new ArgumentOutOfRangeException("addr", addr, "Exceeds extent: " + BaseDB.Config.extent); } if ((addr < ShardID.Zero).Any) { throw new ArgumentOutOfRangeException("addr", addr, "Is (partially) negative"); } Simulation.Run(addr); } catch (Exception ex) { Log.Error(ex); } }