/// <summary> /// Loops through all of the packet queues for this client and tries to send /// an outgoing packet from each, obeying the throttling bucket limits /// </summary> /// /// <remarks> /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the /// wind queue). /// /// This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe /// </remarks> /// /// <returns>True if any packets were sent, otherwise false</returns> public bool DequeueOutgoing() { OutgoingPacket packet; OpenSim.Framework.LocklessQueue <OutgoingPacket> queue; TokenBucket bucket; bool packetSent = false; ThrottleOutPacketTypeFlags emptyCategories = 0; //string queueDebugOutput = String.Empty; // Serious debug business for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { bucket = m_throttleCategories[i]; //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business if (m_nextPackets[i] != null) { // This bucket was empty the last time we tried to send a packet, // leaving a dequeued packet still waiting to be sent out. Try to // send it again OutgoingPacket nextPacket = m_nextPackets[i]; if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(nextPacket); m_nextPackets[i] = null; packetSent = true; } } else { // No dequeued packet waiting to be sent, try to pull one off // this queue queue = m_packetOutboxes[i]; if (queue.Dequeue(out packet)) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (bucket.RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; } else { // Save the dequeued packet for the next iteration m_nextPackets[i] = packet; } // If the queue is empty after this dequeue, fire the queue // empty callback now so it has a chance to fill before we // get back here if (queue.Count == 0) { emptyCategories |= CategoryToFlag(i); } } else { // No packets in this queue. Fire the queue empty callback // if it has not been called recently emptyCategories |= CategoryToFlag(i); } } } if (emptyCategories != 0) { BeginFireQueueEmpty(emptyCategories); } //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return(packetSent); }
/// <summary> /// Loops through all of the packet queues for this client and tries to send /// an outgoing packet from each, obeying the throttling bucket limits /// </summary> /// /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the /// wind queue). /// /// <remarks>This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe</remarks> /// <returns>True if any packets were sent, otherwise false</returns> public bool DequeueOutgoing (int MaxNPacks) { OutgoingPacket packet; bool packetSent = false; ThrottleOutPacketTypeFlags emptyCategories = 0; if (m_nextOutPackets != null) { OutgoingPacket nextPacket = m_nextOutPackets; if (m_throttle.RemoveTokens (nextPacket.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal (nextPacket); m_nextOutPackets = null; packetSent = true; this.PacketsSent++; } } else { // No dequeued packet waiting to be sent, try to pull one off // this queue if (m_outbox.Dequeue (out packet)) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (packet.Category == ThrottleOutPacketType.OutBand || m_throttle.RemoveTokens (packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal (packet); packetSent = true; if (m_throttle.MaxBurst < TotalRateRequested) { float tmp = (float)m_throttle.MaxBurst * 1.005f; m_throttle.DripRate = (int)tmp; m_throttle.MaxBurst = (int)tmp; } this.PacketsSent++; } else { m_nextOutPackets = packet; } } else { emptyCategories = (ThrottleOutPacketTypeFlags)0xffff; } } if (m_outbox.count < 100) { emptyCategories = (ThrottleOutPacketTypeFlags)0xffff; BeginFireQueueEmpty (emptyCategories); } /* if (emptyCategories != 0) BeginFireQueueEmpty(emptyCategories); else { int i = MapCatsToPriority[(int)ThrottleOutPacketType.Texture]; // hack to keep textures flowing for now if (m_outbox.queues[i].Count < 30) { emptyCategories |= ThrottleOutPacketTypeFlags.Texture; } } */ //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return packetSent; /* OutgoingPacket packet; OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; TokenBucket bucket; bool packetSent = false; ThrottleOutPacketTypeFlags emptyCategories = 0; //string queueDebugOutput = String.Empty; // Serious debug business int npacksTosent = MaxNPacks; int i = m_lastthrottleCategoryChecked; for (int j = 0; j < (int)ThrottleOutPacketType.OutBand; j++) // don't check OutBand { bucket = m_throttleCategories[i]; //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business if (m_nextPackets[i] != null) { // This bucket was empty the last time we tried to send a packet, // leaving a dequeued packet still waiting to be sent out. Try to // send it again OutgoingPacket nextPacket = m_nextPackets[i]; if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(nextPacket); m_nextPackets[i] = null; packetSent = true; this.PacketsSent++; } } else { // No dequeued packet waiting to be sent, try to pull one off // this queue queue = m_packetOutboxes[i]; if (queue.Dequeue(out packet)) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (bucket.RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; this.PacketsSent++; } else { // Save the dequeued packet for the next iteration m_nextPackets[i] = packet; } // If the queue is empty after this dequeue, fire the queue // empty callback now so it has a chance to fill before we // get back here if (queue.Count == 0) emptyCategories |= CategoryToFlag(i); } else { // No packets in this queue. Fire the queue empty callback // if it has not been called recently emptyCategories |= CategoryToFlag(i); } } if (++i >= (int)ThrottleOutPacketType.OutBand) i = 0; if (--npacksTosent <= 0) break; } m_lastthrottleCategoryChecked = i; // send at least one outband packet if (npacksTosent <= 0) npacksTosent = 1; i = (int)ThrottleOutPacketType.OutBand; while (npacksTosent > 0) { //outband has no tokens checking and no throttle // No dequeued packet waiting to be sent, try to pull one off // this queue queue = m_packetOutboxes[i]; if (queue.Dequeue(out packet)) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out // if (bucket.RemoveTokens(packet.Buffer.DataLength)) // { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; this.PacketsSent++; // } // else // { // Save the dequeued packet for the next iteration // m_nextPackets[i] = packet; // } // If the queue is empty after this dequeue, fire the queue // empty callback now so it has a chance to fill before we // get back here if (queue.Count == 0) emptyCategories |= CategoryToFlag(i); } else { // No packets in this queue. Fire the queue empty callback // if it has not been called recently emptyCategories |= CategoryToFlag(i); break; } npacksTosent--; } if (emptyCategories != 0) BeginFireQueueEmpty(emptyCategories); //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return packetSent; */ }
/// <summary> /// Loops through all of the packet queues for this client and tries to send /// an outgoing packet from each, obeying the throttling bucket limits /// </summary> /// /// <remarks> /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the /// wind queue). /// /// This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe /// </remarks> /// /// <returns>True if any packets were sent, otherwise false</returns> public bool DequeueOutgoing() { // if (m_deliverPackets == false) return false; OutgoingPacket packet = null; DoubleLocklessQueue <OutgoingPacket> queue; bool packetSent = false; ThrottleOutPacketTypeFlags emptyCategories = 0; //string queueDebugOutput = String.Empty; // Serious debug business // do resends packet = m_nextPackets[0]; if (packet != null) { if (packet.Buffer != null) { if (m_throttleCategories[0].RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; m_nextPackets[0] = null; } } else { m_nextPackets[0] = null; } } else { queue = m_packetOutboxes[0]; if (queue != null) { if (queue.Dequeue(out packet)) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (packet.Buffer != null) { if (m_throttleCategories[0].RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; } else { // Save the dequeued packet for the next iteration m_nextPackets[0] = packet; } } } } else { m_packetOutboxes[0] = new DoubleLocklessQueue <OutgoingPacket>(); } } if (NeedAcks.Count() > 50) { Interlocked.Increment(ref AckStalls); return(true); } for (int i = 1; i < THROTTLE_CATEGORY_COUNT; i++) { //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business packet = m_nextPackets[i]; if (packet != null) { if (packet.Buffer == null) { if (m_packetOutboxes[i].Count < 5) { emptyCategories |= CategoryToFlag(i); } m_nextPackets[i] = null; continue; } if (m_throttleCategories[i].RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); m_nextPackets[i] = null; packetSent = true; if (m_packetOutboxes[i].Count < 5) { emptyCategories |= CategoryToFlag(i); } } } else { // No dequeued packet waiting to be sent, try to pull one off // this queue queue = m_packetOutboxes[i]; if (queue.Dequeue(out packet)) { if (packet.Buffer == null) { // packet canceled elsewhere (by a ack for example) if (queue.Count < 5) { emptyCategories |= CategoryToFlag(i); } continue; } if (m_throttleCategories[i].RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; if (queue.Count < 5) { emptyCategories |= CategoryToFlag(i); } } else { // Save the dequeued packet for the next iteration m_nextPackets[i] = packet; } } else { // No packets in this queue. Fire the queue empty callback // if it has not been called recently emptyCategories |= CategoryToFlag(i); } } } if (emptyCategories != 0) { BeginFireQueueEmpty(emptyCategories); } //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return(packetSent); }
/// <summary> /// Loops through all of the packet queues for this client and tries to send /// an outgoing packet from each, obeying the throttling bucket limits /// </summary> /// /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the /// wind queue). /// /// <remarks>This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe</remarks> /// <returns>True if any packets were sent, otherwise false</returns> public bool DequeueOutgoing(int MaxNPacks) { OutgoingPacket packet; bool packetSent = false; for (int i = 0; i < MaxNPacks; i++) { if (m_nextOutPackets != null) { OutgoingPacket nextPacket = m_nextOutPackets; if (m_throttle.RemoveTokens(nextPacket.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(nextPacket); m_nextOutPackets = null; packetSent = true; this.PacketsSent++; } else { int prio = MapCatsToPriority[(int)nextPacket.Category]; prio++; if (prio > MapCatsToPriority.Length) { prio--; } m_outbox.Enqueue(prio, nextPacket); m_nextOutPackets = null; } } else { // No dequeued packet waiting to be sent, try to pull one off // this queue if (m_outbox.Dequeue(out packet)) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (packet.Category == ThrottleOutPacketType.OutBand || m_throttle.RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; if (m_throttle.MaxBurst < TotalRateRequested) { float tmp = (float)m_throttle.MaxBurst * 1.005f; m_throttle.DripRate = (int)tmp; m_throttle.MaxBurst = (int)tmp; } this.PacketsSent++; } else { m_nextOutPackets = packet; } } else { break; } } } if (m_outbox.count < 100 || m_lastEmptyUpdates > 10) { //if(m_outbox.count > 100) // MainConsole.Instance.Output(m_outbox.count.ToString(), log4net.Core.Level.Alert); m_lastEmptyUpdates = 0; BeginFireQueueEmpty(); } else { m_lastEmptyUpdates++; } //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return(packetSent); /* * * OutgoingPacket packet; * OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; * TokenBucket bucket; * bool packetSent = false; * ThrottleOutPacketTypeFlags emptyCategories = 0; * * //string queueDebugOutput = String.Empty; // Serious debug business * int npacksTosent = MaxNPacks; * * int i = m_lastthrottleCategoryChecked; * for (int j = 0; j < (int)ThrottleOutPacketType.OutBand; j++) // don't check OutBand * { * * bucket = m_throttleCategories[i]; * //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business * * if (m_nextPackets[i] != null) * { * // This bucket was empty the last time we tried to send a packet, * // leaving a dequeued packet still waiting to be sent out. Try to * // send it again * OutgoingPacket nextPacket = m_nextPackets[i]; * if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) * { * // Send the packet * m_udpServer.SendPacketFinal(nextPacket); * m_nextPackets[i] = null; * packetSent = true; * this.PacketsSent++; * } * } * else * { * // No dequeued packet waiting to be sent, try to pull one off * // this queue * queue = m_packetOutboxes[i]; * if (queue.Dequeue(out packet)) * { * // A packet was pulled off the queue. See if we have * // enough tokens in the bucket to send it out * if (bucket.RemoveTokens(packet.Buffer.DataLength)) * { * // Send the packet * m_udpServer.SendPacketFinal(packet); * packetSent = true; * this.PacketsSent++; * } * else * { * // Save the dequeued packet for the next iteration * m_nextPackets[i] = packet; * } * * // If the queue is empty after this dequeue, fire the queue * // empty callback now so it has a chance to fill before we * // get back here * if (queue.Count == 0) * emptyCategories |= CategoryToFlag(i); * } * else * { * // No packets in this queue. Fire the queue empty callback * // if it has not been called recently * emptyCategories |= CategoryToFlag(i); * } * } * * if (++i >= (int)ThrottleOutPacketType.OutBand) * i = 0; * * if (--npacksTosent <= 0) * break; * } * * m_lastthrottleCategoryChecked = i; * * // send at least one outband packet * * if (npacksTosent <= 0) * npacksTosent = 1; * * i = (int)ThrottleOutPacketType.OutBand; * * while (npacksTosent > 0) * { * //outband has no tokens checking and no throttle * // No dequeued packet waiting to be sent, try to pull one off * // this queue * queue = m_packetOutboxes[i]; * if (queue.Dequeue(out packet)) * { * // A packet was pulled off the queue. See if we have * // enough tokens in the bucket to send it out * * // if (bucket.RemoveTokens(packet.Buffer.DataLength)) * // { * // Send the packet * m_udpServer.SendPacketFinal(packet); * packetSent = true; * this.PacketsSent++; * // } * // else * // { * // Save the dequeued packet for the next iteration * // m_nextPackets[i] = packet; * // } * * // If the queue is empty after this dequeue, fire the queue * // empty callback now so it has a chance to fill before we * // get back here * if (queue.Count == 0) * emptyCategories |= CategoryToFlag(i); * } * else * { * // No packets in this queue. Fire the queue empty callback * // if it has not been called recently * emptyCategories |= CategoryToFlag(i); * break; * } * npacksTosent--; * } * * if (emptyCategories != 0) * BeginFireQueueEmpty(emptyCategories); * * //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business * return packetSent; */ }
/// <summary> /// Loops through all of the packet queues for this client and tries to send /// an outgoing packet from each, obeying the throttling bucket limits /// </summary> /// /// <remarks> /// Packet queues are inspected in ascending numerical order starting from 0. Therefore, queues with a lower /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the /// wind queue). /// /// This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe /// </remarks> /// /// <returns>True if any packets were sent, otherwise false</returns> public bool DequeueOutgoing() { // if (m_deliverPackets == false) return false; OutgoingPacket packet = null; DoubleLocklessQueue <OutgoingPacket> queue; TokenBucket bucket; bool packetSent = false; ThrottleOutPacketTypeFlags emptyCategories = 0; //string queueDebugOutput = String.Empty; // Serious debug business for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { bucket = m_throttleCategories[i]; //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business if (m_nextPackets[i] != null) { // This bucket was empty the last time we tried to send a packet, // leaving a dequeued packet still waiting to be sent out. Try to // send it again OutgoingPacket nextPacket = m_nextPackets[i]; if (nextPacket.Buffer == null) { if (m_packetOutboxes[i].Count < 5) { emptyCategories |= CategoryToFlag(i); } continue; } if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(nextPacket); m_nextPackets[i] = null; packetSent = true; if (m_packetOutboxes[i].Count < 5) { emptyCategories |= CategoryToFlag(i); } } } else { // No dequeued packet waiting to be sent, try to pull one off // this queue queue = m_packetOutboxes[i]; if (queue != null) { bool success = false; try { success = queue.Dequeue(out packet); } catch { m_packetOutboxes[i] = new DoubleLocklessQueue <OutgoingPacket>(); } if (success) { // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (packet.Buffer == null) { // packet canceled elsewhere (by a ack for example) if (queue.Count < 5) { emptyCategories |= CategoryToFlag(i); } } else { if (bucket.RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); packetSent = true; if (queue.Count < 5) { emptyCategories |= CategoryToFlag(i); } } else { // Save the dequeued packet for the next iteration m_nextPackets[i] = packet; } } } else { // No packets in this queue. Fire the queue empty callback // if it has not been called recently emptyCategories |= CategoryToFlag(i); } } else { m_packetOutboxes[i] = new DoubleLocklessQueue <OutgoingPacket>(); emptyCategories |= CategoryToFlag(i); } } } if (emptyCategories != 0) { BeginFireQueueEmpty(emptyCategories); } //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business return(packetSent); }
/// <summary> /// tries to send queued packets /// </summary> /// <remarks> /// This function is only called from a synchronous loop in the /// UDPServer so we don't need to bother making this thread safe /// </remarks> /// <returns>True if any packets were sent, otherwise false</returns> public bool DequeueOutgoing(int MaxNPacks) { bool packetSent = false; for (int i = 0; i < MaxNPacks; i++) { OutgoingPacket packet; if (m_nextOutPacket != null) { packet = m_nextOutPacket; if (m_throttle.RemoveTokens(packet.Buffer.DataLength)) { // Send the packet m_udpServer.SendPacketFinal(packet); m_nextOutPacket = null; packetSent = true; } } // No dequeued packet waiting to be sent, try to pull one off // this queue else if (m_outbox.Dequeue(out packet)) { MainConsole.Instance.Output(AgentID + " - " + packet.Packet.Type, "Verbose"); // A packet was pulled off the queue. See if we have // enough tokens in the bucket to send it out if (packet.Category == ThrottleOutPacketType.OutBand || m_throttle.RemoveTokens(packet.Buffer.DataLength)) { packetSent = true; //Send the packet PacketsCounts[(int)packet.Category] += packet.Packet.Length; m_udpServer.SendPacketFinal(packet); PacketsSent++; } else { m_nextOutPacket = packet; break; } } else { break; } } if (packetSent) { if (m_throttle.MaxBurst < TotalRateRequested) { float tmp = m_throttle.MaxBurst * 1.005f; m_throttle.DripRate = (int)tmp; m_throttle.MaxBurst = (int)tmp; } } if (m_nextOnQueueEmpty != 0 && Util.EnvironmentTickCountSubtract(m_nextOnQueueEmpty) >= 0) { // Use a value of 0 to signal that FireQueueEmpty is running m_nextOnQueueEmpty = 0; // Asynchronously run the callback int ptmp = m_outbox.queues[MapCatsToPriority[(int)ThrottleOutPacketType.Task]].Count; int atmp = m_outbox.queues[MapCatsToPriority[(int)ThrottleOutPacketType.AvatarInfo]].Count; int ttmp = m_outbox.queues[MapCatsToPriority[(int)ThrottleOutPacketType.Texture]].Count; int[] arg = { ptmp, atmp, ttmp }; Util.FireAndForget(FireQueueEmpty, arg); } return(packetSent); }