// Enqueue an update // Note that only one update for each id is queued so it is possible that this particular // update will not get queued if there is already one queued for that id. // Returns 'true' if the object was actually enqueued. public bool Enqueue(UUID id, SyncMsg update) { bool ret = false; lock(m_syncRoot) { if (!m_updates.ContainsKey(id)) { m_queue.Enqueue(id); m_updates[id] = update; ret = true; } else { OverWrittenUpdates++; // If this is an update, we merge our update flags SyncMsgUpdatedProperties updatedPropMsg = update as SyncMsgUpdatedProperties; SyncMsgUpdatedProperties existingUpdatedPropMsg = m_updates[id] as SyncMsgUpdatedProperties; if (updatedPropMsg != null && existingUpdatedPropMsg != null) { existingUpdatedPropMsg.AddUpdates(updatedPropMsg.SyncableProperties); } else { // It is very odd that it is not one of ours. Don't know how another type got into the list. } } Monitor.Pulse(m_syncRoot); } return ret; }
// Add a message to the first of the queue. public void QueueMessageFirst(SyncMsg update) { lock (m_syncRoot) { m_firstQueue.Enqueue(update); Monitor.Pulse(m_syncRoot); } }
//Send out a messge directly. This should only by called for short messages that are not sent frequently. //Don't call this function for sending out updates. Call EnqueueOutgoingUpdate instead private void Send(SyncMsg msg) { // m_log.DebugFormat("{0} Send msg: {1}: {2}", LogHeader, this.Description, msg.ToString()); if (m_tcpConnection.Connected) { try { byte[] data = msg.GetWireBytes(); CollectSendStat(msg.MType.ToString(), msg.DataLength); // Rather than async write, use the TCP flow control to stop this thread if the // receiver cannot consume the data quick enough. m_tcpConnection.GetStream().Write(data, 0, data.Length); m_lastSendTime = DateTime.Now; /* m_tcpConnection.GetStream().BeginWrite(data, 0, data.Length, ar => { if (m_tcpConnection.Connected) { try { m_tcpConnection.GetStream().EndWrite(ar); } catch (Exception) { } } }, null); */ } catch (Exception e) { m_log.ErrorFormat("{0}:Error in Send() {1}/{2} has disconnected: connector={3}, msgType={4}. e={5}", LogHeader, otherSideActorID, otherSideRegionName, m_connectorNum, msg.MType.ToString(), e); Shutdown(); } } }
private void HandleMessage(SyncMsg msg) { // m_log.DebugFormat("{0} Recv msg: {1}: {2}", LogHeader, this.Description, msg.ToString()); CollectReceiveStat(msg.MType.ToString(), msg.DataLength); // TODO: Consider doing the data unpacking on a different thread than the input reader thread try { msg.ConvertIn(m_regionSyncModule); } catch (Exception e) { if (msg == null) { m_log.ErrorFormat("{0} Exception converting msg: NULL MESSAGE: {1}", LogHeader, e); } else { m_log.ErrorFormat("{0} Exception converting msg: type={1},len={2}: {3}", LogHeader, msg.MType, msg.DataLength, e); } } // TODO: Consider doing the message processing on a different thread than the input reader thread try { msg.HandleIn(m_regionSyncModule); } catch (Exception e) { if (msg == null) { m_log.ErrorFormat("{0} Exception handling msg: NULL MESSAGE: {1}", LogHeader, e); } else { m_log.ErrorFormat("{0} Exception handling msg: type={1},len={2}: {3}", LogHeader, msg.MType, msg.DataLength, e); } } // If this is an initialization message, print out info and start stats gathering if initialized enough if (msg.MType == SyncMsg.MsgType.RegionName || msg.MType == SyncMsg.MsgType.ActorID) { switch (msg.MType) { case SyncMsg.MsgType.RegionName: m_log.DebugFormat("Syncing to region \"{0}\"", otherSideRegionName); break; case SyncMsg.MsgType.ActorID: m_log.DebugFormat("Syncing to actor \"{0}\"", otherSideActorID); break; } if (otherSideRegionName != null && otherSideActorID != null) StartCollectingStats(); } }
public bool KeepAlive(SyncMsg msg) { TimeSpan timePassed = DateTime.Now - m_lastSendTime; if (timePassed.TotalMilliseconds > KeepAliveMaxInterval) { ImmediateOutgoingMsg(msg); return true; } else return false; }
// Queue the outgoing message so it it sent "now" and before update messages. public void ImmediateOutgoingMsg(SyncMsg msg) { msg.LogTransmission(this); // The new way is to add a first queue and to place this message at the front. m_outQ.QueueMessageFirst(msg); if (m_collectingStats) currentQueue.Event(1); }
/// <summary> /// Enqueue update of an object/avatar into the outgoing queue, and return right away /// </summary> /// <param name="id">UUID of the object/avatar</param> /// <param name="update">the update infomation in byte format</param> public void EnqueueOutgoingUpdate(UUID id, SyncMsg update) { // m_log.DebugFormat("{0} Enqueue msg {1}", LogHeader, update.ToString()); update.LogTransmission(this); // Enqueue is thread safe bool actuallyQueued = m_outQ.Enqueue(id, update); /* BEGIN DEBUG if (!actuallyQueued) { SyncMsgUpdatedProperties upd = update as SyncMsgUpdatedProperties; m_log.DebugFormat("{0} EnqueueOutgoingUpdate. Multiple update. UUID={1}, prop={2}", LogHeader, upd.Uuid, upd.PropsAsString()); } END DEBUG */ if (actuallyQueued && m_collectingStats) currentQueue.Event(1); }