use rand::RngExt;
use rocketmq_model::common::message::message_queue::MessageQueue;
use rocketmq_model::common::message::MessageTrait;
use crate::producer::message_queue_selector::MessageQueueSelector;
#[derive(Debug, Clone, Copy, Default)]
pub struct SelectMessageQueueByRandom;
impl SelectMessageQueueByRandom {
pub fn new() -> Self {
Self
}
}
impl<M, A> MessageQueueSelector<M, A> for SelectMessageQueueByRandom
where
M: MessageTrait,
{
#[inline]
fn select(&self, mqs: &[MessageQueue], _msg: &M, _arg: &A) -> Option<MessageQueue> {
if mqs.is_empty() {
return None;
}
let mut rng = rand::rng();
let index = rng.random_range(0..mqs.len());
mqs.get(index).cloned()
}
}
#[cfg(test)]
mod tests {
use rocketmq_model::common::message::message_queue::MessageQueue;
use rocketmq_model::common::message::message_single::Message;
use super::*;
#[test]
fn test_select_message_queue_by_random() {
let selector = SelectMessageQueueByRandom::new();
let queues = vec![
MessageQueue::from_parts("test_topic", "broker-a", 0),
MessageQueue::from_parts("test_topic", "broker-a", 1),
MessageQueue::from_parts("test_topic", "broker-a", 2),
MessageQueue::from_parts("test_topic", "broker-a", 3),
];
let msg = Message::builder().topic("test_topic").build().unwrap();
let selected = selector.select(&queues, &msg, &());
assert!(selected.is_some());
assert!(queues.contains(&selected.unwrap()));
}
#[test]
fn test_select_empty_queue_list() {
let selector = SelectMessageQueueByRandom::new();
let queues: Vec<MessageQueue> = vec![];
let msg = Message::builder().topic("test_topic").build().unwrap();
let selected = selector.select(&queues, &msg, &());
assert!(selected.is_none());
}
#[test]
fn test_select_single_queue() {
let selector = SelectMessageQueueByRandom::new();
let queues = vec![MessageQueue::from_parts("test_topic", "broker-a", 0)];
let msg = Message::builder().topic("test_topic").build().unwrap();
let selected = selector.select(&queues, &msg, &());
assert_eq!(selected.unwrap().queue_id(), 0);
}
#[test]
fn test_random_distribution() {
let selector = SelectMessageQueueByRandom::new();
let queues = vec![
MessageQueue::from_parts("test_topic", "broker-a", 0),
MessageQueue::from_parts("test_topic", "broker-a", 1),
MessageQueue::from_parts("test_topic", "broker-a", 2),
MessageQueue::from_parts("test_topic", "broker-a", 3),
];
let msg = Message::builder().topic("test_topic").build().unwrap();
let mut queue_counts = std::collections::HashMap::new();
for _ in 0..1000 {
if let Some(queue) = selector.select(&queues, &msg, &()) {
*queue_counts.entry(queue.queue_id()).or_insert(0) += 1;
}
}
assert_eq!(queue_counts.len(), 4);
for &count in queue_counts.values() {
assert!(count > 100);
assert!(count < 400);
}
}
#[test]
fn test_randomness() {
let selector = SelectMessageQueueByRandom::new();
let queues = vec![
MessageQueue::from_parts("test_topic", "broker-a", 0),
MessageQueue::from_parts("test_topic", "broker-a", 1),
MessageQueue::from_parts("test_topic", "broker-a", 2),
MessageQueue::from_parts("test_topic", "broker-a", 3),
];
let msg = Message::builder().topic("test_topic").build().unwrap();
let mut selections = Vec::new();
for _ in 0..10 {
if let Some(queue) = selector.select(&queues, &msg, &()) {
selections.push(queue.queue_id());
}
}
let unique_selections: std::collections::HashSet<_> = selections.iter().collect();
assert!(unique_selections.len() > 1);
}
}