queue.declare即申请队列,首先对队列名作处理,若未指定队列名则随机生成一个,然后查询数据库队列是否已经创建,若创建完成则会申请队列返回

handle_method(#'queue.declare'{queue       = QueueNameBin,
passive = false,
durable = DurableDeclare,
exclusive = ExclusiveDeclare,
auto_delete = AutoDelete,
nowait = NoWait,
arguments = Args} = Declare,
_, State = #ch{virtual_host = VHostPath,
conn_pid = ConnPid,
queue_collector_pid = CollectorPid}) ->
Owner = case ExclusiveDeclare of
true -> ConnPid;
false -> none
end,
Durable = DurableDeclare andalso not ExclusiveDeclare,
ActualNameBin = case QueueNameBin of
<<>> -> rabbit_guid:binary(rabbit_guid:gen_secure(),
"amq.gen");
Other -> check_name('queue', Other)
end,
QueueName = rabbit_misc:r(VHostPath, queue, ActualNameBin),
check_configure_permitted(QueueName, State),
%%查找是否队列是否已经存在
case rabbit_amqqueue:with(
QueueName,
fun (Q) -> ok = rabbit_amqqueue:assert_equivalence(
Q, Durable, AutoDelete, Args, Owner),
maybe_stat(NoWait, Q)
end) of
{ok, MessageCount, ConsumerCount} ->
return_queue_declare_ok(QueueName, NoWait, MessageCount,
ConsumerCount, State);
{error, not_found} ->
DlxKey = <<"x-dead-letter-exchange">>,
case rabbit_misc:r_arg(VHostPath, exchange, Args, DlxKey) of
undefined ->
ok;
{error, {invalid_type, Type}} ->
precondition_failed(
"invalid type '~s' for arg '~s' in ~s",
[Type, DlxKey, rabbit_misc:rs(QueueName)]);
DLX ->
check_read_permitted(QueueName, State),
check_write_permitted(DLX, State),
ok
end,
case rabbit_amqqueue:declare(QueueName, Durable, AutoDelete,
Args, Owner) of
{new, #amqqueue{pid = QPid}} ->
%% We need to notify the reader within the channel
%% process so that we can be sure there are no
%% outstanding exclusive queues being declared as
%% the connection shuts down.
ok = case Owner of
none -> ok;
_ -> rabbit_queue_collector:register(
CollectorPid, QPid)
end,
return_queue_declare_ok(QueueName, NoWait, 0, 0, State);
{existing, _Q} ->
%% must have been created between the stat and the
%% declare. Loop around again.
handle_method(Declare, none, State);
{absent, Q, Reason} ->
rabbit_misc:absent(Q, Reason);
{owner_died, _Q} ->
%% Presumably our own days are numbered since the
%% connection has died. Pretend the queue exists though,
%% just so nothing fails.
return_queue_declare_ok(QueueName, NoWait, 0, 0, State)
end;
{error, {absent, Q, Reason}} ->
rabbit_misc:absent(Q, Reason)
end;

rabbit_amqqueue.erl

其中的node()是为了指明master queue的位置,即收到申请队列消息的节点

declare(QueueName, Durable, AutoDelete, Args, Owner) ->
declare(QueueName, Durable, AutoDelete, Args, Owner, node()).
选择主节点并对主节点发创建队列进程的消息
declare(QueueName, Durable, AutoDelete, Args, Owner, Node) ->
ok = check_declare_arguments(QueueName, Args),
Q = rabbit_queue_decorator:set(
rabbit_policy:set(#amqqueue{name = QueueName,
durable = Durable,
auto_delete = AutoDelete,
arguments = Args,
exclusive_owner = Owner,
pid = none,
slave_pids = [],
sync_slave_pids = [],
recoverable_slaves = [],
gm_pids = [],
state = live})),
Node = rabbit_mirror_queue_misc:initial_queue_node(Q, Node),
gen_server2:call(
rabbit_amqqueue_sup_sup:start_queue_process(Node, Q, declare),
{init, new}, infinity).

rabbit_amqqueue_sup.erl

在启动rabbit_amqp_process的时候,supervisor使用的Maker来标志此进程是否首次启动,以区别重启进程来做不同操作 。

start_link(Q, StartMode) ->
%%Marker存在的意义是什么?标志着是否为第一次启动
Marker = spawn_link(fun() -> receive stop -> ok end end),
ChildSpec = {rabbit_amqqueue,
{rabbit_prequeue, start_link, [Q, StartMode, Marker]},
intrinsic, ?MAX_WAIT, worker, [rabbit_amqqueue_process,
rabbit_mirror_queue_slave]},
{ok, SupPid} = supervisor2:start_link(?MODULE, []),
{ok, QPid} = supervisor2:start_child(SupPid, ChildSpec),
unlink(Marker),
Marker ! stop,
{ok, SupPid, Qpid}.

之后,主节点会启动rabbit_amqp_process,用coordinator来完成数据同步(gm),而备节点则会启动rabbit_mirror_queue_slave进程,后者同时使用了gm behaviour,所以可以和coordinator来进程数据同步,以mq节点之间状态保持一致。

通过coordinator获取gm完成可靠同步,然后获取备节点在备节点增加镜像队列

