Merge pull request #435 from emqtt/0.15

0.15 release - Support 500K+ subscribers to subscribe one topic
This commit is contained in:
Feng Lee 2016-01-24 17:54:01 +08:00
commit 214fb752d4
119 changed files with 1078 additions and 3018 deletions

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ log/
*.swp
*.so
examples
docs/build/*

3
.gitmodules vendored
View File

@ -19,3 +19,6 @@
[submodule "plugins/emqttd_recon"]
path = plugins/emqttd_recon
url = https://github.com/emqtt/emqttd_recon.git
[submodule "plugins/emqttd_plugin_redis"]
path = plugins/emqttd_plugin_redis
url = https://github.com/emqtt/emqttd_plugin_redis.git

View File

@ -2,6 +2,52 @@
emqttd ChangeLog
==================
0.15.0-beta(2016-01-28)
-------------------------
#### Highlights
Optimization for Route ETS insertion (#427)
Add Mongodb, Redis Plugins
Priority Message Queue Support
ReadTheDocs
#### Enhancements
Join/Leave the Cluster
Username Authentication: Default Users
Improve Cli commands: pubsub, bridges, trace
emqttd_mod_subscription: fix client_connected/3
#### BugFix
Fix dequeue/1 of emqttd_bridge...
Add emqttd:seed_now/0 function
#### Plugins
emqttd_plubin_mysql: changed mysql driver to mysql-otp
emqttd_plugin_pgsql: integrate with ecpool
emqttd_plugin_redis: first release
emqttd_plugin_mongo: first release
#### Benchmark
0.14.1-beta(2015-12-28)
-------------------------

View File

@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -5,11 +5,9 @@ emqttd is a massively scalable and clusterable MQTT V3.1/V3.1.1 broker written i
emqttd requires Erlang R17+ to build.
**DON'T compile the broker with Erlang/OTP R18.0 which introduced a [binary memory leak](http://erlang.org/pipermail/erlang-questions/2015-September/086098.html).**
Demo Server: tcp://t.emqtt.io:1883
Twitter: [@emqtt](https://twitter.com/emqtt)
Follow us on Twitter: [@emqtt](https://twitter.com/emqtt)
## Goals

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,55 +0,0 @@
## Transient Client/Session Sequence1
```
Client1->SM: {start_session, {true, ClientId, self()}}
SM-->Session: {destory, ClientId}
Session-->Session: {shutdown, destroy}
Session-->Client2: exit({shutdown, destroy})
Client2-->CM: {'DOWN', MRef, process, Pid, Reason}
SM-->Client1: {ok, SessPid}
Client1-->CM: {register, Client1}
```
![Transient Client/Session Sequence1](TransientSessionSeq1.png)
## Transient Client/Session Sequence2
```
Client1->SM: {start_session, {true, ClientId, self()}}
SM-->Session: {destory, ClientId}
Session-->Session: {shutdown, destroy}
SM-->Client1: {ok, SessPid}
Client1-->CM: {register, Client1}
Session-->Client2: exit({shutdown, destroy})
Client2-->CM: {'DOWN', MRef, process, Pid, Reason}
```
![Transient Client/Session Sequence2](TransientSessionSeq2.png)
## Persistent Client/Session Sequence1
```
Client1->SM: {start_session, {true, ClientId, self()}}
SM-->Session: {resume, ClientId, ClientPid}
Session-->Client2: {shutdown, conflict, {ClientId, Pid}}
Client2-->CM: {unregister, ClientId, self()}
SM-->Client1: {ok, SessPid}
Client1-->CM: {register, Client1}
```
![Persistent Client/Session Sequence1](PersistentSessionSeq1.png)
## Persistent Client/Session Sequence2
```
Client1->SM: {start_session, {true, ClientId, self()}}
SM-->Session: {resume, ClientId, ClientPid}
SM-->Client1: {ok, SessPid}
Client1-->CM: {register, Client1}
Session-->Client2: {shutdown, conflict, {ClientId, Pid}}
Client2-->CM: {unregister, ClientId, self()}
```
![Persistent Client/Session Sequence2](PersistentSessionSeq2.png)

View File

@ -1,847 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.13-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d7"/>
<node id="n0" yfiles.foldertype="group">
<data key="d4"/>
<data key="d5"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="334.0" width="357.5" x="211.25" y="155.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#F5F5F5" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" borderDistance="0.0" configuration="CroppingLabel" fontFamily="Dialog" fontSize="18" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="27.19921875" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="357.5" x="0.0" y="153.400390625">emqttd cluster</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="180.0" y="140.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 1</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0:">
<node id="n0::n0">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="226.25" y="170.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="309.25" y="223.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="268.25" y="223.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n3">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="249.25" y="254.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n4">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="284.25" y="254.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n5">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="284.25" y="193.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n6">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="428.75" y="170.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n7">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="511.75" y="223.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n8">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="470.75" y="223.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n9">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="451.75" y="254.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n10">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="486.75" y="254.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n11">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="486.75" y="193.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n12">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="226.25" y="350.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n13">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="309.25" y="403.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n14">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="268.25" y="403.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n15">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="249.25" y="434.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n16">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="284.25" y="434.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n17">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="284.25" y="373.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n18">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="428.75" y="350.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n19">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="511.75" y="403.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n20">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="470.75" y="403.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n21">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="451.75" y="434.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n22">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="486.75" y="434.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n23">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="486.75" y="373.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n1">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="81.75" y="209.5"/>
<y:Fill color="#3182BD" transparent="false"/>
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="81.75" y="389.5"/>
<y:Fill color="#756BB1" transparent="false"/>
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n3">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="654.25" y="209.5"/>
<y:Fill color="#756BB1" transparent="false"/>
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n4">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="654.25" y="389.5"/>
<y:Fill color="#3182BD" transparent="false"/>
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<edge id="n0::e0" source="n0::n0" target="n0::n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e1" source="n0::n0" target="n0::n12">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e2" source="n0::n0" target="n0::n18">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e3" source="n0::n2" target="n0::n5">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e4" source="n0::n3" target="n0::n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e5" source="n0::n4" target="n0::n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e6" source="n0::n5" target="n0::n1">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e7" source="n0::n6" target="n0::n18">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e8" source="n0::n8" target="n0::n11">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e9" source="n0::n9" target="n0::n8">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e10" source="n0::n10" target="n0::n8">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e11" source="n0::n11" target="n0::n7">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e12" source="n0::n12" target="n0::n18">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e13" source="n0::n12" target="n0::n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e14" source="n0::n14" target="n0::n17">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e15" source="n0::n15" target="n0::n14">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e16" source="n0::n16" target="n0::n14">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e17" source="n0::n17" target="n0::n13">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e18" source="n0::n20" target="n0::n23">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e19" source="n0::n21" target="n0::n20">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e20" source="n0::n22" target="n0::n20">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e21" source="n0::n23" target="n0::n19">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e0" source="n0::n18" target="n4">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#3182BD" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n1" target="n0::n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#3182BD" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n2" target="n0::n12">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#756BB1" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n0::n6" target="n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#756BB1" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources/>
</data>
</graphml>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,274 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.13-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d7"/>
<node id="n0">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="130.0" y="200.0"/>
<y:Fill color="#3182BD" transparent="false"/>
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="130.0" y="279.0"/>
<y:Fill color="#756BB1" transparent="false"/>
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.6328125" x="16.68359375" y="13.43359375">P<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="458.0" y="202.5"/>
<y:Fill color="#756BB1" transparent="false"/>
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n3">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="458.0" y="277.5"/>
<y:Fill color="#3182BD" transparent="false"/>
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.462890625" x="16.7685546875" y="13.43359375">S<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n4">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="250.0" y="193.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="333.0" y="246.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="292.0" y="246.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="273.0" y="277.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n8">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="308.0" y="277.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n9">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="308.0" y="216.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n0" target="n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="270.0" y="222.5"/>
<y:Point x="360.0" y="300.0"/>
</y:Path>
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
<y:Arrows source="none" target="plain"/>
<y:BendStyle smoothed="true"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n1" target="n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
<y:Point x="270.0" y="300.0"/>
<y:Point x="360.0" y="225.0"/>
</y:Path>
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
<y:Arrows source="none" target="plain"/>
<y:BendStyle smoothed="true"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n6" target="n9">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n7" target="n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n8" target="n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n9" target="n5">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources/>
</data>
</graphml>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@ -1,234 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:java="http://www.yworks.com/xml/yfiles-common/1.0/java" xmlns:sys="http://www.yworks.com/xml/yfiles-common/markup/primitives/2.0" xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.14.2-->
<key attr.name="Description" attr.type="string" for="graph" id="d0"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key for="graphml" id="d7" yfiles.type="resources"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d0"/>
<node id="n0">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="60.72000000000003" width="64.55999999999995" x="-371.08000000000004" y="-960.3600000000001"/>
<y:Fill color="#FFCC00" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="26.486054687499973" y="21.293593750000014">T<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="diamond"/>
</y:ShapeNode>
</data>
</node>
<node id="n1">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="30.0" x="-585.0" y="-945.0"/>
<y:Fill color="#CCFFCC" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="19.890625" x="5.0546875" y="5.93359375">C1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="30.0" x="-478.04" y="-945.0"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="18.05078125" x="5.974609375" y="5.93359375">S1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n3">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="30.0" x="-122.60000000000014" y="-945.0"/>
<y:Fill color="#CCFFCC" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="19.890625" x="5.0546875" y="5.93359375">C2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n4">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="30.0" width="30.0" x="-229.56000000000012" y="-945.0"/>
<y:Fill color="#99CCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="18.05078125" x="5.974609375" y="5.93359375">S2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="18.715277777777715" width="82.08333333333326" x="-255.60166666666674" y="-879.3576388888889"/>
<y:Fill color="#C0C0C0" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="41.587890625" x="20.24772135416663" y="0.29123263888891415">Queue<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="18.715277777777715" width="82.08333333333326" x="-504.08166666666665" y="-879.3576388888889"/>
<y:Fill color="#C0C0C0" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="41.587890625" x="20.24772135416663" y="0.29123263888891415">Queue<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="rectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="e0" source="n0" target="n4">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="54.8359375" x="6.2584301757812" y="-23.026406250000264">Dispatch<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n4" target="n3">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="44.41796875" x="13.971013183593755" y="-23.66640625000025">Deliver<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n1" target="n2">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="94.556640625" x="43.54167968749999" y="-36.46640625000032">Publish QoS1/2<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n2" target="n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n1" target="n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="-32.24675781249998" ty="0.0">
<y:Point x="-464.4087997380702" y="-990.0"/>
</y:Path>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="80.330078125" x="53.093395996093705" y="-79.45582275390632">Publish Qos0<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n4" target="n5">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n2" target="n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#000000" type="dashed" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d7">
<y:Resources/>
</data>
</graphml>

View File

@ -1,14 +0,0 @@
## QoS0 Publish Sequence
```
title QoS0 Publish Sequence
C1->PubSub: Publish QoS0
PubSub-->S2: Dispatch QoS0
S2-->C2: Deliver QoS0
```
## QoS1 Publish Sequence

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,993 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
<!--Created by yEd 3.13-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
<key for="port" id="d3" yfiles.type="portuserdata"/>
<key attr.name="url" attr.type="string" for="node" id="d4"/>
<key attr.name="description" attr.type="string" for="node" id="d5"/>
<key for="node" id="d6" yfiles.type="nodegraphics"/>
<key attr.name="Description" attr.type="string" for="graph" id="d7"/>
<key attr.name="url" attr.type="string" for="edge" id="d8"/>
<key attr.name="description" attr.type="string" for="edge" id="d9"/>
<key for="edge" id="d10" yfiles.type="edgegraphics"/>
<graph edgedefault="directed" id="G">
<data key="d7"/>
<node id="n0" yfiles.foldertype="group">
<data key="d4"/>
<data key="d6">
<y:ProxyAutoBoundsNode>
<y:Realizers active="0">
<y:GroupNode>
<y:Geometry height="334.0" width="357.5" x="242.0" y="185.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#F5F5F5" type="dashed" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="node_width" borderDistance="0.0" configuration="CroppingLabel" fontFamily="Dialog" fontSize="18" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="27.19921875" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="357.5" x="0.0" y="153.400390625">emqttd broker cluster</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="false" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="15" bottomF="15.0" left="15" leftF="15.0" right="15" rightF="15.0" top="15" topF="15.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
<y:GroupNode>
<y:Geometry height="50.0" width="50.0" x="180.0" y="140.0"/>
<y:Fill color="#F5F5F5" transparent="false"/>
<y:BorderStyle color="#000000" type="dashed" width="1.0"/>
<y:NodeLabel alignment="right" autoSizePolicy="node_width" backgroundColor="#EBEBEB" borderDistance="0.0" fontFamily="Dialog" fontSize="15" fontStyle="plain" hasLineColor="false" height="21.666015625" modelName="internal" modelPosition="t" textColor="#000000" visible="true" width="63.75830078125" x="-6.879150390625" y="0.0">Folder 1</y:NodeLabel>
<y:Shape type="roundrectangle"/>
<y:State closed="true" closedHeight="50.0" closedWidth="50.0" innerGraphDisplayEnabled="false"/>
<y:Insets bottom="5" bottomF="5.0" left="5" leftF="5.0" right="5" rightF="5.0" top="5" topF="5.0"/>
<y:BorderInsets bottom="0" bottomF="0.0" left="0" leftF="0.0" right="0" rightF="0.0" top="0" topF="0.0"/>
</y:GroupNode>
</y:Realizers>
</y:ProxyAutoBoundsNode>
</data>
<graph edgedefault="directed" id="n0:">
<node id="n0::n0">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="257.0" y="200.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="340.0" y="253.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="299.0" y="253.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="280.0" y="284.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="315.0" y="284.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n5">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="315.0" y="223.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n6">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="459.5" y="200.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n7">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="542.5" y="253.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n8">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="501.5" y="253.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n9">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="482.5" y="284.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n10">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="517.5" y="284.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n11">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="517.5" y="223.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n12">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="257.0" y="380.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n13">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="340.0" y="433.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n14">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="299.0" y="433.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n15">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="280.0" y="464.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n16">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="315.0" y="464.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n17">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="315.0" y="403.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n18">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="124.0" width="125.0" x="459.5" y="380.0"/>
<y:Fill color="#74C476" transparent="false"/>
<y:BorderStyle color="#74C476" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="60.5" y="60.0">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n19">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="542.5" y="433.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.587890625" x="2.2060546875" y="-0.56640625">#<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n20">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="501.5" y="433.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="13.5390625" x="1.23046875" y="-0.56640625">+<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n21">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="482.5" y="464.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="11.359375" x="2.3203125" y="-0.56640625">x<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n22">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="517.5" y="464.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="10.26953125" x="2.865234375" y="-0.56640625">y<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n0::n23">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="17.0" width="16.0" x="517.5" y="403.5"/>
<y:Fill color="#FD8D3C" transparent="false"/>
<y:BorderStyle color="#FD8D3C" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="8.48828125" x="3.755859375" y="-0.56640625">t<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
</graph>
</node>
<node id="n1">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="257.0" y="596.5"/>
<y:Fill color="#3182BD" transparent="false"/>
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="37.861328125" x="3.0693359375" y="13.43359375">Client<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n2">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="338.0" y="567.5"/>
<y:Fill color="#756BB1" transparent="false"/>
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="42.994140625" x="0.5029296875" y="13.43359375">Sensor<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n3">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="447.5" y="589.5"/>
<y:Fill color="#756BB1" transparent="false"/>
<y:BorderStyle color="#756BB1" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="42.994140625" x="0.5029296875" y="13.43359375">Sensor<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n4">
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="44.0" x="542.5" y="596.5"/>
<y:Fill color="#3182BD" transparent="false"/>
<y:BorderStyle color="#3182BD" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="37.861328125" x="3.0693359375" y="13.43359375">Client<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="ellipse"/>
</y:ShapeNode>
</data>
</node>
<node id="n5">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="64.0" width="357.5" x="242.0" y="58.0"/>
<y:Fill color="#BDBDBD" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="109.533203125" x="123.9833984375" y="22.933593750000014">Application Server<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n6">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="85.0" x="71.5" y="239.5"/>
<y:Fill color="#C0C0C0" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="28.50390625" x="28.248046875" y="13.43359375">Web<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n7">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="45.0" width="85.0" x="71.5" y="419.5"/>
<y:Fill color="#C0C0C0" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="28.50390625" x="28.248046875" y="13.43359375">Web<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n8">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="64.0" width="49.0" x="685.0" y="230.0"/>
<y:Fill color="#C0C0C0" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="43.052734375" x="2.9736328125" y="22.93359375">iPhone<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<node id="n9">
<data key="d5"/>
<data key="d6">
<y:ShapeNode>
<y:Geometry height="64.0" width="49.0" x="685.0" y="410.0"/>
<y:Fill color="#C0C0C0" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="50.58203125" x="-0.791015625" y="22.93359375">Android<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
</y:ModelParameter>
</y:NodeLabel>
<y:Shape type="roundrectangle"/>
</y:ShapeNode>
</data>
</node>
<edge id="n0::e0" source="n0::n0" target="n0::n6">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e1" source="n0::n0" target="n0::n12">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e2" source="n0::n2" target="n0::n5">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e3" source="n0::n3" target="n0::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e4" source="n0::n4" target="n0::n2">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e5" source="n0::n5" target="n0::n1">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e6" source="n0::n6" target="n0::n18">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e7" source="n0::n8" target="n0::n11">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e8" source="n0::n9" target="n0::n8">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e9" source="n0::n10" target="n0::n8">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e10" source="n0::n11" target="n0::n7">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e11" source="n0::n12" target="n0::n18">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#74C476" type="dashed" width="2.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e12" source="n0::n14" target="n0::n17">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e13" source="n0::n15" target="n0::n14">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e14" source="n0::n16" target="n0::n14">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e15" source="n0::n17" target="n0::n13">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e16" source="n0::n20" target="n0::n23">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e17" source="n0::n21" target="n0::n20">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e18" source="n0::n22" target="n0::n20">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="n0::e19" source="n0::n23" target="n0::n19">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FD8D3C" type="line" width="1.0"/>
<y:Arrows source="none" target="none"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e0" source="n0::n18" target="n4">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e1" source="n2" target="n0::n12">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e2" source="n0::n18" target="n3">
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-22.749321892003195" sy="57.76129269460557" tx="0.0" ty="0.0"/>
<y:LineStyle color="#756BB1" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="-31.872099564693826" y="37.92230224609375">MQTT<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e3" source="n5" target="n0::n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-101.25" sy="32.0078125" tx="0.0" ty="0.0"/>
<y:LineStyle color="#BDBDBD" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="34.626953125" x="-17.3134765625" y="29.92578125">HTTP<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e4" source="n5" target="n0::n6">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="101.25" sy="31.9765625" tx="0.0" ty="0.0"/>
<y:LineStyle color="#BDBDBD" type="dashed" width="2.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="-19.4169921875" y="29.92284393310547">MQTT<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e5" source="n6" target="n0::n0">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="66.671875" x="16.89422607421875" y="-9.06640625">WebSocket<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e6" source="n7" target="n0::n12">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="66.671875" x="16.89422607421875" y="-9.06640625">WebSocket<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e7" source="n0::n6" target="n8">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="30.8330078125" y="-9.06640625">MQTT<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e8" source="n0::n18" target="n9">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="30.8330078125" y="-9.06640625">MQTT<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
<edge id="e9" source="n1" target="n0::n12">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
<y:LineStyle color="#3182BD" type="dashed" width="1.0"/>
<y:Arrows source="standard" target="standard"/>
<y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="38.833984375" x="-8.698938402078966" y="-55.90826416015625">MQTT<y:LabelModel>
<y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
</y:LabelModel>
<y:ModelParameter>
<y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.5" segment="0"/>
</y:ModelParameter>
<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
</y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
</graph>
<data key="d0">
<y:Resources/>
</data>
</graphml>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

View File

@ -1,7 +0,0 @@
sup(one_for_all)
manager
pool_sup(one_for_one)
worker1
worker2
...
workerN

Binary file not shown.

View File

@ -1,19 +0,0 @@
## Mongodb ObjectId
* 4-byte value representing the seconds since the Unix epoch,
* 3-byte machine identifier,
* 2-byte process id, and
* 3-byte counter, starting with a random value.
## Flake Id
* 64bits Timestamp
* 48bits WorkerId
* 16bits Sequence
## emqttd Id
* 64bits Timestamp: erlang:now(), erlang:system_time
* 48bits (node+pid): Node + Pid -> Integer
* 16bits Sequence: PktId

0
docs/.placeholder Normal file
View File

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -28,7 +28,7 @@
%%------------------------------------------------------------------------------
%% Banner
%%------------------------------------------------------------------------------
-define(COPYRIGHT, "Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>").
-define(COPYRIGHT, "Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>").
-define(LICENSE_MESSAGE, "Licensed under MIT").

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% @Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>
%%% @Copyright (C) 2012-2016, Feng Lee <feng@emqtt.io>
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

@ -0,0 +1 @@
Subproject commit c6a532d49d2b479551bfd3b8d278d40c99e96ae3

View File

@ -85,9 +85,6 @@
{client, [
%% Socket is connected, but no 'CONNECT' packet received
{idle_timeout, 10} %% seconds
%TODO: Network ingoing limit
%{ingoing_rate_limit, '64KB/s'}
%TODO: Reconnet control
]},
%% Session
{session, [
@ -111,11 +108,17 @@
{expired_after, 48}
]},
%% Session
%% Queue
{queue, [
%% Max queue length. enqueued messages when persistent client disconnected,
%% simple | priority
{type, simple},
%% Topic Priority: 0~255, Default is 0
%% {priority, [{"topic/1", 10}, {"topic/2", 8}]},
%% Max queue length. Enqueued messages when persistent client disconnected,
%% or inflight window is full.
{max_length, 100},
{max_length, infinity},
%% Low-water mark of queued messages
{low_watermark, 0.2},
@ -147,7 +150,7 @@
%% PubSub and Router
{pubsub, [
%% Default should be scheduler numbers
%% {pool_size, 8},
{pool_size, 8},
%% Subscription: disc | ram | false
{subscription, ram},

View File

@ -103,11 +103,17 @@
{expired_after, 48}
]},
%% Session
%% Queue
{queue, [
%% Max queue length. enqueued messages when persistent client disconnected,
%% simple | priority
{type, simple},
%% Topic Priority: 0~255, Default is 0
%% {priority, [{"topic/1", 10}, {"topic/2", 8}]},
%% Max queue length. Enqueued messages when persistent client disconnected,
%% or inflight window is full.
{max_length, 100},
{max_length, infinity},
%% Low-water mark of queued messages
{low_watermark, 0.2},
@ -139,7 +145,7 @@
%% PubSub and Router
{pubsub, [
%% Default should be scheduler numbers
%% {pool_size, 8},
{pool_size, 8},
%% Subscription: disc | ram | false
{subscription, ram},

View File

@ -46,6 +46,7 @@
-env ERTS_MAX_PORTS 8192
## Mnesia and SSL will create temporary ets tables.
-env ERL_MAX_ETS_TABLES 1024
## Tweak GC to run more often

View File

@ -13,4 +13,3 @@
{mod, {emqttd_app, []}},
{env, []}
]}.

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -23,12 +23,16 @@
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%-----------------------------------------------------------------------------
-module(emqttd).
-export([start/0, env/1, env/2,
start_listeners/0, stop_listeners/0,
load_all_mods/0, is_mod_enabled/1,
is_running/1]).
is_running/1, seed_now/0]).
%% Utility functions.
-export([reg_name/2]).
-define(MQTT_SOCKOPTS, [
binary,
@ -122,10 +126,8 @@ load_mod({Name, Opts}) ->
is_mod_enabled(Name) ->
env(modules, Name) =/= undefined.
%%------------------------------------------------------------------------------
%% @doc Is running?
%% @end
%%------------------------------------------------------------------------------
-spec is_running(node()) -> boolean().
is_running(Node) ->
case rpc:call(Node, erlang, whereis, [?APP]) of
{badrpc, _} -> false;
@ -133,3 +135,16 @@ is_running(Node) ->
Pid when is_pid(Pid) -> true
end.
-spec reg_name(module(), pos_integer()) -> atom().
reg_name(M, Id) when is_atom(M), is_integer(Id) ->
list_to_atom(lists:concat([M, "_", Id])).
seed_now() ->
case erlang:function_exported(erlang, timestamp, 0) of
true -> %% R18
random:seed(erlang:timestamp());
false ->
%% compress 'now()' warning...
random:seed(os:timestamp())
end.

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -27,6 +27,10 @@
-include("emqttd.hrl").
-export([passwd_hash/2]).
-type hash_type() :: plain | md5 | sha | sha256.
%%%=============================================================================
%%% Auth behavihour
%%%=============================================================================
@ -53,3 +57,21 @@ behaviour_info(_Other) ->
-endif.
%% @doc Password Hash
-spec passwd_hash(hash_type(), binary()) -> binary().
passwd_hash(plain, Password) ->
Password;
passwd_hash(md5, Password) ->
hexstring(crypto:hash(md5, Password));
passwd_hash(sha, Password) ->
hexstring(crypto:hash(sha, Password));
passwd_hash(sha256, Password) ->
hexstring(crypto:hash(sha256, Password)).
hexstring(<<X:128/big-unsigned-integer>>) ->
iolist_to_binary(io_lib:format("~32.16.0b", [X]));
hexstring(<<X:160/big-unsigned-integer>>) ->
iolist_to_binary(io_lib:format("~40.16.0b", [X]));
hexstring(<<X:256/big-unsigned-integer>>) ->
iolist_to_binary(io_lib:format("~64.16.0b", [X])).

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -71,6 +71,9 @@ add_user(Username, Password) ->
User = #?AUTH_USERNAME_TAB{username = Username, password = hash(Password)},
mnesia:transaction(fun mnesia:write/1, [User]).
add_default_user(Username, Password) ->
add_user(bin(Username), bin(Password)).
%%------------------------------------------------------------------------------
%% @doc Lookup user by username
%% @end
@ -98,13 +101,16 @@ all_users() ->
%%%=============================================================================
%%% emqttd_auth callbacks
%%%=============================================================================
init(Opts) ->
init(DefautUsers) ->
mnesia:create_table(?AUTH_USERNAME_TAB, [
{disc_copies, [node()]},
{attributes, record_info(fields, ?AUTH_USERNAME_TAB)}]),
mnesia:add_table_copy(?AUTH_USERNAME_TAB, node(), disc_copies),
lists:foreach(fun({Username, Password}) ->
add_default_user(Username, Password)
end, DefautUsers),
emqttd_ctl:register_cmd(users, {?MODULE, cli}, []),
{ok, Opts}.
{ok, []}.
check(#mqtt_client{username = undefined}, _Password, _Opts) ->
{error, "Username undefined"};
@ -136,8 +142,11 @@ md5_hash(SaltBin, Password) ->
erlang:md5(<<SaltBin/binary, Password/binary>>).
salt() ->
{A1,A2,A3} = now(),
random:seed(A1, A2, A3),
emqttd:seed_now(),
Salt = random:uniform(16#ffffffff),
<<Salt:32>>.
bin(A) when is_atom(A) -> bin(atom_to_list(A));
bin(L) when is_list(L) -> list_to_binary(L);
bin(B) when is_binary(B) -> B.

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -172,7 +172,7 @@ dequeue(State = #state{mqueue = MQ}) ->
{empty, MQ1} ->
State#state{mqueue = MQ1};
{{value, Msg}, MQ1} ->
handle_info({dispatch, Msg}, State),
handle_info({dispatch, Msg#mqtt_message.topic, Msg}, State),
dequeue(State#state{mqueue = MQ1})
end.

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -218,7 +218,7 @@ stop_tick(TRef) ->
%%%=============================================================================
init([]) ->
random:seed(os:timestamp()),
emqttd:seed_now(),
ets:new(?BROKER_TAB, [set, public, named_table]),
% Create $SYS Topics
emqttd_pubsub:create(topic, <<"$SYS/brokers">>),

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -101,7 +101,7 @@ broker(["metrics"]) ->
end, lists:sort(emqttd_metrics:all()));
broker(["pubsub"]) ->
Pubsubs = supervisor:which_children(emqttd_pubsub_sup),
Pubsubs = supervisor:which_children(emqttd_pubsub_sup:pubsub_pool()),
foreach(fun({{_, Id}, Pid, _, _}) ->
ProcInfo = erlang:process_info(Pid, ?PROC_INFOKEYS),
?PRINT("pubsub: ~w~n", [Id]),
@ -323,7 +323,7 @@ plugins(_) ->
bridges(["list"]) ->
foreach(fun({{Node, Topic}, _Pid}) ->
?PRINT("bridge: ~s ~s~n", [Node, Topic])
?PRINT("bridge: ~s--~s-->~s~n", [node(), Topic, Node])
end, emqttd_bridge_sup:bridges());
bridges(["options"]) ->
@ -449,7 +449,7 @@ trace(_) ->
{"trace topic <Topic> off", "stop to trace Topic"}]).
trace_on(Who, Name, LogFile) ->
case emqttd_trace:start_trace({Who, bin(Name)}, LogFile) of
case emqttd_trace:start_trace({Who, iolist_to_binary(Name)}, LogFile) of
ok ->
?PRINT("trace ~s ~s successfully.~n", [Who, Name]);
{error, Error} ->
@ -457,7 +457,7 @@ trace_on(Who, Name, LogFile) ->
end.
trace_off(Who, Name) ->
case emqttd_trace:stop_trace({Who, bin(Name)}) of
case emqttd_trace:stop_trace({Who, iolist_to_binary(Name)}) of
ok ->
?PRINT("stop to trace ~s ~s successfully.~n", [Who, Name]);
{error, Error} ->
@ -507,17 +507,16 @@ print({{ClientId, _ClientPid}, SessInfo}) ->
awaiting_rel,
awaiting_ack,
awaiting_comp,
created_at,
subscriptions],
created_at],
?PRINT("Session(~s, clean_sess=~s, max_inflight=~w, inflight_queue=~w, "
"message_queue=~w, message_dropped=~w, "
"awaiting_rel=~w, awaiting_ack=~w, awaiting_comp=~w, "
"created_at=~w, subscriptions=~s)~n",
"created_at=~w)~n",
[ClientId | [format(Key, proplists:get_value(Key, SessInfo)) || Key <- InfoKeys]]).
print(topic, Topic, Records) ->
Nodes = [Node || #mqtt_topic{node = Node} <- Records],
?PRINT("~s: on ~p~n", [Topic, Nodes]);
?PRINT("~s: ~p~n", [Topic, Nodes]);
print(subscription, ClientId, Subscriptions) ->
TopicTable = [{Topic, Qos} || #mqtt_subscription{topic = Topic, qos = Qos} <- Subscriptions],

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -283,7 +283,7 @@ key(counter, Metric) ->
%%%=============================================================================
init([]) ->
random:seed(os:timestamp()),
emqttd:seed_now(),
Metrics = ?SYSTOP_BYTES ++ ?SYSTOP_PACKETS ++ ?SYSTOP_MESSAGES,
% Create metrics table
ets:new(?METRIC_TAB, [set, public, named_table, {write_concurrency, true}]),

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -40,7 +40,7 @@
-endif.
load(Opts) ->
Topics = [{bin(Topic), QoS} || {Topic, QoS} <- Opts, ?IS_QOS(QoS)],
Topics = [{iolist_to_binary(Topic), QoS} || {Topic, QoS} <- Opts, ?IS_QOS(QoS)],
State = #state{topics = Topics, stored = lists:member(stored, Opts)},
emqttd_broker:hook('client.connected', {?MODULE, client_connected},
{?MODULE, client_connected, [State]}),
@ -52,7 +52,9 @@ client_connected(?CONNACK_ACCEPT, #mqtt_client{client_id = ClientId,
#state{topics = Topics, stored = Stored}) ->
Replace = fun(Topic) -> rep(<<"$u">>, Username, rep(<<"$c">>, ClientId, Topic)) end,
TopicTable = with_stored(Stored, ClientId, [{Replace(Topic), Qos} || {Topic, Qos} <- Topics]),
emqttd_client:subscribe(ClientPid, TopicTable).
emqttd_client:subscribe(ClientPid, TopicTable);
client_connected(_ConnAck, _Client, _State) -> ok.
with_stored(false, _ClientId, TopicTable) ->
TopicTable;
@ -70,8 +72,3 @@ rep(<<"$u">>, undefined, Topic) ->
rep(<<"$u">>, Username, Topic) ->
emqttd_topic:feed_var(<<"$u">>, Username, Topic).
bin(B) when is_binary(B) ->
B;
bin(S) when is_list(S) ->
list_to_binary(S).

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -30,20 +30,21 @@
%%%
%%% If the broker restarted or crashed, all the messages queued will be gone.
%%%
%%% Desgin of The Queue:
%%% Concept of Message Queue and Inflight Window:
%%%
%%% |<----------------- Max Len ----------------->|
%%% -----------------------------------------------
%%% IN -> | Pending Messages | Inflight Window | -> Out
%%% IN -> | Messages Queue | Inflight Window | -> Out
%%% -----------------------------------------------
%%% |<--- Win Size --->|
%%%
%%%
%%% 1. Inflight Window to store the messages awaiting for ack.
%%% 1. Inflight Window to store the messages delivered and awaiting for puback.
%%%
%%% 2. Suspend IN messages when the queue is deactive, or inflight windows is full.
%%% 2. Enqueue messages when the inflight window is full.
%%%
%%% 3. If the queue is full, dropped qos0 messages if store_qos0 is true,
%%% otherwise dropped the oldest pending one.
%%% otherwise dropped the oldest one.
%%%
%%% @end
%%%
@ -55,96 +56,161 @@
-include("emqttd_protocol.hrl").
-export([new/3, name/1,
is_empty/1, is_full/1,
len/1, max_len/1,
in/2, out/1,
stats/1]).
-export([new/3, type/1, name/1, is_empty/1, len/1, max_len/1, in/2, out/1, stats/1]).
-define(LOW_WM, 0.2).
-define(HIGH_WM, 0.6).
-record(mqueue, {name,
q = queue:new(), %% pending queue
len = 0, %% current queue len
low_wm = ?LOW_WM,
high_wm = ?HIGH_WM,
max_len = ?MAX_LEN,
qos0 = false,
dropped = 0,
alarm_fun}).
-type priority() :: {iolist(), pos_integer()}.
-type mqueue() :: #mqueue{}.
-type option() :: {type, simple | priority}
| {max_length, pos_integer() | infinity}
| {priority, list(priority())}
| {low_watermark, float()} %% Low watermark
| {high_watermark, float()} %% High watermark
| {queue_qos0, boolean()}. %% Queue Qos0?
-type mqueue_option() :: {max_length, pos_integer()} %% Max queue length
| {low_watermark, float()} %% Low watermark
| {high_watermark, float()} %% High watermark
| {queue_qos0, boolean()}. %% Queue Qos0
-export_type([mqueue/0]).
-type stat() :: {max_len, infinity | pos_integer()}
| {len, non_neg_integer()}
| {dropped, non_neg_integer()}.
-record(mqueue, {type :: simple | priority,
name, q :: queue:queue() | priority_queue:q(),
%% priority table
pseq = 0, priorities = [],
%% len of simple queue
len = 0, max_len = ?MAX_LEN,
low_wm = ?LOW_WM, high_wm = ?HIGH_WM,
qos0 = false, dropped = 0,
alarm_fun}).
-type mqueue() :: #mqueue{}.
-export_type([mqueue/0, priority/0, option/0]).
%%------------------------------------------------------------------------------
%% @doc New Queue.
%% @end
%%------------------------------------------------------------------------------
-spec new(binary(), list(mqueue_option()), fun()) -> mqueue().
-spec new(iolist(), list(mqueue_option()), fun()) -> mqueue().
new(Name, Opts, AlarmFun) ->
MaxLen = emqttd_opts:g(max_length, Opts, 1000),
#mqueue{name = Name,
max_len = MaxLen,
low_wm = round(MaxLen * emqttd_opts:g(low_watermark, Opts, ?LOW_WM)),
high_wm = round(MaxLen * emqttd_opts:g(high_watermark, Opts, ?HIGH_WM)),
qos0 = emqttd_opts:g(queue_qos0, Opts, true),
alarm_fun = AlarmFun}.
Type = emqttd_opts:g(type, Opts, simple),
MaxLen = emqttd_opts:g(max_length, Opts, infinity),
init_q(#mqueue{type = Type, name = iolist_to_binary(Name),
len = 0, max_len = MaxLen,
low_wm = low_wm(MaxLen, Opts),
high_wm = high_wm(MaxLen, Opts),
qos0 = emqttd_opts:g(queue_qos0, Opts, false),
alarm_fun = AlarmFun}, Opts).
init_q(MQ = #mqueue{type = simple}, _Opts) ->
MQ#mqueue{q = queue:new()};
init_q(MQ = #mqueue{type = priority}, Opts) ->
Priorities = emqttd_opts:g(priority, Opts, []),
init_p(Priorities, MQ#mqueue{q = priority_queue:new()}).
init_p([], MQ) ->
MQ;
init_p([{Topic, P} | L], MQ) ->
{_, MQ1} = insert_p(iolist_to_binary(Topic), P, MQ),
init_p(L, MQ1).
insert_p(Topic, P, MQ = #mqueue{priorities = Tab, pseq = Seq}) ->
<<PInt:48>> = <<P:8, (erlang:phash2(Topic)):32, Seq:8>>,
{PInt, MQ#mqueue{priorities = [{Topic, PInt} | Tab], pseq = Seq + 1}}.
low_wm(infinity, _Opts) ->
infinity;
low_wm(MaxLen, Opts) ->
round(MaxLen * emqttd_opts:g(low_watermark, Opts, ?LOW_WM)).
high_wm(infinity, _Opts) ->
infinity;
high_wm(MaxLen, Opts) ->
round(MaxLen * emqttd_opts:g(high_watermark, Opts, ?HIGH_WM)).
-spec name(mqueue()) -> iolist().
name(#mqueue{name = Name}) ->
Name.
is_empty(#mqueue{len = 0}) -> true;
is_empty(_MQ) -> false.
-spec type(mqueue()) -> atom().
type(#mqueue{type = Type}) ->
Type.
is_full(#mqueue{len = Len, max_len = MaxLen})
when Len =:= MaxLen -> true;
is_full(_MQ) -> false.
is_empty(#mqueue{type = simple, len = Len}) -> Len =:= 0;
is_empty(#mqueue{type = priority, q = Q}) -> priority_queue:is_empty(Q).
len(#mqueue{len = Len}) -> Len.
len(#mqueue{type = simple, len = Len}) -> Len;
len(#mqueue{type = priority, q = Q}) -> priority_queue:len(Q).
max_len(#mqueue{max_len= MaxLen}) -> MaxLen.
stats(#mqueue{max_len = MaxLen, len = Len, dropped = Dropped}) ->
[{max_len, MaxLen}, {len, Len}, {dropped, Dropped}].
%%------------------------------------------------------------------------------
%% @doc Queue one message.
%% @end
%%------------------------------------------------------------------------------
%% @doc Stats of the mqueue
-spec stats(mqueue()) -> [stat()].
stats(#mqueue{type = Type, q = Q, max_len = MaxLen, len = Len, dropped = Dropped}) ->
[{len, case Type of
simple -> Len;
priority -> priority_queue:len(Q)
end} | [{max_len, MaxLen}, {dropped, Dropped}]].
%% @doc Enqueue a message.
-spec in(mqtt_message(), mqueue()) -> mqueue().
%% drop qos0
in(#mqtt_message{qos = ?QOS_0}, MQ = #mqueue{qos0 = false}) ->
MQ;
%% simply drop the oldest one if queue is full, improve later
in(Msg, MQ = #mqueue{q = Q, len = Len, max_len = MaxLen, dropped = Dropped})
when Len =:= MaxLen ->
{{value, _OldMsg}, Q2} = queue:out(Q),
%lager:error("MQueue(~s) drop ~s", [Name, emqttd_message:format(OldMsg)]),
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len, max_len = infinity}) ->
MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1};
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len, max_len = MaxLen, dropped = Dropped})
when Len >= MaxLen ->
{{value, _Old}, Q2} = queue:out(Q),
MQ#mqueue{q = queue:in(Msg, Q2), dropped = Dropped +1};
in(Msg, MQ = #mqueue{type = simple, q = Q, len = Len}) ->
maybe_set_alarm(MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1});
in(Msg, MQ = #mqueue{q = Q, len = Len}) ->
maybe_set_alarm(MQ#mqueue{q = queue:in(Msg, Q), len = Len + 1}).
in(Msg = #mqtt_message{topic = Topic}, MQ = #mqueue{type = priority, q = Q,
priorities = Priorities,
max_len = infinity}) ->
case lists:keysearch(Topic, 1, Priorities) of
{value, {_, Pri}} ->
MQ#mqueue{q = priority_queue:in(Msg, Pri, Q)};
false ->
{Pri, MQ1} = insert_p(Topic, 0, MQ),
MQ1#mqueue{q = priority_queue:in(Msg, Pri, Q)}
end;
in(Msg = #mqtt_message{topic = Topic}, MQ = #mqueue{type = priority, q = Q,
priorities = Priorities,
max_len = MaxLen}) ->
case lists:keysearch(Topic, 1, Priorities) of
{value, {_, Pri}} ->
case priority_queue:plen(Pri, Q) >= MaxLen of
true ->
{_, Q1} = priority_queue:out(Pri, Q),
MQ#mqueue{q = priority_queue:in(Msg, Pri, Q1)};
false ->
MQ#mqueue{q = priority_queue:in(Msg, Pri, Q)}
end;
false ->
{Pri, MQ1} = insert_p(Topic, 0, MQ),
MQ1#mqueue{q = priority_queue:in(Msg, Pri, Q)}
end.
out(MQ = #mqueue{len = 0}) ->
out(MQ = #mqueue{type = simple, len = 0}) ->
{empty, MQ};
out(MQ = #mqueue{q = Q, len = Len}) ->
{Result, Q2} = queue:out(Q),
{Result, maybe_clear_alarm(MQ#mqueue{q = Q2, len = Len - 1})}.
out(MQ = #mqueue{type = simple, q = Q, len = Len, max_len = infinity}) ->
{R, Q2} = queue:out(Q),
{R, MQ#mqueue{q = Q2, len = Len - 1}};
out(MQ = #mqueue{type = simple, q = Q, len = Len}) ->
{R, Q2} = queue:out(Q),
{R, maybe_clear_alarm(MQ#mqueue{q = Q2, len = Len - 1})};
out(MQ = #mqueue{type = priority, q = Q}) ->
{R, Q2} = priority_queue:out(Q),
{R, MQ#mqueue{q = Q2}}.
maybe_set_alarm(MQ = #mqueue{name = Name, len = Len, high_wm = HighWM, alarm_fun = AlarmFun})
when Len > HighWM ->
Alarm = #mqtt_alarm{id = list_to_binary(["queue_high_watermark.", Name]),
Alarm = #mqtt_alarm{id = iolist_to_binary(["queue_high_watermark.", Name]),
severity = warning,
title = io_lib:format("Queue ~s high-water mark", [Name]),
summary = io_lib:format("queue len ~p > high_watermark ~p", [Len, HighWM])},

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -53,10 +53,7 @@ start_link() ->
%%%=============================================================================
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
start_link(Pool, Id) ->
gen_server:start_link({local, name(Id)}, ?MODULE, [Pool, Id], []).
name(Id) ->
list_to_atom(lists:concat([?MODULE, "_", integer_to_list(Id)])).
gen_server:start_link({local, emqttd:reg_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
%%------------------------------------------------------------------------------
%% @doc Submit work to pooler

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -19,7 +19,7 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc emqttd pubsub
%%% @doc PubSub
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%-----------------------------------------------------------------------------
@ -43,9 +43,7 @@
-export([start_link/4]).
-export([create/2, lookup/2, subscribe/1, subscribe/2,
unsubscribe/1, unsubscribe/2, publish/1, delete/2]).
%% Subscriptions API
publish/1, unsubscribe/1, unsubscribe/2, delete/2]).
%% Local node
-export([match/1]).
@ -62,8 +60,6 @@
-define(ROUTER, emqttd_router).
-define(HELPER, emqttd_pubsub_helper).
%%%=============================================================================
%%% Mnesia callbacks
%%%=============================================================================
@ -123,26 +119,19 @@ cache_env(Key) ->
%%% API
%%%=============================================================================
%%------------------------------------------------------------------------------
%% @doc Start one pubsub server
%% @end
%%------------------------------------------------------------------------------
-spec start_link(Pool, Id, StatsFun, Opts) -> {ok, pid()} | ignore | {error, any()} when
Pool :: atom(),
Id :: pos_integer(),
StatsFun :: fun(),
StatsFun :: fun((atom()) -> any()),
Opts :: list(tuple()).
start_link(Pool, Id, StatsFun, Opts) ->
gen_server2:start_link({local, name(Id)}, ?MODULE, [Pool, Id, StatsFun, Opts], []).
gen_server2:start_link({local, emqttd:reg_name(?MODULE, Id)},
?MODULE, [Pool, Id, StatsFun, Opts], []).
name(Id) ->
list_to_atom("emqttd_pubsub_" ++ integer_to_list(Id)).
%%------------------------------------------------------------------------------
%% @doc Create Topic or Subscription.
%% @end
%%------------------------------------------------------------------------------
-spec create(topic | subscription, binary() | {binary(), binary(), mqtt_qos()}) -> ok | {error, any()}.
-spec create(topic, emqttd_topic:topic()) -> ok | {error, any()};
(subscription, {binary(), binary(), mqtt_qos()}) -> ok | {error, any()}.
create(topic, Topic) when is_binary(Topic) ->
Record = #mqtt_topic{topic = Topic, node = node()},
case mnesia:transaction(fun add_topic/1, [Record]) of
@ -151,39 +140,33 @@ create(topic, Topic) when is_binary(Topic) ->
end;
create(subscription, {SubId, Topic, Qos}) when is_binary(SubId) andalso is_binary(Topic) ->
case mnesia:transaction(fun add_subscription/2, [SubId, {Topic, Qos}]) of
case mnesia:transaction(fun add_subscription/2, [SubId, {Topic, ?QOS_I(Qos)}]) of
{atomic, ok} -> ok;
{aborted, Error} -> {error, Error}
end.
%%------------------------------------------------------------------------------
%% @doc Lookup Topic or Subscription.
%% @end
%%------------------------------------------------------------------------------
-spec lookup(topic | subscription, binary()) -> list().
lookup(topic, Topic) ->
-spec lookup(topic, emqttd_topic:topic()) -> list(mqtt_topic());
(subscription, binary()) -> list(mqtt_subscription()).
lookup(topic, Topic) when is_binary(Topic) ->
mnesia:dirty_read(topic, Topic);
lookup(subscription, ClientId) ->
mnesia:dirty_read(subscription, ClientId).
lookup(subscription, SubId) when is_binary(SubId) ->
mnesia:dirty_read(subscription, SubId).
%%------------------------------------------------------------------------------
%% @doc Delete Topic or Subscription.
%% @end
%%------------------------------------------------------------------------------
-spec delete(topic, emqttd_topic:topic()) -> ok | {error, any()};
(subscription, binary() | {binary(), emqttd_topic:topic()}) -> ok.
delete(topic, _Topic) ->
{error, unsupported};
delete(subscription, ClientId) when is_binary(ClientId) ->
mnesia:dirty_delete({subscription, ClientId});
delete(subscription, SubId) when is_binary(SubId) ->
mnesia:dirty_delete({subscription, SubId});
delete(subscription, {ClientId, Topic}) when is_binary(ClientId) ->
mnesia:async_dirty(fun remove_subscriptions/2, [ClientId, [Topic]]).
delete(subscription, {SubId, Topic}) when is_binary(SubId) andalso is_binary(Topic) ->
mnesia:async_dirty(fun remove_subscriptions/2, [SubId, [Topic]]).
%%------------------------------------------------------------------------------
%% @doc Subscribe Topics
%% @end
%%------------------------------------------------------------------------------
-spec subscribe({Topic, Qos} | list({Topic, Qos})) ->
{ok, Qos | list(Qos)} | {error, any()} when
Topic :: binary(),
@ -206,34 +189,28 @@ subscribe(ClientId, TopicTable) when is_binary(ClientId) andalso is_list(TopicTa
fixqos(TopicTable) ->
[{Topic, ?QOS_I(Qos)} || {Topic, Qos} <- TopicTable].
call(Request) ->
PubSub = gproc_pool:pick_worker(pubsub, self()),
gen_server2:call(PubSub, Request, infinity).
%%------------------------------------------------------------------------------
%% @doc Unsubscribe Topic or Topics
%% @end
%%------------------------------------------------------------------------------
-spec unsubscribe(binary() | list(binary())) -> ok.
-spec unsubscribe(emqttd_topic:topic() | list(emqttd_topic:topic())) -> ok.
unsubscribe(Topic) when is_binary(Topic) ->
unsubscribe([Topic]);
unsubscribe(Topics = [Topic|_]) when is_binary(Topic) ->
cast({unsubscribe, {undefined, self()}, Topics}).
-spec unsubscribe(binary(), binary() | list(binary())) -> ok.
-spec unsubscribe(binary(), emqttd_topic:topic() | list(emqttd_topic:topic())) -> ok.
unsubscribe(ClientId, Topic) when is_binary(ClientId) andalso is_binary(Topic) ->
unsubscribe(ClientId, [Topic]);
unsubscribe(ClientId, Topics = [Topic|_]) when is_binary(Topic) ->
cast({unsubscribe, {ClientId, self()}, Topics}).
cast(Msg) ->
PubSub = gproc_pool:pick_worker(pubsub, self()),
gen_server2:cast(PubSub, Msg).
call(Request) ->
gen_server2:call(pick(self()), Request, infinity).
cast(Msg) ->
gen_server2:cast(pick(self()), Msg).
pick(Self) -> gproc_pool:pick_worker(pubsub, Self).
%%------------------------------------------------------------------------------
%% @doc Publish to cluster nodes
%% @end
%%------------------------------------------------------------------------------
-spec publish(Msg :: mqtt_message()) -> ok.
publish(Msg = #mqtt_message{from = From}) ->
trace(publish, From, Msg),
@ -257,35 +234,41 @@ publish(To, Msg) ->
end
end, match(To)).
%%------------------------------------------------------------------------------
%% @doc Match Topic Name with Topic Filters
%% @end
%%------------------------------------------------------------------------------
-spec match(binary()) -> [mqtt_topic()].
-spec match(emqttd_topic:topic()) -> [mqtt_topic()].
match(To) ->
MatchedTopics = mnesia:async_dirty(fun emqttd_trie:match/1, [To]),
%% ets:lookup for topic table will be replicated.
%% ets:lookup for topic table will be replicated to all nodes.
lists:append([ets:lookup(topic, Topic) || Topic <- MatchedTopics]).
%%%=============================================================================
%%% gen_server callbacks
%%%=============================================================================
init([Pool, Id, StatsFun, Opts]) ->
?ROUTER:init(Opts),
init([Pool, Id, StatsFun, _Opts]) ->
?GPROC_POOL(join, Pool, Id),
{ok, #state{pool = Pool, id = Id, statsfun = StatsFun}}.
handle_call({subscribe, {SubId, SubPid}, TopicTable}, _From,
State = #state{statsfun = StatsFun}) ->
%% Monitor SubPid first
try_monitor(SubPid),
%% Topics
Topics = [Topic || {Topic, _Qos} <- TopicTable],
%% Add routes first
?ROUTER:add_routes(Topics, SubPid),
NewTopics = Topics -- reverse_routes(SubPid),
%% Insert topic records to global topic table
Records = [#mqtt_topic{topic = Topic, node = node()} || Topic <- Topics],
%% Add routes
?ROUTER:add_routes(NewTopics, SubPid),
insert_reverse_routes(SubPid, NewTopics),
StatsFun(reverse_route),
%% Insert topic records to mnesia
Records = [#mqtt_topic{topic = Topic, node = node()} || Topic <- NewTopics],
case mnesia:transaction(fun add_topics/1, [Records]) of
{atomic, _} ->
@ -307,9 +290,14 @@ handle_call(Req, _From, State) ->
?UNEXPECTED_REQ(Req, State).
handle_cast({unsubscribe, {SubId, SubPid}, Topics}, State = #state{statsfun = StatsFun}) ->
%% Delete routes first
?ROUTER:delete_routes(Topics, SubPid),
delete_reverse_routes(SubPid, Topics),
StatsFun(reverse_route),
%% Remove subscriptions
if_subscription(
fun(_) ->
@ -317,19 +305,21 @@ handle_cast({unsubscribe, {SubId, SubPid}, Topics}, State = #state{statsfun = St
emqttd_pooler:async_submit({mnesia, async_dirty, Args}),
StatsFun(subscription)
end),
{noreply, State};
handle_cast(Msg, State) ->
?UNEXPECTED_MSG(Msg, State).
handle_info({'DOWN', _Mon, _Type, DownPid, _Info}, State) ->
handle_info({'DOWN', _Mon, _Type, DownPid, _Info}, State = #state{statsfun = StatsFun}) ->
Routes = ?ROUTER:lookup_routes(DownPid),
Topics = reverse_routes(DownPid),
%% Delete all routes of the process
?ROUTER:delete_routes(DownPid),
?ROUTER:delete_routes(Topics, DownPid),
?HELPER:aging([Topic || Topic <- Routes, not ?ROUTER:has_route(Topic)]),
delete_reverse_routes(DownPid),
StatsFun(reverse_route),
{noreply, State, hibernate};
@ -395,6 +385,31 @@ remove_subscriptions(SubId, Topics) ->
delete_subscription(Record) ->
mnesia:delete_object(subscription, Record, write).
reverse_routes(SubPid) ->
case ets:member(reverse_route, SubPid) of
true ->
try ets:lookup_element(reverse_route, SubPid, 2) catch error:badarg -> [] end;
false ->
[]
end.
insert_reverse_routes(SubPid, Topics) ->
ets:insert(reverse_route, [{SubPid, Topic} || Topic <- Topics]).
delete_reverse_routes(SubPid, Topics) ->
lists:foreach(fun(Topic) ->
ets:delete_object(reverse_route, {SubPid, Topic})
end, Topics).
delete_reverse_routes(SubPid) ->
ets:delete(reverse_route, SubPid).
try_monitor(SubPid) ->
case ets:member(reverse_route, SubPid) of
true -> ignore;
false -> erlang:monitor(process, SubPid)
end.
%%%=============================================================================
%%% Trace Functions
%%%=============================================================================

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -19,176 +19,66 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc PubSub Route Aging Helper
%%% @doc PubSub Helper.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%-----------------------------------------------------------------------------
-module(emqttd_pubsub_helper).
-behaviour(gen_server2).
-behaviour(gen_server).
-include("emqttd.hrl").
-include("emqttd_internal.hrl").
%% API Function Exports
-export([start_link/2, aging/1]).
-export([start_link/1]).
%% gen_server Function Exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-ifdef(TEST).
-compile(export_all).
-endif.
-record(aging, {topics, time, tref}).
-record(state, {aging :: #aging{}, statsfun}).
-record(state, {statsfun}).
-define(SERVER, ?MODULE).
-define(ROUTER, emqttd_router).
%%%=============================================================================
%%% API
%%%=============================================================================
%%------------------------------------------------------------------------------
%% @doc Start pubsub helper.
%% @end
%%------------------------------------------------------------------------------
-spec start_link(fun(), list(tuple())) -> {ok, pid()} | ignore | {error, any()}.
start_link(StatsFun, Opts) ->
gen_server2:start_link({local, ?SERVER}, ?MODULE, [StatsFun, Opts], []).
%%------------------------------------------------------------------------------
%% @doc Aging topics
%% @end
%%------------------------------------------------------------------------------
-spec aging(list(binary())) -> ok.
aging(Topics) ->
gen_server2:cast(?SERVER, {aging, Topics}).
%% @doc Start PubSub Helper.
-spec start_link(fun()) -> {ok, pid()} | ignore | {error, any()}.
start_link(StatsFun) ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [StatsFun], []).
%%%=============================================================================
%%% gen_server callbacks
%%%=============================================================================
init([StatsFun, Opts]) ->
init([StatsFun]) ->
mnesia:subscribe(system),
AgingSecs = proplists:get_value(route_aging, Opts, 5),
%% Aging Timer
{ok, AgingTref} = start_tick(AgingSecs div 2),
{ok, #state{aging = #aging{topics = dict:new(),
time = AgingSecs,
tref = AgingTref},
statsfun = StatsFun}}.
start_tick(Secs) ->
timer:send_interval(timer:seconds(Secs), {clean, aged}).
{ok, #state{statsfun = StatsFun}}.
handle_call(Req, _From, State) ->
?UNEXPECTED_REQ(Req, State).
handle_cast({aging, Topics}, State = #state{aging = Aging}) ->
#aging{topics = Dict} = Aging,
TS = emqttd_util:now_to_secs(),
Dict1 =
lists:foldl(fun(Topic, Acc) ->
case dict:find(Topic, Acc) of
{ok, _} -> Acc;
error -> dict:store(Topic, TS, Acc)
end
end, Dict, Topics),
{noreply, State#state{aging = Aging#aging{topics = Dict1}}};
handle_cast(Msg, State) ->
?UNEXPECTED_MSG(Msg, State).
handle_info({clean, aged}, State = #state{aging = Aging}) ->
#aging{topics = Dict, time = Time} = Aging,
ByTime = emqttd_util:now_to_secs() - Time,
Dict1 = try_clean(ByTime, dict:to_list(Dict)),
NewAging = Aging#aging{topics = dict:from_list(Dict1)},
noreply(State#state{aging = NewAging});
handle_info({mnesia_system_event, {mnesia_down, Node}}, State) ->
%% mnesia master?
%% TODO: mnesia master?
Pattern = #mqtt_topic{_ = '_', node = Node},
F = fun() ->
[mnesia:delete_object(topic, R, write) ||
R <- mnesia:match_object(topic, Pattern, write)]
end,
mnesia:async_dirty(F),
noreply(State);
mnesia:transaction(F), noreply(State);
handle_info(Info, State) ->
?UNEXPECTED_INFO(Info, State).
terminate(_Reason, #state{aging = #aging{tref = TRef}}) ->
timer:cancel(TRef).
terminate(_Reason, _State) ->
mnesia:unsubscribe(system).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%=============================================================================
%%% Internal Functions
%%%=============================================================================
noreply(State = #state{statsfun = StatsFun}) ->
StatsFun(topic),
{noreply, State, hibernate}.
try_clean(ByTime, List) ->
try_clean(ByTime, List, []).
try_clean(_ByTime, [], Acc) ->
Acc;
try_clean(ByTime, [{Topic, TS} | Left], Acc) ->
case ?ROUTER:has_route(Topic) of
false ->
try_clean2(ByTime, {Topic, TS}, Left, Acc);
true ->
try_clean(ByTime, Left, Acc)
end.
try_clean2(ByTime, {Topic, TS}, Left, Acc) when TS > ByTime ->
try_clean(ByTime, Left, [{Topic, TS}|Acc]);
try_clean2(ByTime, {Topic, _TS}, Left, Acc) ->
TopicR = #mqtt_topic{topic = Topic, node = node()},
mnesia:transaction(fun try_remove_topic/1, [TopicR]),
try_clean(ByTime, Left, Acc).
try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
%% Lock topic first
case mnesia:wread({topic, Topic}) of
[] -> ok;
[TopicR] ->
if_no_route(Topic, fun() ->
%% Remove topic and trie
mnesia:delete_object(topic, TopicR, write),
emqttd_trie:delete(Topic)
end);
_More ->
if_no_route(Topic, fun() ->
%% Remove topic
mnesia:delete_object(topic, TopicR, write)
end)
end.
if_no_route(Topic, Fun) ->
case ?ROUTER:has_route(Topic) of
true -> ok;
false -> Fun()
end.
StatsFun(topic), {noreply, State}.

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -19,7 +19,7 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc PubSub Supervisor
%%% @doc PubSub Supervisor.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%-----------------------------------------------------------------------------
@ -31,8 +31,10 @@
-define(HELPER, emqttd_pubsub_helper).
-define(CONCURRENCY_OPTS, [{read_concurrency, true}, {write_concurrency, true}]).
%% API
-export([start_link/0]).
-export([start_link/0, pubsub_pool/0]).
%% Supervisor callbacks
-export([init/1]).
@ -40,24 +42,57 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, [emqttd_broker:env(pubsub)]).
init([Opts]) ->
pubsub_pool() ->
hd([Pid|| {pubsub_pool, Pid, _, _} <- supervisor:which_children(?MODULE)]).
init([Env]) ->
%% Create tabs
create_tab(route), create_tab(reverse_route),
%% PubSub Helper
Helper = {helper, {?HELPER, start_link, [fun stats/1, Opts]},
Helper = {helper, {?HELPER, start_link, [fun setstats/1]},
permanent, infinity, worker, [?HELPER]},
%% Router Pool Sup
RouterMFA = {emqttd_router, start_link, [fun setstats/1, Env]},
%% Pool_size / 2
RouterSup = emqttd_pool_sup:spec(router_pool, [router, hash, pool_size(Env) div 2, RouterMFA]),
%% PubSub Pool Sup
MFA = {emqttd_pubsub, start_link, [fun stats/1, Opts]},
PoolSup = emqttd_pool_sup:spec([pubsub, hash, pool_size(Opts), MFA]),
{ok, {{one_for_all, 10, 60}, [Helper, PoolSup]}}.
PubSubMFA = {emqttd_pubsub, start_link, [fun setstats/1, Env]},
PubSubSup = emqttd_pool_sup:spec(pubsub_pool, [pubsub, hash, pool_size(Env), PubSubMFA]),
pool_size(Opts) ->
{ok, {{one_for_all, 10, 60}, [Helper, RouterSup, PubSubSup]}}.
create_tab(route) ->
%% Route Table: Topic -> Pid1, Pid2, ..., PidN
%% duplicate_bag: o(1) insert
ensure_tab(route, [public, named_table, duplicate_bag | ?CONCURRENCY_OPTS]);
create_tab(reverse_route) ->
%% Reverse Route Table: Pid -> Topic1, Topic2, ..., TopicN
ensure_tab(reverse_route, [public, named_table, bag | ?CONCURRENCY_OPTS]).
ensure_tab(Tab, Opts) ->
case ets:info(Tab, name) of
undefined -> ets:new(Tab, Opts);
_ -> ok
end.
pool_size(Env) ->
Schedulers = erlang:system_info(schedulers),
proplists:get_value(pool_size, Opts, Schedulers).
proplists:get_value(pool_size, Env, Schedulers).
stats(topic) ->
emqttd_stats:setstats('topics/count', 'topics/max',
mnesia:table_info(topic, size));
stats(subscription) ->
setstats(route) ->
emqttd_stats:setstat('routes/count', ets:info(route, size));
setstats(reverse_route) ->
emqttd_stats:setstat('routes/reverse', ets:info(reverse_route, size));
setstats(topic) ->
emqttd_stats:setstats('topics/count', 'topics/max', mnesia:table_info(topic, size));
setstats(subscription) ->
emqttd_stats:setstats('subscriptions/count', 'subscriptions/max',
mnesia:table_info(subscription, size)).

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -19,167 +19,267 @@
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
%%% SOFTWARE.
%%%-----------------------------------------------------------------------------
%%% @doc MQTT Message Router on Local Node
%%%
%%% Route Table:
%%%
%%% Topic -> Pid1, Pid2, ...
%%%
%%% Reverse Route Table:
%%%
%%% Pid -> Topic1, Topic2, ...
%%%
%%% @end
%%% @doc Message Router on local node.
%%%
%%% @author Feng Lee <feng@emqtt.io>
%%%-----------------------------------------------------------------------------
-module(emqttd_router).
-behaviour(gen_server2).
-include("emqttd.hrl").
-include("emqttd_protocol.hrl").
-export([init/1, route/2, lookup_routes/1, has_route/1,
add_routes/2, delete_routes/1, delete_routes/2]).
-include("emqttd_internal.hrl").
-ifdef(TEST).
-compile(export_all).
-endif.
-export([start_link/4]).
%%------------------------------------------------------------------------------
%% @doc Create route tables.
%% @end
%%------------------------------------------------------------------------------
init(_Opts) ->
TabOpts = [bag, public, named_table,
{write_concurrency, true}],
%% Route Table: Topic -> {Pid, QoS}
%% Route Shard: {Topic, Shard} -> {Pid, QoS}
ensure_tab(route, TabOpts),
%% Route API
-export([route/2]).
%% Reverse Route Table: Pid -> {Topic, QoS}
ensure_tab(reverse_route, TabOpts).
%% Route Admin API
-export([add_route/2, lookup_routes/1, has_route/1, delete_route/2]).
ensure_tab(Tab, Opts) ->
case ets:info(Tab, name) of
undefined ->
ets:new(Tab, Opts);
_ ->
ok
end.
%% Batch API
-export([add_routes/2, delete_routes/2]).
-ifdef(TEST).
destory() ->
ets:delete(route),
ets:delete(reverse_route).
-endif.
%% For Test
-export([stop/1]).
%%------------------------------------------------------------------------------
%% @doc Add Routes.
%% @end
%%------------------------------------------------------------------------------
-spec add_routes(list(binary()), pid()) -> ok.
add_routes(Topics, Pid) when is_pid(Pid) ->
with_stats(fun() ->
case lookup_routes(Pid) of
[] ->
erlang:monitor(process, Pid),
insert_routes(Topics, Pid);
InEts ->
insert_routes(Topics -- InEts, Pid)
end
end).
%% gen_server Callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
%%------------------------------------------------------------------------------
%% @doc Lookup Routes
%% @end
%%------------------------------------------------------------------------------
-spec lookup_routes(pid()) -> list(binary()).
lookup_routes(Pid) when is_pid(Pid) ->
[Topic || {_, Topic} <- ets:lookup(reverse_route, Pid)].
-record(aging, {topics, time, tref}).
%%------------------------------------------------------------------------------
%% @doc Has Route?
%% @end
%%------------------------------------------------------------------------------
-spec has_route(binary()) -> boolean().
has_route(Topic) ->
ets:member(route, Topic).
-record(state, {pool, id, statsfun, aging :: #aging{}}).
%%------------------------------------------------------------------------------
%% @doc Delete Routes
%% @end
%%------------------------------------------------------------------------------
-spec delete_routes(list(binary()), pid()) -> ok.
delete_routes(Topics, Pid) ->
with_stats(fun() ->
Routes = [{Topic, Pid} || Topic <- Topics],
lists:foreach(fun delete_route/1, Routes)
end).
%% @doc Start a local router.
-spec start_link(atom(), pos_integer(), fun((atom()) -> ok), list()) -> {ok, pid()} | {error, any()}.
start_link(Pool, Id, StatsFun, Env) ->
gen_server2:start_link({local, emqttd:reg_name(?MODULE,Id)},
?MODULE, [Pool, Id, StatsFun, Env], []).
-spec delete_routes(pid()) -> ok.
delete_routes(Pid) when is_pid(Pid) ->
with_stats(fun() ->
Routes = [{Topic, Pid} || Topic <- lookup_routes(Pid)],
ets:delete(reverse_route, Pid),
lists:foreach(fun delete_route_only/1, Routes)
end).
%%------------------------------------------------------------------------------
%% @doc Route Message on Local Node.
%% @end
%%------------------------------------------------------------------------------
-spec route(binary(), mqtt_message()) -> non_neg_integer().
%% @doc Route Message on the local node.
-spec route(emqttd_topic:topic(), mqtt_message()) -> any().
route(Queue = <<"$Q/", _Q>>, Msg) ->
case ets:lookup(route, Queue) of
case lookup_routes(Queue) of
[] ->
emqttd_metrics:inc('messages/dropped');
[SubPid] ->
SubPid ! {dispatch, Queue, Msg};
Routes ->
Idx = crypto:rand_uniform(1, length(Routes) + 1),
{_, SubPid} = lists:nth(Idx, Routes),
dispatch(SubPid, Queue, Msg)
SubPid = lists:nth(Idx, Routes),
SubPid ! {dispatch, Queue, Msg}
end;
route(Topic, Msg) ->
case ets:lookup(route, Topic) of
case lookup_routes(Topic) of
[] ->
emqttd_metrics:inc('messages/dropped');
[SubPid] -> %% optimize
SubPid ! {dispatch, Topic, Msg};
Routes ->
lists:foreach(fun({_Topic, SubPid}) ->
dispatch(SubPid, Topic, Msg)
lists:foreach(fun(SubPid) ->
SubPid ! {dispatch, Topic, Msg}
end, Routes)
end.
dispatch(SubPid, Topic, Msg) -> SubPid ! {dispatch, Topic, Msg}.
%% @doc Has Route?
-spec has_route(emqttd_topic:topic()) -> boolean().
has_route(Topic) ->
ets:member(route, Topic).
%%%=============================================================================
%%% Internal Functions
%%%=============================================================================
%% @doc Lookup Routes
-spec lookup_routes(emqttd_topic:topic()) -> list(pid()).
lookup_routes(Topic) when is_binary(Topic) ->
case ets:member(route, Topic) of
true ->
try ets:lookup_element(route, Topic, 2) catch error:badarg -> [] end;
false ->
[]
end.
insert_routes([], _Pid) ->
%% @doc Add Route.
-spec add_route(emqttd_topic:topic(), pid()) -> ok.
add_route(Topic, Pid) when is_pid(Pid) ->
call(pick(Topic), {add_route, Topic, Pid}).
%% @doc Add Routes.
-spec add_routes(list(emqttd_topic:topic()), pid()) -> ok.
add_routes([], _Pid) ->
ok;
insert_routes(Topics, Pid) ->
{Routes, ReverseRoutes} = routes(Topics, Pid),
ets:insert(route, Routes),
ets:insert(reverse_route, ReverseRoutes).
add_routes([Topic], Pid) ->
add_route(Topic, Pid);
routes(Topics, Pid) ->
lists:unzip([{{Topic, Pid}, {Pid, Topic}} || Topic <- Topics]).
add_routes(Topics, Pid) ->
lists:foreach(fun({Router, Slice}) ->
call(Router, {add_routes, Slice, Pid})
end, slice(Topics)).
delete_route({Topic, Pid}) ->
ets:delete_object(reverse_route, {Pid, Topic}),
ets:delete_object(route, {Topic, Pid}).
%% @doc Delete Route.
-spec delete_route(emqttd_topic:topic(), pid()) -> ok.
delete_route(Topic, Pid) ->
cast(pick(Topic), {delete_route, Topic, Pid}).
delete_route_only({Topic, Pid}) ->
ets:delete_object(route, {Topic, Pid}).
%% @doc Delete Routes.
-spec delete_routes(list(emqttd_topic:topic()), pid()) -> ok.
delete_routes([Topic], Pid) ->
delete_route(Topic, Pid);
with_stats(Fun) ->
Ok = Fun(), setstats(), Ok.
delete_routes(Topics, Pid) ->
lists:foreach(fun({Router, Slice}) ->
cast(Router, {delete_routes, Slice, Pid})
end, slice(Topics)).
setstats() ->
lists:foreach(fun setstat/1, [{route, 'routes/count'},
{reverse_route, 'routes/reverse'}]).
%% @private Slice topics.
slice(Topics) ->
dict:to_list(lists:foldl(fun(Topic, Dict) ->
dict:append(pick(Topic), Topic, Dict)
end, dict:new(), Topics)).
setstat({Tab, Stat}) ->
emqttd_stats:setstat(Stat, ets:info(Tab, size)).
%% @private Pick a router.
pick(Topic) ->
gproc_pool:pick_worker(router, Topic).
stop(Id) when is_integer(Id) ->
gen_server2:call(emqttd:reg_name(?MODULE, Id), stop).
call(Router, Request) ->
gen_server2:call(Router, Request, infinity).
cast(Router, Msg) ->
gen_server2:cast(Router, Msg).
init([Pool, Id, StatsFun, Opts]) ->
%% Calls from pubsub should be scheduled first?
process_flag(priority, high),
?GPROC_POOL(join, Pool, Id),
emqttd:seed_now(),
AgingSecs = proplists:get_value(route_aging, Opts, 5),
%% Aging Timer
{ok, AgingTref} = start_tick(AgingSecs + random:uniform(AgingSecs)),
Aging = #aging{topics = dict:new(), time = AgingSecs, tref = AgingTref},
{ok, #state{pool = Pool, id = Id, statsfun = StatsFun, aging = Aging}}.
start_tick(Secs) ->
timer:send_interval(timer:seconds(Secs), {clean, aged}).
handle_call(stop, _From, State) ->
{stop, normal, ok, State};
handle_call({add_route, Topic, Pid}, _From, State) ->
ets:insert(route, {Topic, Pid}),
{reply, ok, setstats(State)};
handle_call({add_routes, Topics, Pid}, _From, State) ->
ets:insert(route, [{Topic, Pid} || Topic <- Topics]),
{reply, ok, setstats(State)};
handle_call(Req, _From, State) ->
?UNEXPECTED_REQ(Req, State).
handle_cast({delete_route, Topic, Pid}, State = #state{aging = Aging}) ->
ets:delete_object(route, {Topic, Pid}),
NewState =
case has_route(Topic) of
false -> State#state{aging = store_aged(Topic, Aging)};
true -> State
end,
{noreply, setstats(NewState)};
handle_cast({delete_routes, Topics, Pid}, State) ->
NewAging =
lists:foldl(fun(Topic, Aging) ->
ets:delete_object(route, {Topic, Pid}),
case has_route(Topic) of
false -> store_aged(Topic, Aging);
true -> Aging
end
end, State#state.aging, Topics),
{noreply, setstats(State#state{aging = NewAging})};
handle_cast(Msg, State) ->
?UNEXPECTED_MSG(Msg, State).
handle_info({clean, aged}, State = #state{aging = Aging}) ->
#aging{topics = Dict, time = Time} = Aging,
ByTime = emqttd_util:now_to_secs() - Time,
Dict1 = try_clean(ByTime, dict:to_list(Dict)),
NewAging = Aging#aging{topics = dict:from_list(Dict1)},
{noreply, State#state{aging = NewAging}, hibernate};
handle_info(Info, State) ->
?UNEXPECTED_INFO(Info, State).
terminate(_Reason, #state{pool = Pool, id = Id, aging = #aging{tref = TRef}}) ->
timer:cancel(TRef),
?GPROC_POOL(leave, Pool, Id).
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
try_clean(ByTime, List) ->
try_clean(ByTime, List, []).
try_clean(_ByTime, [], Acc) ->
Acc;
try_clean(ByTime, [{Topic, TS} | Left], Acc) ->
case has_route(Topic) of
false ->
try_clean2(ByTime, {Topic, TS}, Left, Acc);
true ->
try_clean(ByTime, Left, Acc)
end.
try_clean2(ByTime, {Topic, TS}, Left, Acc) when TS > ByTime ->
try_clean(ByTime, Left, [{Topic, TS} | Acc]);
try_clean2(ByTime, {Topic, _TS}, Left, Acc) ->
TopicR = #mqtt_topic{topic = Topic, node = node()},
case mnesia:transaction(fun try_remove_topic/1, [TopicR]) of
{atomic, _} -> ok;
{aborted, Error} -> lager:error("Clean Topic '~s' Error: ~p", [Topic, Error])
end,
try_clean(ByTime, Left, Acc).
try_remove_topic(TopicR = #mqtt_topic{topic = Topic}) ->
%% Lock topic first
case mnesia:wread({topic, Topic}) of
[] ->
ok; %% mnesia:abort(not_found);
[TopicR] ->
%% Remove topic and trie
delete_topic(TopicR),
emqttd_trie:delete(Topic);
_More ->
%% Remove topic only
delete_topic(TopicR)
end.
delete_topic(TopicR) ->
mnesia:delete_object(topic, TopicR, write).
store_aged(Topic, Aging = #aging{topics = Dict}) ->
Now = emqttd_util:now_to_secs(),
Aging#aging{topics = dict:store(Topic, Now, Dict)}.
setstats(State = #state{statsfun = StatsFun}) ->
StatsFun(route), State.

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -85,10 +85,7 @@ mnesia(copy) ->
%%------------------------------------------------------------------------------
-spec start_link(atom(), pos_integer()) -> {ok, pid()} | ignore | {error, any()}.
start_link(Pool, Id) ->
gen_server2:start_link({local, name(Id)}, ?MODULE, [Pool, Id], []).
name(Id) ->
list_to_atom("emqttd_sm_" ++ integer_to_list(Id)).
gen_server2:start_link({local, emqttd:reg_name(?MODULE, Id)}, ?MODULE, [Pool, Id], []).
%%------------------------------------------------------------------------------
%% @doc Start a session

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -143,7 +143,7 @@ setstats(Stat, MaxStat, Val) ->
%%%=============================================================================
init([]) ->
random:seed(os:timestamp()),
emqttd:seed_now(),
ets:new(?STATS_TAB, [set, public, named_table, {write_concurrency, true}]),
Topics = ?SYSTOP_CLIENTS ++ ?SYSTOP_SESSIONS ++ ?SYSTOP_PUBSUB ++ ?SYSTOP_RETAINED,
ets:insert(?STATS_TAB, [{Topic, 0} || Topic <- Topics]),

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
@ -31,6 +31,8 @@
-export([join/1, feed_var/3, is_queue/1, systop/1]).
-type topic() :: binary().
%-type type() :: static | dynamic.
-type word() :: '' | '+' | '#' | binary().
@ -39,7 +41,7 @@
-type triple() :: {root | binary(), word(), binary()}.
-export_type([word/0, triple/0]).
-export_type([topic/0, word/0, triple/0]).
-define(MAX_TOPIC_LEN, 4096).
@ -47,7 +49,7 @@
%% @doc Is wildcard topic?
%% @end
%%%-----------------------------------------------------------------------------
-spec wildcard(binary()) -> true | false.
-spec wildcard(topic()) -> true | false.
wildcard(Topic) when is_binary(Topic) ->
wildcard(words(Topic));
wildcard([]) ->
@ -64,8 +66,8 @@ wildcard([_H|T]) ->
%% @end
%%------------------------------------------------------------------------------
-spec match(Name, Filter) -> boolean() when
Name :: binary() | words(),
Filter :: binary() | words().
Name :: topic() | words(),
Filter :: topic() | words().
match(Name, Filter) when is_binary(Name) and is_binary(Filter) ->
match(words(Name), words(Filter));
match([], []) ->
@ -91,7 +93,7 @@ match([], [_H|_T2]) ->
%% @doc Validate Topic
%% @end
%%------------------------------------------------------------------------------
-spec validate({name | filter, binary()}) -> boolean().
-spec validate({name | filter, topic()}) -> boolean().
validate({_, <<>>}) ->
false;
validate({_, Topic}) when is_binary(Topic) and (size(Topic) > ?MAX_TOPIC_LEN) ->
@ -129,7 +131,7 @@ validate3(<<_/utf8, Rest/binary>>) ->
%% @doc Topic to Triples
%% @end
%%%-----------------------------------------------------------------------------
-spec triples(binary()) -> list(triple()).
-spec triples(topic()) -> list(triple()).
triples(Topic) when is_binary(Topic) ->
triples(words(Topic), root, []).
@ -154,7 +156,7 @@ bin(B) when is_binary(B) -> B.
%% @doc Split Topic Path to Words
%% @end
%%------------------------------------------------------------------------------
-spec words(binary()) -> words().
-spec words(topic()) -> words().
words(Topic) when is_binary(Topic) ->
[word(W) || W <- binary:split(Topic, <<"/">>, [global])].
@ -167,7 +169,7 @@ word(Bin) -> Bin.
%% @doc Queue is a special topic name that starts with "$Q/"
%% @end
%%------------------------------------------------------------------------------
-spec is_queue(binary()) -> boolean().
-spec is_queue(topic()) -> boolean().
is_queue(<<"$Q/", _Queue/binary>>) ->
true;
is_queue(_) ->

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

View File

@ -1,5 +1,5 @@
%%%-----------------------------------------------------------------------------
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
%%% Copyright (c) 2012-2016 eMQTT.IO, All Rights Reserved.
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal

Some files were not shown because too many files have changed in this diff Show More