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. Hide JSP error icons in Eclipse

    down voteaccepted Can can either configure this at workspace level or overwrite at web project level ...

  2. errno.h

    linux 中c语言使用errno.h头文件来记录错误信息以及定义返回错误代码的宏. strerror(errno)打印错误信息 1. warning: implicit declaration of ...

  3. 使用微信web开发者工具调试微信企业号页面(前端页面,已发布在服务器上的)

    前几天写了一篇使用fiddler调试微信端页面的,然后博友评论说使用fiddler太麻烦了,推荐使用微信web开发者工具调试微信页面,这两天弄着玩了一下,很强大.这篇文章只是做一个记录,方便自己以后使 ...

  4. NYOJ题目28大数阶乘

    -------------------------------------祭出BigInteger AC代码: import java.math.BigInteger; import java.uti ...

  5. poj 3728(LCA + dp)

    题目链接:http://poj.org/problem?id=3728 思路:题目的意思是求树上a -> b的路径上的最大收益(在最小值买入,在最大值卖出). 我们假设路径a - > b ...

  6. python处理地理数据-geopandas和pyshp

    这边博客并不是有关geopandas的教程和pyshp的教程! 使用python来处理地理数据有很多相关的包,最近研究需要处理一些地理数据,然而arcgis的arcpy总是不能令人满意.所以这里说说p ...

  7. redis数据类型之—String

    (1)String 简单介绍 string是redis中最基本的数据类型,一个字符串类型的值存储的最大容量是1GB. (2)String 常用命令

  8. ASP.NET 你必须知道的EF知识和经验

    原文:http://www.cnblogs.com/zhaopei/p/5721789.html

  9. WPF中的动画——(三)时间线(TimeLine)

    WPF中的动画——(三)时间线(TimeLine) 时间线(TimeLine)表示时间段. 它提供的属性可以让控制该时间段的长度.开始时间.重复次数.该时间段内时间进度的快慢等等.在WPF中内置了如下 ...

  10. [转]webpack进阶构建项目(一)

    阅读目录 1.理解webpack加载器 2.html-webpack-plugin学习 3.压缩js与css 4.理解less-loader加载器的使用 5.理解babel-loader加载器 6.理 ...