init_with_existing_bq(Q = #amqqueue{name = QName}, BQ, BQS) ->
{ok, CPid} = rabbit_mirror_queue_coordinator:start_link(
Q, undefined, sender_death_fun(), depth_fun()),
GM = rabbit_mirror_queue_coordinator:get_gm(CPid),
Self = self(),
ok = rabbit_misc:execute_mnesia_transaction(
fun () ->
[Q1 = #amqqueue{gm_pids = GMPids}]
= mnesia:read({rabbit_queue, QName}),
ok = rabbit_amqqueue:store_queue(
Q1#amqqueue{gm_pids = [{GM, Self} | GMPids],
state = live})
end),

{_MNode, SNodes} = rabbit_mirror_queue_misc:suggested_queue_nodes(Q),

在所有的备节点上增加镜像队列,即创建备队列进程
    rabbit_mirror_queue_misc:add_mirrors(QName, SNodes, sync),
#state { name = QName,
gm = GM,
coordinator = CPid,
backing_queue = BQ,
backing_queue_state = BQS,
seen_status = dict:new(),
confirmed = [],
known_senders = sets:new() }. add_mirrors(QName, Nodes, SyncMode) ->
[add_mirror(QName, Node, SyncMode) || Node <- Nodes],
ok. add_mirror(QName, MirrorNode, SyncMode) ->
case rabbit_amqqueue:lookup(QName) of
{ok, Q} ->
rabbit_misc:with_exit_handler(
rabbit_misc:const(ok),
fun () ->
SPid = rabbit_amqqueue_sup_sup:start_queue_process(
MirrorNode, Q, slave),
log_info(QName, "Adding mirror on node ~p: ~p~n",
[MirrorNode, SPid]),
rabbit_mirror_queue_slave:go(SPid, SyncMode)
end);
{error, not_found} = E ->
E
end.
未完成待续

rabbitmq method之queue.declare的更多相关文章

  1. rabbitmq之back queue草稿

    申请队列rabbit_reader在收到消息后处理数据帧时,如果channel id不是0(0代表连接),则认为是channel相关方法. handle_frame(Type, Channel, Pa ...

  2. rabbitmq method之basic.consume

    basic.consume指的是channel在 某个队列上注册消费者,那在这个队列有消息来了之后,就会把消息转发到给此channel处理,如果 这个队列有多个消费者,则会采用轮转的方式将消息分发给消 ...

  3. Java使用Rabbitmq惊喜队列queue和消息内容的本地持久化核心方法。(内容存储在硬盘)

    _Channel.queueDeclare(queue, true, false, false, null); _Channel.basicPublish(_ExchangeName, queue,M ...

  4. RabbitMQ的work queue(1)

    http://www.rabbitmq.com/tutorials/tutorial-two-java.html 在第一个教程中,我们通过一个命名队列来发送消息和接受消息.在这一节,我们将创建一个工作 ...

  5. RabbitMQ的work queue(2)

    课堂上work queue没能很好的理解,看了大神的博客,顿觉醍醐灌顶,豁然开朗. work queue有两种模式: 平均分配:(默认)//channel.basicQos(1);即把 同一时刻服务器 ...

  6. rabbitmq之amqp queue

    rabbitmq作为一个消息中间件,暂存信息的能力是必不可少的. 镜像队列

  7. RabbitMQ-从基础到实战(1)— Hello RabbitMQ

    转载请注明出处 1.简介 本篇博文介绍了在windows平台下安装RabbitMQ Server端,并用JAVA代码实现收发消息 2.安装RabbitMQ RabbitMQ是用Erlang开发的,所以 ...

  8. RabbitMQ channel 参数详解

    1.Channel 1.1 channel.exchangeDeclare(): type:有direct.fanout.topic三种durable:true.false true:服务器重启会保留 ...

  9. RabbitMQ中客户端的Channel类里各方法释义

    // The contents of this file are subject to the Mozilla Public License // Version 1.1 (the "Lic ...

随机推荐

  1. 命令行环境下简单实用的工具——重定向&管道

    如果你对管道和重定向应用自如了,无需继续往下看.本文虽然以windows上cmd命令行环境演示,但同样适用于Unix/Linux等平台. 引言 关于管道和重定向,最初是在刘汝佳的<算法竞赛入门经 ...

  2. Redirect url 路径简单介绍

    问题:Response.redirect 用法asp 中 用response.redirect () 跳转到不同的页面是怎么写的,比如从index.asp跳到admin目录下的a.asp 还有从a跳回 ...

  3. NavigationController

    前面的一篇文章<iOS开发16:使用Navigation Controller切换视图>中的小例子在运行时,屏幕上方出现的工具栏就是Navigation Bar,而所谓UINavigati ...

  4. Caffe初试(二)windows下的cafee训练和测试mnist数据集

    一.mnist数据集 mnist是一个手写数字数据库,由Google实验室的Corinna Cortes和纽约大学柯朗研究院的Yann LeCun等人建立,它有60000个训练样本集和10000个测试 ...

  5. Android开发之---Activity生命周期

    Android开发中,有四大组件:Activity.Service.Content Provider.Broadcast Receiver,可以说,activity的使用是最频繁的了,这里来梳理一下与 ...

  6. 进击的Python【第一章】:Python背景初探与Python基础(一)

    Python背景初探 一.Python起源 Python的创始人为Guido van Rossum.1989年圣诞节期间,在阿姆斯特丹,Guido为了打发圣诞节的无趣,决心开发一个新的脚本解释程序,做 ...

  7. Js-知识小总结

    1.给标签价 class属性的时候,记住是 ClassName, 例如:var oImg = document.getElementById('img1'); 要给这个对象价class属性 oimg. ...

  8. windows查看端口占用情况

    1,查看指定端口被哪个进程占用. >netstat -ano|findstr 8008 TCP    127.0.0.1:8083         0.0.0.0:0              ...

  9. 如何打开 系统信息窗体和 DirectX诊断工具

    开始---运行----msinfo32.exe 运行 位于C:\Program Files\Common Files\Microsoft Shared\Msinfo\msinfo32.exe,显示计算 ...

  10. python 获取日期

    转载   原文:python 获取日期 作者:m4774411wang python 获取日期我们需要用到time模块,比如time.strftime方法 time.strftime('%Y-%m-% ...