zeroMQ初体验-34.发布/订阅模式进阶-克隆模式-下,结言

来源:互联网 发布:东风风神a30abs数据 编辑:程序博客网 时间:2024/05/18 01:42
 
服务器:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone server Model Six   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "bstar.c"   
  7. #include "kvmsg.c"   
  8.   
  9. //  Bstar reactor handlers   
  10. staticint s_snapshots  (zloop_t *loop, void *socket, void *args);   
  11. staticint s_collector  (zloop_t *loop, void *socket, void *args);   
  12. staticint s_flush_ttl  (zloop_t *loop, void *socket, void *args);   
  13. staticint s_send_hugz  (zloop_t *loop, void *socket, void *args);   
  14. staticint s_new_master (zloop_t *loop, void *unused, void *args);   
  15. staticint s_new_slave  (zloop_t *loop, void *unused, void *args);   
  16. staticint s_subscriber (zloop_t *loop, void *socket, void *args);   
  17.   
  18. //  Our server is defined by these properties  
  19. typedefstruct {   
  20.     zctx_t *ctx;                //  Context wrapper  
  21.     zhash_t *kvmap;             //  Key-value store  
  22.     bstar_t *bstar;             //  Bstar reactor core  
  23.     int64_t sequence;           //  How many updates we're at  
  24.     int port;                   //  Main port we're working on  
  25.     int peer;                   //  Main port of our peer  
  26.     void *publisher;            //  Publish updates and hugz  
  27.     void *collector;            //  Collect updates from clients  
  28.     void *subscriber;           //  Get updates from peer  
  29.     zlist_t *pending;           //  Pending updates from clients  
  30.     Bool primary;               //  TRUE if we're primary  
  31.     Bool master;                //  TRUE if we're master  
  32.     Bool slave;                 //  TRUE if we're slave  
  33. } clonesrv_t;   
  34.   
  35. int main (int argc, char *argv [])   
  36. {   
  37.     clonesrv_t *self = (clonesrv_t *) zmalloc (sizeof (clonesrv_t));   
  38.     if (argc == 2 && streq (argv [1], "-p")) {   
  39.         zclock_log ("I: primary master, waiting for backup (slave)");   
  40.         self->bstar = bstar_new (BSTAR_PRIMARY, "tcp://*:5003",   
  41.                                  "tcp://localhost:5004");   
  42.         bstar_voter (self->bstar, "tcp://*:5556", ZMQ_ROUTER,   
  43.                      s_snapshots, self);   
  44.         self->port = 5556;   
  45.         self->peer = 5566;   
  46.         self->primary = TRUE;   
  47.     }   
  48.     else  
  49.     if (argc == 2 && streq (argv [1], "-b")) {   
  50.         zclock_log ("I: backup slave, waiting for primary (master)");   
  51.         self->bstar = bstar_new (BSTAR_BACKUP, "tcp://*:5004",   
  52.                                  "tcp://localhost:5003");   
  53.         bstar_voter (self->bstar, "tcp://*:5566", ZMQ_ROUTER,   
  54.                      s_snapshots, self);   
  55.         self->port = 5566;   
  56.         self->peer = 5556;   
  57.         self->primary = FALSE;   
  58.     }   
  59.     else {   
  60.         printf ("Usage: clonesrv4 { -p | -b }\n");   
  61.         free (self);   
  62.         exit (0);   
  63.     }   
  64.     //  Primary server will become first master  
  65.     if (self->primary)   
  66.         self->kvmap = zhash_new ();   
  67.   
  68.     self->ctx = zctx_new ();   
  69.     self->pending = zlist_new ();   
  70.     bstar_set_verbose (self->bstar, TRUE);   
  71.   
  72.     //  Set up our clone server sockets   
  73.     self->publisher = zsocket_new (self->ctx, ZMQ_PUB);   
  74.     self->collector = zsocket_new (self->ctx, ZMQ_SUB);   
  75.     zsocket_bind (self->publisher, "tcp://*:%d", self->port + 1);   
  76.     zsocket_bind (self->collector, "tcp://*:%d", self->port + 2);   
  77.   
  78.     //  Set up our own clone client interface to peer  
  79.     self->subscriber = zsocket_new (self->ctx, ZMQ_SUB);   
  80.     zsocket_connect (self->subscriber, "tcp://localhost:%d", self->peer + 1);   
  81.   
  82.     //  Register state change handlers   
  83.     bstar_new_master (self->bstar, s_new_master, self);   
  84.     bstar_new_slave (self->bstar, s_new_slave, self);   
  85.   
  86.     //  Register our other handlers with the bstar reactor  
  87.     zloop_reader (bstar_zloop (self->bstar), self->collector, s_collector, self);   
  88.     zloop_timer  (bstar_zloop (self->bstar), 1000, 0, s_flush_ttl, self);   
  89.     zloop_timer  (bstar_zloop (self->bstar), 1000, 0, s_send_hugz, self);   
  90.   
  91.     //  Start the Bstar reactor   
  92.     bstar_start (self->bstar);   
  93.   
  94.     //  Interrupted, so shut down   
  95.     while (zlist_size (self->pending)) {   
  96.         kvmsg_t *kvmsg = (kvmsg_t *) zlist_pop (self->pending);   
  97.         kvmsg_destroy (&kvmsg);   
  98.     }   
  99.     zlist_destroy (&self->pending);   
  100.     bstar_destroy (&self->bstar);   
  101.     zhash_destroy (&self->kvmap);   
  102.     zctx_destroy (&self->ctx);   
  103.     free (self);   
  104.   
  105.     return 0;   
  106. }   
  107.   
  108. //  ---------------------------------------------------------------------  
  109. //  Send snapshots to clients who ask for them  
  110.   
  111. staticint s_send_single (char *key, void *data, void *args);   
  112.   
  113. //  Routing information for a key-value snapshot  
  114. typedefstruct {   
  115.     void *socket;           //  ROUTER socket to send to  
  116.     zframe_t *identity;     //  Identity of peer who requested state  
  117.     char *subtree;          //  Client subtree specification  
  118. } kvroute_t;   
  119.   
  120. staticint  
  121. s_snapshots (zloop_t *loop, void *snapshot, void *args)   
  122. {   
  123.     clonesrv_t *self = (clonesrv_t *) args;   
  124.   
  125.     zframe_t *identity = zframe_recv (snapshot);   
  126.     if (identity) {   
  127.         //  Request is in second frame of message  
  128.         char *request = zstr_recv (snapshot);   
  129.         char *subtree = NULL;   
  130.         if (streq (request, "ICANHAZ?")) {   
  131.             free (request);   
  132.             subtree = zstr_recv (snapshot);   
  133.         }   
  134.         else  
  135.             printf ("E: bad request, aborting\n");   
  136.   
  137.         if (subtree) {   
  138.             //  Send state socket to client  
  139.             kvroute_t routing = { snapshot, identity, subtree };   
  140.             zhash_foreach (self->kvmap, s_send_single, &routing);   
  141.   
  142.             //  Now send END message with sequence number  
  143.             zclock_log ("I: sending shapshot=%d", (int) self->sequence);   
  144.             zframe_send (&identity, snapshot, ZFRAME_MORE);   
  145.             kvmsg_t *kvmsg = kvmsg_new (self->sequence);   
  146.             kvmsg_set_key  (kvmsg, "KTHXBAI");   
  147.             kvmsg_set_body (kvmsg, (byte *) subtree, 0);   
  148.             kvmsg_send     (kvmsg, snapshot);   
  149.             kvmsg_destroy (&kvmsg);   
  150.             free (subtree);   
  151.         }   
  152.     }   
  153.     return 0;   
  154. }   
  155.   
  156. //  Send one state snapshot key-value pair to a socket  
  157. //  Hash item data is our kvmsg object, ready to send  
  158. staticint  
  159. s_send_single (char *key, void *data, void *args)   
  160. {   
  161.     kvroute_t *kvroute = (kvroute_t *) args;   
  162.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  163.     if (strlen (kvroute->subtree) <= strlen (kvmsg_key (kvmsg))   
  164.     &&  memcmp (kvroute->subtree,   
  165.                 kvmsg_key (kvmsg), strlen (kvroute->subtree)) == 0) {   
  166.         //  Send identity of recipient first  
  167.         zframe_send (&kvroute->identity,   
  168.             kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);   
  169.         kvmsg_send (kvmsg, kvroute->socket);   
  170.     }   
  171.     return 0;   
  172. }   
  173.   
  174. //  ---------------------------------------------------------------------  
  175. //  Collect updates from clients   
  176. //  If we're master, we apply these to the kvmap  
  177. //  If we're slave, or unsure, we queue them on our pending list  
  178.   
  179. staticint s_was_pending (clonesrv_t *self, kvmsg_t *kvmsg);   
  180.   
  181. staticint  
  182. s_collector (zloop_t *loop, void *collector, void *args)   
  183. {   
  184.     clonesrv_t *self = (clonesrv_t *) args;   
  185.   
  186.     kvmsg_t *kvmsg = kvmsg_recv (collector);   
  187.     kvmsg_dump (kvmsg);   
  188.     if (kvmsg) {   
  189.         if (self->master) {   
  190.             kvmsg_set_sequence (kvmsg, ++self->sequence);   
  191.             kvmsg_send (kvmsg, self->publisher);   
  192.             int ttl = atoi (kvmsg_get_prop (kvmsg, "ttl"));   
  193.             if (ttl)   
  194.                 kvmsg_set_prop (kvmsg, "ttl",   
  195.                     "%" PRId64, zclock_time () + ttl * 1000);   
  196.             kvmsg_store (&kvmsg, self->kvmap);   
  197.             zclock_log ("I: publishing update=%d", (int) self->sequence);   
  198.         }   
  199.         else {   
  200.             //  If we already got message from master, drop it, else  
  201.             //  hold on pending list   
  202.             if (s_was_pending (self, kvmsg))   
  203.                 kvmsg_destroy (&kvmsg);   
  204.             else  
  205.                 zlist_append (self->pending, kvmsg);   
  206.         }   
  207.     }   
  208.     return 0;   
  209. }   
  210.   
  211. //  If message was already on pending list, remove it and  
  212. //  return TRUE, else return FALSE.   
  213.   
  214. staticint  
  215. s_was_pending (clonesrv_t *self, kvmsg_t *kvmsg)   
  216. {   
  217.     kvmsg_t *held = (kvmsg_t *) zlist_first (self->pending);   
  218.     while (held) {   
  219.         if (memcmp (kvmsg_uuid (kvmsg),   
  220.                     kvmsg_uuid (held), sizeof (uuid_t)) == 0) {   
  221.             zlist_remove (self->pending, held);   
  222.             return TRUE;   
  223.         }   
  224.         held = (kvmsg_t *) zlist_next (self->pending);   
  225.     }   
  226.     return FALSE;   
  227. }   
  228.   
  229. //  ---------------------------------------------------------------------  
  230. //  Purge ephemeral values that have expired  
  231.   
  232. staticint s_flush_single (char *key, void *data, void *args);   
  233.   
  234. staticint  
  235. s_flush_ttl (zloop_t *loop, void *unused, void *args)   
  236. {   
  237.     clonesrv_t *self = (clonesrv_t *) args;   
  238.     zhash_foreach (self->kvmap, s_flush_single, args);   
  239.     return 0;   
  240. }   
  241.   
  242. //  If key-value pair has expired, delete it and publish the  
  243. //  fact to listening clients.   
  244. staticint  
  245. s_flush_single (char *key, void *data, void *args)   
  246. {   
  247.     clonesrv_t *self = (clonesrv_t *) args;   
  248.   
  249.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  250.     int64_t ttl;   
  251.     sscanf (kvmsg_get_prop (kvmsg, "ttl"), "%" PRId64, &ttl);   
  252.     if (ttl && zclock_time () >= ttl) {   
  253.         kvmsg_set_sequence (kvmsg, ++self->sequence);   
  254.         kvmsg_set_body (kvmsg, (byte *) "", 0);   
  255.         kvmsg_send (kvmsg, self->publisher);   
  256.         kvmsg_store (&kvmsg, self->kvmap);   
  257.         zclock_log ("I: publishing delete=%d", (int) self->sequence);   
  258.     }   
  259.     return 0;   
  260. }   
  261.   
  262. //  ---------------------------------------------------------------------  
  263. //  Send hugz to anyone listening on the publisher socket  
  264.   
  265. staticint  
  266. s_send_hugz (zloop_t *loop, void *unused, void *args)   
  267. {   
  268.     clonesrv_t *self = (clonesrv_t *) args;   
  269.   
  270.     kvmsg_t *kvmsg = kvmsg_new (self->sequence);   
  271.     kvmsg_set_key  (kvmsg, "HUGZ");   
  272.     kvmsg_set_body (kvmsg, (byte *) "", 0);   
  273.     kvmsg_send     (kvmsg, self->publisher);   
  274.     kvmsg_destroy (&kvmsg);   
  275.   
  276.     return 0;   
  277. }   
  278.   
  279. //  ---------------------------------------------------------------------  
  280. //  State change handlers   
  281. //  We're becoming master   
  282. //   
  283. //  The backup server applies its pending list to its own hash table,  
  284. //  and then starts to process state snapshot requests.  
  285.   
  286. staticint  
  287. s_new_master (zloop_t *loop, void *unused, void *args)   
  288. {   
  289.     clonesrv_t *self = (clonesrv_t *) args;   
  290.   
  291.     self->master = TRUE;   
  292.     self->slave = FALSE;   
  293.     zloop_cancel (bstar_zloop (self->bstar), self->subscriber);   
  294.   
  295.     //  Apply pending list to own hash table  
  296.     while (zlist_size (self->pending)) {   
  297.         kvmsg_t *kvmsg = (kvmsg_t *) zlist_pop (self->pending);   
  298.         kvmsg_set_sequence (kvmsg, ++self->sequence);   
  299.         kvmsg_send (kvmsg, self->publisher);   
  300.         kvmsg_store (&kvmsg, self->kvmap);   
  301.         zclock_log ("I: publishing pending=%d", (int) self->sequence);   
  302.     }   
  303.     return 0;   
  304. }   
  305.   
  306. //  ---------------------------------------------------------------------  
  307. //  We're becoming slave   
  308.   
  309. staticint  
  310. s_new_slave (zloop_t *loop, void *unused, void *args)   
  311. {   
  312.     clonesrv_t *self = (clonesrv_t *) args;   
  313.   
  314.     zhash_destroy (&self->kvmap);   
  315.     self->master = FALSE;   
  316.     self->slave = TRUE;   
  317.     zloop_reader (bstar_zloop (self->bstar), self->subscriber,   
  318.                   s_subscriber, self);   
  319.   
  320.     return 0;   
  321. }   
  322.   
  323. //  ---------------------------------------------------------------------  
  324. //  Collect updates from peer (master)   
  325. //  We're always slave when we get these updates  
  326.   
  327. staticint  
  328. s_subscriber (zloop_t *loop, void *subscriber, void *args)   
  329. {   
  330.     clonesrv_t *self = (clonesrv_t *) args;   
  331.     //  Get state snapshot if necessary   
  332.     if (self->kvmap == NULL) {   
  333.         self->kvmap = zhash_new ();   
  334.         void *snapshot = zsocket_new (self->ctx, ZMQ_DEALER);   
  335.         zsocket_connect (snapshot, "tcp://localhost:%d", self->peer);   
  336.         zclock_log ("I: asking for snapshot from: tcp://localhost:%d",   
  337.                     self->peer);   
  338.         zstr_send (snapshot, "ICANHAZ?");   
  339.         while (TRUE) {   
  340.             kvmsg_t *kvmsg = kvmsg_recv (snapshot);   
  341.             if (!kvmsg)   
  342.                 break;          //  Interrupted  
  343.             if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {   
  344.                 self->sequence = kvmsg_sequence (kvmsg);   
  345.                 kvmsg_destroy (&kvmsg);   
  346.                 break;          //  Done  
  347.             }   
  348.             kvmsg_store (&kvmsg, self->kvmap);   
  349.         }   
  350.         zclock_log ("I: received snapshot=%d", (int) self->sequence);   
  351.         zsocket_destroy (self->ctx, snapshot);   
  352.     }   
  353.     //  Find and remove update off pending list  
  354.     kvmsg_t *kvmsg = kvmsg_recv (subscriber);   
  355.     if (!kvmsg)   
  356.         return 0;   
  357.   
  358.     if (strneq (kvmsg_key (kvmsg), "HUGZ")) {   
  359.         if (!s_was_pending (self, kvmsg)) {   
  360.             //  If master update came before client update, flip it  
  361.             //  around, store master update (with sequence) on pending  
  362.             //  list and use to clear client update when it comes later  
  363.             zlist_append (self->pending, kvmsg_dup (kvmsg));   
  364.         }   
  365.         //  If update is more recent than our kvmap, apply it  
  366.         if (kvmsg_sequence (kvmsg) > self->sequence) {   
  367.             self->sequence = kvmsg_sequence (kvmsg);   
  368.             kvmsg_store (&kvmsg, self->kvmap);   
  369.             zclock_log ("I: received update=%d", (int) self->sequence);   
  370.         }   
  371.         else  
  372.             kvmsg_destroy (&kvmsg);   
  373.     }   
  374.     else  
  375.         kvmsg_destroy (&kvmsg);   
  376.   
  377.     return 0;   
  378. }  

代码不短,不过作者的牢骚更长。(貌似花了一周的时间)

当然作为一个靠谱的模型,总会制定一些规范给某些不太靠谱的人:http://rfc.zeromq.org/spec:12

至此,整个教程算是告一段落了。(之所以这最后一个模型分了三段,着实是代码多了些)
教程结束了,学习才刚开始。至于会不会再有后续,诚如guide结尾:
More coming soon…


结言:
虽然知道翻译技术文章有难度,但着实还是吓着了,在写第一章的时候就打了退堂鼓。终究在自我安慰、勉励下完成了这个系列的笔记(退一步)。好吧,我承认代码、图示占了大比例,不过,好歹算是有始有终的完成了。
原计划一周时间结束的,由于诸多原因(磨蹭,消极,退堂鼓)前后竟然跨了两个多月,总算咬牙坚持了下来,其实不敢说学到了很多,自从中部python的代码不再时,几乎就没有再自己验证代码的可行和逻辑了。写本系列,更多的是自个儿跟自个儿过不去(俺就不信写不完了!)折腾到最后,多少也是有些收获的(谁折腾谁知道~)
回首看看,也就这样了,倒是有些"天凉好个秋"的意味。
也罢,哦了
原创粉丝点击