zeroMQ初体验-33.发布/订阅模式进阶-克隆模式-中

来源:互联网 发布:东风风神a30abs数据 编辑:程序博客网 时间:2024/05/21 11:29
 
临时缓存
现实中,比如DNS服务器,可以算是一个典型案例。临时存储一个节点,如果节点小时,那么该存储也会随之灰飞,所以,"过期"也是一个靠谱的需求。
由于有新的需求提出,我们的key-value库也得做些相应的改动:
C代码 复制代码 收藏代码
  1. /*  ===================================================================== 
  2.     kvmsg - key-value message class for example applications 
  3.  
  4.     --------------------------------------------------------------------- 
  5.     Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com> 
  6.     Copyright other contributors as noted in the AUTHORS file. 
  7.  
  8.     This file is part of the ZeroMQ Guide: http://zguide.zeromq.org 
  9.  
  10.     This is free software; you can redistribute it and/or modify it under 
  11.     the terms of the GNU Lesser General Public License as published by 
  12.     the Free Software Foundation; either version 3 of the License, or (at 
  13.     your option) any later version.  
  14.  
  15.     This software is distributed in the hope that it will be useful, but 
  16.     WITHOUT ANY WARRANTY; without even the implied warranty of 
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
  18.     Lesser General Public License for more details. 
  19.  
  20.     You should have received a copy of the GNU Lesser General Public 
  21.     License along with this program. If not, see  
  22.     <http://www.gnu.org/licenses/>.  
  23.     ===================================================================== 
  24. */  
  25.   
  26. #include "kvmsg.h"   
  27. #include <uuid/uuid.h>   
  28. #include "zlist.h"   
  29.   
  30. //  Keys are short strings   
  31. #define KVMSG_KEY_MAX   255   
  32.   
  33. //  Message is formatted on wire as 4 frames:  
  34. //  frame 0: key (0MQ string)   
  35. //  frame 1: sequence (8 bytes, network order)  
  36. //  frame 2: uuid (blob, 16 bytes)   
  37. //  frame 3: properties (0MQ string)   
  38. //  frame 4: body (blob)   
  39. #define FRAME_KEY       0   
  40. #define FRAME_SEQ       1   
  41. #define FRAME_UUID      2   
  42. #define FRAME_PROPS     3   
  43. #define FRAME_BODY      4   
  44. #define KVMSG_FRAMES    5   
  45.   
  46. //  Structure of our class   
  47. struct _kvmsg {   
  48.     //  Presence indicators for each frame  
  49.     int present [KVMSG_FRAMES];   
  50.     //  Corresponding 0MQ message frames, if any  
  51.     zmq_msg_t frame [KVMSG_FRAMES];   
  52.     //  Key, copied into safe C string   
  53.     char key [KVMSG_KEY_MAX + 1];   
  54.     //  List of properties, as name=value strings  
  55.     zlist_t *props;   
  56.     size_t props_size;   
  57. };   
  58.   
  59. //  Serialize list of properties to a message frame  
  60. staticvoid  
  61. s_encode_props (kvmsg_t *self)   
  62. {   
  63.     zmq_msg_t *msg = &self->frame [FRAME_PROPS];   
  64.     if (self->present [FRAME_PROPS])   
  65.         zmq_msg_close (msg);   
  66.   
  67.     zmq_msg_init_size (msg, self->props_size);   
  68.     char *prop = zlist_first (self->props);   
  69.     char *dest = (char *) zmq_msg_data (msg);   
  70.     while (prop) {   
  71.         strcpy (dest, prop);   
  72.         dest += strlen (prop);   
  73.         *dest++ = '\n';   
  74.         prop = zlist_next (self->props);   
  75.     }   
  76.     self->present [FRAME_PROPS] = 1;   
  77. }   
  78.   
  79. //  Rebuild properties list from message frame  
  80. staticvoid  
  81. s_decode_props (kvmsg_t *self)   
  82. {   
  83.     zmq_msg_t *msg = &self->frame [FRAME_PROPS];   
  84.     self->props_size = 0;   
  85.     while (zlist_size (self->props))   
  86.         free (zlist_pop (self->props));   
  87.   
  88.     size_t remainder = zmq_msg_size (msg);   
  89.     char *prop = (char *) zmq_msg_data (msg);   
  90.     char *eoln = memchr (prop, '\n', remainder);   
  91.     while (eoln) {   
  92.         *eoln = 0;   
  93.         zlist_append (self->props, strdup (prop));   
  94.         self->props_size += strlen (prop) + 1;   
  95.         remainder -= strlen (prop) + 1;   
  96.         prop = eoln + 1;   
  97.         eoln = memchr (prop, '\n', remainder);   
  98.     }   
  99. }   
  100.   
  101. //  ---------------------------------------------------------------------  
  102. //  Constructor, sets sequence as provided  
  103.   
  104. kvmsg_t *   
  105. kvmsg_new (int64_t sequence)   
  106. {   
  107.     kvmsg_t   
  108.         *self;   
  109.   
  110.     self = (kvmsg_t *) zmalloc (sizeof (kvmsg_t));   
  111.     self->props = zlist_new ();   
  112.     kvmsg_set_sequence (self, sequence);   
  113.     return self;   
  114. }   
  115.   
  116. //  ---------------------------------------------------------------------  
  117. //  Destructor   
  118.   
  119. //  Free shim, compatible with zhash_free_fn  
  120. void  
  121. kvmsg_free (void *ptr)   
  122. {   
  123.     if (ptr) {   
  124.         kvmsg_t *self = (kvmsg_t *) ptr;   
  125.         //  Destroy message frames if any   
  126.         int frame_nbr;   
  127.         for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++)   
  128.             if (self->present [frame_nbr])   
  129.                 zmq_msg_close (&self->frame [frame_nbr]);   
  130.   
  131.         //  Destroy property list   
  132.         while (zlist_size (self->props))   
  133.             free (zlist_pop (self->props));   
  134.         zlist_destroy (&self->props);   
  135.   
  136.         //  Free object itself   
  137.         free (self);   
  138.     }   
  139. }   
  140.   
  141. void  
  142. kvmsg_destroy (kvmsg_t **self_p)   
  143. {   
  144.     assert (self_p);   
  145.     if (*self_p) {   
  146.         kvmsg_free (*self_p);   
  147.         *self_p = NULL;   
  148.     }   
  149. }   
  150.   
  151. //  ---------------------------------------------------------------------  
  152. //  Create duplicate of kvmsg   
  153.   
  154. kvmsg_t *   
  155. kvmsg_dup (kvmsg_t *self)   
  156. {   
  157.     kvmsg_t *kvmsg = kvmsg_new (0);   
  158.     int frame_nbr;   
  159.     for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {   
  160.         if (self->present [frame_nbr]) {   
  161.             zmq_msg_t *src = &self->frame [frame_nbr];   
  162.             zmq_msg_t *dst = &kvmsg->frame [frame_nbr];   
  163.             zmq_msg_init_size (dst, zmq_msg_size (src));   
  164.             memcpy (zmq_msg_data (dst),   
  165.                     zmq_msg_data (src), zmq_msg_size (src));   
  166.             kvmsg->present [frame_nbr] = 1;   
  167.         }   
  168.     }   
  169.     kvmsg->props = zlist_copy (self->props);   
  170.     return kvmsg;   
  171. }   
  172.   
  173. //  ---------------------------------------------------------------------  
  174. //  Reads key-value message from socket, returns new kvmsg instance.  
  175.   
  176. kvmsg_t *   
  177. kvmsg_recv (void *socket)   
  178. {   
  179.     assert (socket);   
  180.     kvmsg_t *self = kvmsg_new (0);   
  181.   
  182.     //  Read all frames off the wire, reject if bogus  
  183.     int frame_nbr;   
  184.     for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {   
  185.         if (self->present [frame_nbr])   
  186.             zmq_msg_close (&self->frame [frame_nbr]);   
  187.         zmq_msg_init (&self->frame [frame_nbr]);   
  188.         self->present [frame_nbr] = 1;   
  189.         if (zmq_recvmsg (socket, &self->frame [frame_nbr], 0) == -1) {   
  190.             kvmsg_destroy (&self);   
  191.             break;   
  192.         }   
  193.         //  Verify multipart framing   
  194.         int rcvmore = (frame_nbr < KVMSG_FRAMES - 1)? 1: 0;   
  195.         if (zsockopt_rcvmore (socket) != rcvmore) {   
  196.             kvmsg_destroy (&self);   
  197.             break;   
  198.         }   
  199.     }   
  200.     if (self)   
  201.         s_decode_props (self);   
  202.     return self;   
  203. }   
  204.   
  205. //  ---------------------------------------------------------------------  
  206. //  Send key-value message to socket; any empty frames are sent as such.  
  207.   
  208. void  
  209. kvmsg_send (kvmsg_t *self, void *socket)   
  210. {   
  211.     assert (self);   
  212.     assert (socket);   
  213.   
  214.     s_encode_props (self);   
  215.     int frame_nbr;   
  216.     for (frame_nbr = 0; frame_nbr < KVMSG_FRAMES; frame_nbr++) {   
  217.         zmq_msg_t copy;   
  218.         zmq_msg_init (&copy);   
  219.         if (self->present [frame_nbr])   
  220.             zmq_msg_copy (&copy, &self->frame [frame_nbr]);   
  221.         zmq_sendmsg (socket, &copy,   
  222.             (frame_nbr < KVMSG_FRAMES - 1)? ZMQ_SNDMORE: 0);   
  223.         zmq_msg_close (&copy);   
  224.     }   
  225. }   
  226.   
  227. //  ---------------------------------------------------------------------  
  228. //  Return key from last read message, if any, else NULL  
  229.   
  230. char *   
  231. kvmsg_key (kvmsg_t *self)   
  232. {   
  233.     assert (self);   
  234.     if (self->present [FRAME_KEY]) {   
  235.         if (!*self->key) {   
  236.             size_t size = zmq_msg_size (&self->frame [FRAME_KEY]);   
  237.             if (size > KVMSG_KEY_MAX)   
  238.                 size = KVMSG_KEY_MAX;   
  239.             memcpy (self->key,   
  240.                 zmq_msg_data (&self->frame [FRAME_KEY]), size);   
  241.             self->key [size] = 0;   
  242.         }   
  243.         return self->key;   
  244.     }   
  245.     else  
  246.         return NULL;   
  247. }   
  248.   
  249. //  ---------------------------------------------------------------------  
  250. //  Return sequence nbr from last read message, if any  
  251.   
  252. int64_t   
  253. kvmsg_sequence (kvmsg_t *self)   
  254. {   
  255.     assert (self);   
  256.     if (self->present [FRAME_SEQ]) {   
  257.         assert (zmq_msg_size (&self->frame [FRAME_SEQ]) == 8);   
  258.         byte *source = zmq_msg_data (&self->frame [FRAME_SEQ]);   
  259.         int64_t sequence = ((int64_t) (source [0]) << 56)   
  260.                          + ((int64_t) (source [1]) << 48)   
  261.                          + ((int64_t) (source [2]) << 40)   
  262.                          + ((int64_t) (source [3]) << 32)   
  263.                          + ((int64_t) (source [4]) << 24)   
  264.                          + ((int64_t) (source [5]) << 16)   
  265.                          + ((int64_t) (source [6]) << 8)   
  266.                          +  (int64_t) (source [7]);   
  267.         return sequence;   
  268.     }   
  269.     else  
  270.         return 0;   
  271. }   
  272.   
  273. //  ---------------------------------------------------------------------  
  274. //  Return UUID from last read message, if any, else NULL  
  275.   
  276. byte *   
  277. kvmsg_uuid (kvmsg_t *self)   
  278. {   
  279.     assert (self);   
  280.     if (self->present [FRAME_UUID]   
  281.     &&  zmq_msg_size (&self->frame [FRAME_UUID]) == sizeof (uuid_t))   
  282.         return (byte *) zmq_msg_data (&self->frame [FRAME_UUID]);   
  283.     else  
  284.         return NULL;   
  285. }   
  286.   
  287. //  ---------------------------------------------------------------------  
  288. //  Return body from last read message, if any, else NULL  
  289.   
  290. byte *   
  291. kvmsg_body (kvmsg_t *self)   
  292. {   
  293.     assert (self);   
  294.     if (self->present [FRAME_BODY])   
  295.         return (byte *) zmq_msg_data (&self->frame [FRAME_BODY]);   
  296.     else  
  297.         return NULL;   
  298. }   
  299.   
  300. //  ---------------------------------------------------------------------  
  301. //  Return body size from last read message, if any, else zero  
  302.   
  303. size_t  
  304. kvmsg_size (kvmsg_t *self)   
  305. {   
  306.     assert (self);   
  307.     if (self->present [FRAME_BODY])   
  308.         return zmq_msg_size (&self->frame [FRAME_BODY]);   
  309.     else  
  310.         return 0;   
  311. }   
  312.   
  313. //  ---------------------------------------------------------------------  
  314. //  Set message key as provided   
  315.   
  316. void  
  317. kvmsg_set_key (kvmsg_t *self, char *key)   
  318. {   
  319.     assert (self);   
  320.     zmq_msg_t *msg = &self->frame [FRAME_KEY];   
  321.     if (self->present [FRAME_KEY])   
  322.         zmq_msg_close (msg);   
  323.     zmq_msg_init_size (msg, strlen (key));   
  324.     memcpy (zmq_msg_data (msg), key, strlen (key));   
  325.     self->present [FRAME_KEY] = 1;   
  326. }   
  327.   
  328. //  ---------------------------------------------------------------------  
  329. //  Set message sequence number   
  330.   
  331. void  
  332. kvmsg_set_sequence (kvmsg_t *self, int64_t sequence)   
  333. {   
  334.     assert (self);   
  335.     zmq_msg_t *msg = &self->frame [FRAME_SEQ];   
  336.     if (self->present [FRAME_SEQ])   
  337.         zmq_msg_close (msg);   
  338.     zmq_msg_init_size (msg, 8);   
  339.   
  340.     byte *source = zmq_msg_data (msg);   
  341.     source [0] = (byte) ((sequence >> 56) & 255);   
  342.     source [1] = (byte) ((sequence >> 48) & 255);   
  343.     source [2] = (byte) ((sequence >> 40) & 255);   
  344.     source [3] = (byte) ((sequence >> 32) & 255);   
  345.     source [4] = (byte) ((sequence >> 24) & 255);   
  346.     source [5] = (byte) ((sequence >> 16) & 255);   
  347.     source [6] = (byte) ((sequence >> 8)  & 255);   
  348.     source [7] = (byte) ((sequence)       & 255);   
  349.   
  350.     self->present [FRAME_SEQ] = 1;   
  351. }   
  352.   
  353. //  ---------------------------------------------------------------------  
  354. //  Set message UUID to generated value   
  355.   
  356. void  
  357. kvmsg_set_uuid (kvmsg_t *self)   
  358. {   
  359.     assert (self);   
  360.     zmq_msg_t *msg = &self->frame [FRAME_UUID];   
  361.     uuid_t uuid;   
  362.     uuid_generate (uuid);   
  363.     if (self->present [FRAME_UUID])   
  364.         zmq_msg_close (msg);   
  365.     zmq_msg_init_size (msg, sizeof (uuid));   
  366.     memcpy (zmq_msg_data (msg), uuid, sizeof (uuid));   
  367.     self->present [FRAME_UUID] = 1;   
  368. }   
  369.   
  370. //  ---------------------------------------------------------------------  
  371. //  Set message body   
  372.   
  373. void  
  374. kvmsg_set_body (kvmsg_t *self, byte *body, size_t size)   
  375. {   
  376.     assert (self);   
  377.     zmq_msg_t *msg = &self->frame [FRAME_BODY];   
  378.     if (self->present [FRAME_BODY])   
  379.         zmq_msg_close (msg);   
  380.     self->present [FRAME_BODY] = 1;   
  381.     zmq_msg_init_size (msg, size);   
  382.     memcpy (zmq_msg_data (msg), body, size);   
  383. }   
  384.   
  385. //  ---------------------------------------------------------------------  
  386. //  Set message key using printf format   
  387.   
  388. void  
  389. kvmsg_fmt_key (kvmsg_t *self, char *format, …)   
  390. {   
  391.     char value [KVMSG_KEY_MAX + 1];   
  392.     va_list args;   
  393.   
  394.     assert (self);   
  395.     va_start (args, format);   
  396.     vsnprintf (value, KVMSG_KEY_MAX, format, args);   
  397.     va_end (args);   
  398.     kvmsg_set_key (self, value);   
  399. }   
  400.   
  401. //  ---------------------------------------------------------------------  
  402. //  Set message body using printf format   
  403.   
  404. void  
  405. kvmsg_fmt_body (kvmsg_t *self, char *format, …)   
  406. {   
  407.     char value [255 + 1];   
  408.     va_list args;   
  409.   
  410.     assert (self);   
  411.     va_start (args, format);   
  412.     vsnprintf (value, 255, format, args);   
  413.     va_end (args);   
  414.     kvmsg_set_body (self, (byte *) value, strlen (value));   
  415. }   
  416.   
  417. //  ---------------------------------------------------------------------  
  418. //  Get message property, if set, else ""   
  419.   
  420. char *   
  421. kvmsg_get_prop (kvmsg_t *self, char *name)   
  422. {   
  423.     assert (strchr (name, '=') == NULL);   
  424.     char *prop = zlist_first (self->props);   
  425.     size_t namelen = strlen (name);   
  426.     while (prop) {   
  427.         if (strlen (prop) > namelen   
  428.         &&  memcmp (prop, name, namelen) == 0   
  429.         &&  prop [namelen] == '=')   
  430.             return prop + namelen + 1;   
  431.         prop = zlist_next (self->props);   
  432.     }   
  433.     return"";   
  434. }   
  435.   
  436. //  ---------------------------------------------------------------------  
  437. //  Set message property   
  438. //  Names cannot contain '='. Max length of value is 255 chars.  
  439.   
  440. void  
  441. kvmsg_set_prop (kvmsg_t *self, char *name, char *format, …)   
  442. {   
  443.     assert (strchr (name, '=') == NULL);   
  444.   
  445.     char value [255 + 1];   
  446.     va_list args;   
  447.     assert (self);   
  448.     va_start (args, format);   
  449.     vsnprintf (value, 255, format, args);   
  450.     va_end (args);   
  451.   
  452.     //  Allocate name=value string   
  453.     char *prop = malloc (strlen (name) + strlen (value) + 2);   
  454.   
  455.     //  Remove existing property if any   
  456.     sprintf (prop, "%s=", name);   
  457.     char *existing = zlist_first (self->props);   
  458.     while (existing) {   
  459.         if (memcmp (prop, existing, strlen (prop)) == 0) {   
  460.             self->props_size -= strlen (existing) + 1;   
  461.             zlist_remove (self->props, existing);   
  462.             free (existing);   
  463.             break;   
  464.         }   
  465.         existing = zlist_next (self->props);   
  466.     }   
  467.     //  Add new name=value property string  
  468.     strcat (prop, value);   
  469.     zlist_append (self->props, prop);   
  470.     self->props_size += strlen (prop) + 1;   
  471. }   
  472.   
  473. //  ---------------------------------------------------------------------  
  474. //  Store entire kvmsg into hash map, if key/value are set.  
  475. //  Nullifies kvmsg reference, and destroys automatically when no longer  
  476. //  needed. If value is empty, deletes any previous value from store.  
  477.   
  478. void  
  479. kvmsg_store (kvmsg_t **self_p, zhash_t *hash)   
  480. {   
  481.     assert (self_p);   
  482.     if (*self_p) {   
  483.         kvmsg_t *self = *self_p;   
  484.         assert (self);   
  485.         if (kvmsg_size (self)) {   
  486.             if (self->present [FRAME_KEY]   
  487.             &&  self->present [FRAME_BODY]) {   
  488.                 zhash_update (hash, kvmsg_key (self), self);   
  489.                 zhash_freefn (hash, kvmsg_key (self), kvmsg_free);   
  490.             }   
  491.         }   
  492.         else  
  493.             zhash_delete (hash, kvmsg_key (self));   
  494.   
  495.         *self_p = NULL;   
  496.     }   
  497. }   
  498.   
  499. //  ---------------------------------------------------------------------  
  500. //  Dump message to stderr, for debugging and tracing  
  501.   
  502. void  
  503. kvmsg_dump (kvmsg_t *self)   
  504. {   
  505.     if (self) {   
  506.         if (!self) {   
  507.             fprintf (stderr, "NULL");   
  508.             return;   
  509.         }   
  510.         size_t size = kvmsg_size (self);   
  511.         byte  *body = kvmsg_body (self);   
  512.         fprintf (stderr, "[seq:%" PRId64 "]", kvmsg_sequence (self));   
  513.         fprintf (stderr, "[key:%s]", kvmsg_key (self));   
  514.         fprintf (stderr, "[size:%zd] ", size);   
  515.         if (zlist_size (self->props)) {   
  516.             fprintf (stderr, "[");   
  517.             char *prop = zlist_first (self->props);   
  518.             while (prop) {   
  519.                 fprintf (stderr, "%s;", prop);   
  520.                 prop = zlist_next (self->props);   
  521.             }   
  522.             fprintf (stderr, "]");   
  523.         }   
  524.         int char_nbr;   
  525.         for (char_nbr = 0; char_nbr < size; char_nbr++)   
  526.             fprintf (stderr, "%02X", body [char_nbr]);   
  527.         fprintf (stderr, "\n");   
  528.     }   
  529.     else  
  530.         fprintf (stderr, "NULL message\n");   
  531. }   
  532.   
  533. //  ---------------------------------------------------------------------  
  534. //  Runs self test of class   
  535.   
  536. int  
  537. kvmsg_test (int verbose)   
  538. {   
  539.     kvmsg_t   
  540.         *kvmsg;   
  541.   
  542.     printf (" * kvmsg: ");   
  543.   
  544.     //  Prepare our context and sockets   
  545.     zctx_t *ctx = zctx_new ();   
  546.     void *output = zsocket_new (ctx, ZMQ_DEALER);   
  547.     int rc = zmq_bind (output, "ipc://kvmsg_selftest.ipc");   
  548.     assert (rc == 0);   
  549.     void *input = zsocket_new (ctx, ZMQ_DEALER);   
  550.     rc = zmq_connect (input, "ipc://kvmsg_selftest.ipc");   
  551.     assert (rc == 0);   
  552.   
  553.     zhash_t *kvmap = zhash_new ();   
  554.   
  555.     //  Test send and receive of simple message  
  556.     kvmsg = kvmsg_new (1);   
  557.     kvmsg_set_key  (kvmsg, "key");   
  558.     kvmsg_set_uuid (kvmsg);   
  559.     kvmsg_set_body (kvmsg, (byte *) "body", 4);   
  560.     if (verbose)   
  561.         kvmsg_dump (kvmsg);   
  562.     kvmsg_send (kvmsg, output);   
  563.     kvmsg_store (&kvmsg, kvmap);   
  564.   
  565.     kvmsg = kvmsg_recv (input);   
  566.     if (verbose)   
  567.         kvmsg_dump (kvmsg);   
  568.     assert (streq (kvmsg_key (kvmsg), "key"));   
  569.     kvmsg_store (&kvmsg, kvmap);   
  570.   
  571.     //  Test send and receive of message with properties  
  572.     kvmsg = kvmsg_new (2);   
  573.     kvmsg_set_prop (kvmsg, "prop1", "value1");   
  574.     kvmsg_set_prop (kvmsg, "prop2", "value1");   
  575.     kvmsg_set_prop (kvmsg, "prop2", "value2");   
  576.     kvmsg_set_key  (kvmsg, "key");   
  577.     kvmsg_set_uuid (kvmsg);   
  578.     kvmsg_set_body (kvmsg, (byte *) "body", 4);   
  579.     assert (streq (kvmsg_get_prop (kvmsg, "prop2"), "value2"));   
  580.     if (verbose)   
  581.         kvmsg_dump (kvmsg);   
  582.     kvmsg_send (kvmsg, output);   
  583.     kvmsg_destroy (&kvmsg);   
  584.   
  585.     kvmsg = kvmsg_recv (input);   
  586.     if (verbose)   
  587.         kvmsg_dump (kvmsg);   
  588.     assert (streq (kvmsg_key (kvmsg), "key"));   
  589.     assert (streq (kvmsg_get_prop (kvmsg, "prop2"), "value2"));   
  590.     kvmsg_destroy (&kvmsg);   
  591.   
  592.     //  Shutdown and destroy all objects   
  593.     zhash_destroy (&kvmap);   
  594.     zctx_destroy (&ctx);   
  595.   
  596.     printf ("OK\n");   
  597.     return 0;   
  598. }  

服务器:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone server Model Five   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "kvmsg.c"   
  7.   
  8. //  zloop reactor handlers   
  9. staticint s_snapshots  (zloop_t *loop, void *socket, void *args);   
  10. staticint s_collector  (zloop_t *loop, void *socket, void *args);   
  11. staticint s_flush_ttl  (zloop_t *loop, void *socket, void *args);   
  12.   
  13. //  Our server is defined by these properties  
  14. typedefstruct {   
  15.     zctx_t *ctx;                //  Context wrapper  
  16.     zhash_t *kvmap;             //  Key-value store  
  17.     zloop_t *loop;              //  zloop reactor  
  18.     int port;                   //  Main port we're working on  
  19.     int64_t sequence;           //  How many updates we're at  
  20.     void *snapshot;             //  Handle snapshot requests  
  21.     void *publisher;            //  Publish updates to clients  
  22.     void *collector;            //  Collect updates from clients  
  23. } clonesrv_t;   
  24.   
  25. int main (void)   
  26. {   
  27.     clonesrv_t *self = (clonesrv_t *) zmalloc (sizeof (clonesrv_t));   
  28.   
  29.     self->port = 5556;   
  30.     self->ctx = zctx_new ();   
  31.     self->kvmap = zhash_new ();   
  32.     self->loop = zloop_new ();   
  33.     zloop_set_verbose (self->loop, FALSE);   
  34.   
  35.     //  Set up our clone server sockets   
  36.     self->snapshot  = zsocket_new (self->ctx, ZMQ_ROUTER);   
  37.     self->publisher = zsocket_new (self->ctx, ZMQ_PUB);   
  38.     self->collector = zsocket_new (self->ctx, ZMQ_PULL);   
  39.     zsocket_bind (self->snapshot,  "tcp://*:%d", self->port);   
  40.     zsocket_bind (self->publisher, "tcp://*:%d", self->port + 1);   
  41.     zsocket_bind (self->collector, "tcp://*:%d", self->port + 2);   
  42.   
  43.     //  Register our handlers with reactor  
  44.     zloop_reader (self->loop, self->snapshot, s_snapshots, self);   
  45.     zloop_reader (self->loop, self->collector, s_collector, self);   
  46.     zloop_timer  (self->loop, 1000, 0, s_flush_ttl, self);   
  47.   
  48.     //  Run reactor until process interrupted  
  49.     zloop_start (self->loop);   
  50.   
  51.     zloop_destroy (&self->loop);   
  52.     zhash_destroy (&self->kvmap);   
  53.     zctx_destroy (&self->ctx);   
  54.     free (self);   
  55.     return 0;   
  56. }   
  57.   
  58. //  ---------------------------------------------------------------------  
  59. //  Send snapshots to clients who ask for them  
  60.   
  61. staticint s_send_single (char *key, void *data, void *args);   
  62.   
  63. //  Routing information for a key-value snapshot  
  64. typedefstruct {   
  65.     void *socket;           //  ROUTER socket to send to  
  66.     zframe_t *identity;     //  Identity of peer who requested state  
  67.     char *subtree;          //  Client subtree specification  
  68. } kvroute_t;   
  69.   
  70. staticint  
  71. s_snapshots (zloop_t *loop, void *snapshot, void *args)   
  72. {   
  73.     clonesrv_t *self = (clonesrv_t *) args;   
  74.   
  75.     zframe_t *identity = zframe_recv (snapshot);   
  76.     if (identity) {   
  77.         //  Request is in second frame of message  
  78.         char *request = zstr_recv (snapshot);   
  79.         char *subtree = NULL;   
  80.         if (streq (request, "ICANHAZ?")) {   
  81.             free (request);   
  82.             subtree = zstr_recv (snapshot);   
  83.         }   
  84.         else  
  85.             printf ("E: bad request, aborting\n");   
  86.   
  87.         if (subtree) {   
  88.             //  Send state socket to client  
  89.             kvroute_t routing = { snapshot, identity, subtree };   
  90.             zhash_foreach (self->kvmap, s_send_single, &routing);   
  91.   
  92.             //  Now send END message with sequence number  
  93.             zclock_log ("I: sending shapshot=%d", (int) self->sequence);   
  94.             zframe_send (&identity, snapshot, ZFRAME_MORE);   
  95.             kvmsg_t *kvmsg = kvmsg_new (self->sequence);   
  96.             kvmsg_set_key  (kvmsg, "KTHXBAI");   
  97.             kvmsg_set_body (kvmsg, (byte *) subtree, 0);   
  98.             kvmsg_send     (kvmsg, snapshot);   
  99.             kvmsg_destroy (&kvmsg);   
  100.             free (subtree);   
  101.         }   
  102.     }   
  103.     return 0;   
  104. }   
  105.   
  106. //  Send one state snapshot key-value pair to a socket  
  107. //  Hash item data is our kvmsg object, ready to send  
  108. staticint  
  109. s_send_single (char *key, void *data, void *args)   
  110. {   
  111.     kvroute_t *kvroute = (kvroute_t *) args;   
  112.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  113.     if (strlen (kvroute->subtree) <= strlen (kvmsg_key (kvmsg))   
  114.     &&  memcmp (kvroute->subtree,   
  115.                 kvmsg_key (kvmsg), strlen (kvroute->subtree)) == 0) {   
  116.         //  Send identity of recipient first  
  117.         zframe_send (&kvroute->identity,   
  118.             kvroute->socket, ZFRAME_MORE + ZFRAME_REUSE);   
  119.         kvmsg_send (kvmsg, kvroute->socket);   
  120.     }   
  121.     return 0;   
  122. }   
  123.   
  124. //  ---------------------------------------------------------------------  
  125. //  Collect updates from clients   
  126.   
  127. staticint  
  128. s_collector (zloop_t *loop, void *collector, void *args)   
  129. {   
  130.     clonesrv_t *self = (clonesrv_t *) args;   
  131.   
  132.     kvmsg_t *kvmsg = kvmsg_recv (collector);   
  133.     if (kvmsg) {   
  134.         kvmsg_set_sequence (kvmsg, ++self->sequence);   
  135.         kvmsg_send (kvmsg, self->publisher);   
  136.         int ttl = atoi (kvmsg_get_prop (kvmsg, "ttl"));   
  137.         if (ttl)   
  138.             kvmsg_set_prop (kvmsg, "ttl",   
  139.                 "%" PRId64, zclock_time () + ttl * 1000);   
  140.         kvmsg_store (&kvmsg, self->kvmap);   
  141.         zclock_log ("I: publishing update=%d", (int) self->sequence);   
  142.     }   
  143.     return 0;   
  144. }   
  145.   
  146. //  ---------------------------------------------------------------------  
  147. //  Purge ephemeral values that have expired  
  148.   
  149. staticint s_flush_single (char *key, void *data, void *args);   
  150.   
  151. staticint  
  152. s_flush_ttl (zloop_t *loop, void *unused, void *args)   
  153. {   
  154.     clonesrv_t *self = (clonesrv_t *) args;   
  155.     zhash_foreach (self->kvmap, s_flush_single, args);   
  156.     return 0;   
  157. }   
  158.   
  159. //  If key-value pair has expired, delete it and publish the  
  160. //  fact to listening clients.   
  161. staticint  
  162. s_flush_single (char *key, void *data, void *args)   
  163. {   
  164.     clonesrv_t *self = (clonesrv_t *) args;   
  165.   
  166.     kvmsg_t *kvmsg = (kvmsg_t *) data;   
  167.     int64_t ttl;   
  168.     sscanf (kvmsg_get_prop (kvmsg, "ttl"), "%" PRId64, &ttl);   
  169.     if (ttl && zclock_time () >= ttl) {   
  170.         kvmsg_set_sequence (kvmsg, ++self->sequence);   
  171.         kvmsg_set_body (kvmsg, (byte *) "", 0);   
  172.         kvmsg_send (kvmsg, self->publisher);   
  173.         kvmsg_store (&kvmsg, self->kvmap);   
  174.         zclock_log ("I: publishing delete=%d", (int) self->sequence);   
  175.     }   
  176.     return 0;   
  177. }  


可靠性
任何东东,一旦脱离的 可靠性,那么终将只是个玩具,虽然它也会带来无尽的麻烦。
之前的"主从模式"似乎不错,再稍微变动下,把“从”也当作客户端之一,接受、存储所有的更新,是不是有点靠谱的感觉。
主从的状态机制模型图:


机制为:客户端发现主服务器不返回了,那么就向从服务器请求,从服务器确认主服务器的确不行了,于是就上马充当服务器。主回归后,从再变为一个客户端。

客户端:
C代码 复制代码 收藏代码
  1. //   
  2. //  Clone client Model Six   
  3. //   
  4.   
  5. //  Lets us build this source without creating a library  
  6. #include "clone.c"   
  7.   
  8. #define SUBTREE "/client/"   
  9.   
  10. int main (void)   
  11. {   
  12.     //  Create distributed hash instance   
  13.     clone_t *clone = clone_new ();   
  14.   
  15.     //  Specify configuration   
  16.     clone_subtree (clone, SUBTREE);   
  17.     clone_connect (clone, "tcp://localhost", "5556");   
  18.     clone_connect (clone, "tcp://localhost", "5566");   
  19.   
  20.     //  Set random tuples into the distributed hash  
  21.     while (!zctx_interrupted) {   
  22.         //  Set random value, check it was stored  
  23.         char key [255];   
  24.         char value [10];   
  25.         sprintf (key, "%s%d", SUBTREE, randof (10000));   
  26.         sprintf (value, "%d", randof (1000000));   
  27.         clone_set (clone, key, value, randof (30));   
  28.         sleep (1);   
  29.     }   
  30.     clone_destroy (&clone);   
  31.     return 0;   
  32. }  

客户端api:
C代码 复制代码 收藏代码
  1. /*  ===================================================================== 
  2.     clone - client-side Clone Pattern class  
  3.  
  4.     --------------------------------------------------------------------- 
  5.     Copyright (c) 1991-2011 iMatix Corporation <www.imatix.com> 
  6.     Copyright other contributors as noted in the AUTHORS file. 
  7.  
  8.     This file is part of the ZeroMQ Guide: http://zguide.zeromq.org 
  9.  
  10.     This is free software; you can redistribute it and/or modify it under 
  11.     the terms of the GNU Lesser General Public License as published by 
  12.     the Free Software Foundation; either version 3 of the License, or (at 
  13.     your option) any later version.  
  14.  
  15.     This software is distributed in the hope that it will be useful, but 
  16.     WITHOUT ANY WARRANTY; without even the implied warranty of 
  17.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
  18.     Lesser General Public License for more details. 
  19.  
  20.     You should have received a copy of the GNU Lesser General Public 
  21.     License along with this program. If not, see  
  22.     <http://www.gnu.org/licenses/>.  
  23.     ===================================================================== 
  24. */  
  25.   
  26. #include "clone.h"   
  27.   
  28. //  If no server replies within this time, abandon request  
  29. #define GLOBAL_TIMEOUT  4000    //  msecs  
  30. //  Server considered dead if silent for this long  
  31. #define SERVER_TTL      5000    //  msecs  
  32. //  Number of servers we will talk to   
  33. #define SERVER_MAX      2   
  34.   
  35. //  =====================================================================  
  36. //  Synchronous part, works in our application thread  
  37.   
  38. //  ---------------------------------------------------------------------  
  39. //  Structure of our class   
  40.   
  41. struct _clone_t {   
  42.     zctx_t *ctx;                //  Our context wrapper  
  43.     void *pipe;                 //  Pipe through to clone agent  
  44. };   
  45.   
  46. //  This is the thread that handles our real clone class  
  47. staticvoid clone_agent (void *args, zctx_t *ctx, void *pipe);   
  48.   
  49. //  ---------------------------------------------------------------------  
  50. //  Constructor   
  51.   
  52. clone_t *   
  53. clone_new (void)   
  54. {   
  55.     clone_t   
  56.         *self;   
  57.   
  58.     self = (clone_t *) zmalloc (sizeof (clone_t));   
  59.     self->ctx = zctx_new ();   
  60.     self->pipe = zthread_fork (self->ctx, clone_agent, NULL);   
  61.     return self;   
  62. }   
  63.   
  64. //  ---------------------------------------------------------------------  
  65. //  Destructor   
  66.   
  67. void  
  68. clone_destroy (clone_t **self_p)   
  69. {   
  70.     assert (self_p);   
  71.     if (*self_p) {   
  72.         clone_t *self = *self_p;   
  73.         zctx_destroy (&self->ctx);   
  74.         free (self);   
  75.         *self_p = NULL;   
  76.     }   
  77. }   
  78.   
  79. //  ---------------------------------------------------------------------  
  80. //  Specify subtree for snapshot and updates, do before connect  
  81. //  Sends [SUBTREE][subtree] to the agent   
  82.   
  83. void clone_subtree (clone_t *self, char *subtree)   
  84. {   
  85.     assert (self);   
  86.     zmsg_t *msg = zmsg_new ();   
  87.     zmsg_addstr (msg, "SUBTREE");   
  88.     zmsg_addstr (msg, subtree);   
  89.     zmsg_send (&msg, self->pipe);   
  90. }   
  91.   
  92. //  ---------------------------------------------------------------------  
  93. //  Connect to new server endpoint   
  94. //  Sends [CONNECT][endpoint][service] to the agent  
  95.   
  96. void  
  97. clone_connect (clone_t *self, char *address, char *service)   
  98. {   
  99.     assert (self);   
  100.     zmsg_t *msg = zmsg_new ();   
  101.     zmsg_addstr (msg, "CONNECT");   
  102.     zmsg_addstr (msg, address);   
  103.     zmsg_addstr (msg, service);   
  104.     zmsg_send (&msg, self->pipe);   
  105. }   
  106.   
  107. //  ---------------------------------------------------------------------  
  108. //  Set new value in distributed hash table  
  109. //  Sends [SET][key][value][ttl] to the agent  
  110.   
  111. void  
  112. clone_set (clone_t *self, char *key, char *value, int ttl)   
  113. {   
  114.     char ttlstr [10];   
  115.     sprintf (ttlstr, "%d", ttl);   
  116.   
  117.     assert (self);   
  118.     zmsg_t *msg = zmsg_new ();   
  119.     zmsg_addstr (msg, "SET");   
  120.     zmsg_addstr (msg, key);   
  121.     zmsg_addstr (msg, value);   
  122.     zmsg_addstr (msg, ttlstr);   
  123.     zmsg_send (&msg, self->pipe);   
  124. }   
  125.   
  126. //  ---------------------------------------------------------------------  
  127. //  Lookup value in distributed hash table  
  128. //  Sends [GET][key] to the agent and waits for a value response  
  129. //  If there is no clone available, will eventually return NULL.  
  130.   
  131. char *   
  132. clone_get (clone_t *self, char *key)   
  133. {   
  134.     assert (self);   
  135.     assert (key);   
  136.     zmsg_t *msg = zmsg_new ();   
  137.     zmsg_addstr (msg, "GET");   
  138.     zmsg_addstr (msg, key);   
  139.     zmsg_send (&msg, self->pipe);   
  140.   
  141.     zmsg_t *reply = zmsg_recv (self->pipe);   
  142.     if (reply) {   
  143.         char *value = zmsg_popstr (reply);   
  144.         zmsg_destroy (&reply);   
  145.         return value;   
  146.     }   
  147.     return NULL;   
  148. }   
  149.   
  150. //  =====================================================================  
  151. //  Asynchronous part, works in the background  
  152.   
  153. //  ---------------------------------------------------------------------  
  154. //  Simple class for one server we talk to  
  155.   
  156. typedefstruct {   
  157.     char *address;              //  Server address  
  158.     int port;                   //  Server port  
  159.     void *snapshot;             //  Snapshot socket  
  160.     void *subscriber;           //  Incoming updates  
  161.     uint64_t expiry;            //  When server expires  
  162.     uint requests;              //  How many snapshot requests made?  
  163. } server_t;   
  164.   
  165. static server_t *   
  166. server_new (zctx_t *ctx, char *address, int port, char *subtree)   
  167. {   
  168.     server_t *self = (server_t *) zmalloc (sizeof (server_t));   
  169.   
  170.     zclock_log ("I: adding server %s:%d…", address, port);   
  171.     self->address = strdup (address);   
  172.     self->port = port;   
  173.   
  174.     self->snapshot = zsocket_new (ctx, ZMQ_DEALER);   
  175.     zsocket_connect (self->snapshot, "%s:%d", address, port);   
  176.     self->subscriber = zsocket_new (ctx, ZMQ_SUB);   
  177.     zsocket_connect (self->subscriber, "%s:%d", address, port + 1);   
  178.     zsockopt_set_subscribe (self->subscriber, subtree);   
  179.     return self;   
  180. }   
  181.   
  182. staticvoid  
  183. server_destroy (server_t **self_p)   
  184. {   
  185.     assert (self_p);   
  186.     if (*self_p) {   
  187.         server_t *self = *self_p;   
  188.         free (self->address);   
  189.         free (self);   
  190.         *self_p = NULL;   
  191.     }   
  192. }   
  193.   
  194. //  ---------------------------------------------------------------------  
  195. //  Our agent class   
  196.   
  197. //  States we can be in   
  198. #define STATE_INITIAL       0   //  Before asking server for state  
  199. #define STATE_SYNCING       1   //  Getting state from server  
  200. #define STATE_ACTIVE        2   //  Getting new updates from server  
  201.   
  202. typedefstruct {   
  203.     zctx_t *ctx;                //  Context wrapper  
  204.     void *pipe;                 //  Pipe back to application  
  205.     zhash_t *kvmap;             //  Actual key/value table  
  206.     char *subtree;              //  Subtree specification, if any  
  207.     server_t *server [SERVER_MAX];   
  208.     uint nbr_servers;           //  0 to SERVER_MAX  
  209.     uint state;                 //  Current state  
  210.     uint cur_server;            //  If active, server 0 or 1  
  211.     int64_t sequence;           //  Last kvmsg processed  
  212.     void *publisher;            //  Outgoing updates  
  213. } agent_t;   
  214.   
  215. static agent_t *   
  216. agent_new (zctx_t *ctx, void *pipe)   
  217. {   
  218.     agent_t *self = (agent_t *) zmalloc (sizeof (agent_t));   
  219.     self->ctx = ctx;   
  220.     self->pipe = pipe;   
  221.     self->kvmap = zhash_new ();   
  222.     self->subtree = strdup ("");   
  223.     self->state = STATE_INITIAL;   
  224.     self->publisher = zsocket_new (self->ctx, ZMQ_PUB);   
  225.     return self;   
  226. }   
  227.   
  228. staticvoid  
  229. agent_destroy (agent_t **self_p)   
  230. {   
  231.     assert (self_p);   
  232.     if (*self_p) {   
  233.         agent_t *self = *self_p;   
  234.         int server_nbr;   
  235.         for (server_nbr = 0; server_nbr < self->nbr_servers; server_nbr++)   
  236.             server_destroy (&self->server [server_nbr]);   
  237.         zhash_destroy (&self->kvmap);   
  238.         free (self->subtree);   
  239.         free (self);   
  240.         *self_p = NULL;   
  241.     }   
  242. }   
  243.   
  244. //  Returns -1 if thread was interrupted   
  245. staticint  
  246. agent_control_message (agent_t *self)   
  247. {   
  248.     zmsg_t *msg = zmsg_recv (self->pipe);   
  249.     char *command = zmsg_popstr (msg);   
  250.     if (command == NULL)   
  251.         return -1;   
  252.   
  253.     if (streq (command, "SUBTREE")) {   
  254.         free (self->subtree);   
  255.         self->subtree = zmsg_popstr (msg);   
  256.     }   
  257.     else  
  258.     if (streq (command, "CONNECT")) {   
  259.         char *address = zmsg_popstr (msg);   
  260.         char *service = zmsg_popstr (msg);   
  261.         if (self->nbr_servers < SERVER_MAX) {   
  262.             self->server [self->nbr_servers++] = server_new (   
  263.                 self->ctx, address, atoi (service), self->subtree);   
  264.             //  We broadcast updates to all known servers  
  265.             zsocket_connect (self->publisher, "%s:%d",   
  266.                 address, atoi (service) + 2);   
  267.         }   
  268.         else  
  269.             zclock_log ("E: too many servers (max. %d)", SERVER_MAX);   
  270.         free (address);   
  271.         free (service);   
  272.     }   
  273.     else  
  274.     if (streq (command, "SET")) {   
  275.         char *key = zmsg_popstr (msg);   
  276.         char *value = zmsg_popstr (msg);   
  277.         char *ttl = zmsg_popstr (msg);   
  278.         zhash_update (self->kvmap, key, (byte *) value);   
  279.         zhash_freefn (self->kvmap, key, free);   
  280.   
  281.         //  Send key-value pair on to server  
  282.         kvmsg_t *kvmsg = kvmsg_new (0);   
  283.         kvmsg_set_key  (kvmsg, key);   
  284.         kvmsg_set_uuid (kvmsg);   
  285.         kvmsg_fmt_body (kvmsg, "%s", value);   
  286.         kvmsg_set_prop (kvmsg, "ttl", ttl);   
  287.         kvmsg_send     (kvmsg, self->publisher);   
  288.         kvmsg_destroy (&kvmsg);   
  289. puts (key);   
  290.         free (ttl);   
  291.         free (key);             //  Value is owned by hash table  
  292.     }   
  293.     else  
  294.     if (streq (command, "GET")) {   
  295.         char *key = zmsg_popstr (msg);   
  296.         char *value = zhash_lookup (self->kvmap, key);   
  297.         if (value)   
  298.             zstr_send (self->pipe, value);   
  299.         else  
  300.             zstr_send (self->pipe, "");   
  301.         free (key);   
  302.         free (value);   
  303.     }   
  304.     free (command);   
  305.     zmsg_destroy (&msg);   
  306.     return 0;   
  307. }   
  308.   
  309. //  ---------------------------------------------------------------------  
  310. //  Asynchronous agent manages server pool and handles request/reply  
  311. //  dialog when the application asks for it.  
  312.   
  313. staticvoid  
  314. clone_agent (void *args, zctx_t *ctx, void *pipe)   
  315. {   
  316.     agent_t *self = agent_new (ctx, pipe);   
  317.   
  318.     while (TRUE) {   
  319.         zmq_pollitem_t poll_set [] = {   
  320.             { pipe, 0, ZMQ_POLLIN, 0 },   
  321.             { 0,    0, ZMQ_POLLIN, 0 }   
  322.         };   
  323.         int poll_timer = -1;   
  324.         int poll_size = 2;   
  325.         server_t *server = self->server [self->cur_server];   
  326.         switch (self->state) {   
  327.             case STATE_INITIAL:   
  328.                 //  In this state we ask the server for a snapshot,  
  329.                 //  if we have a server to talk to…  
  330.                 if (self->nbr_servers > 0) {   
  331.                     zclock_log ("I: waiting for server at %s:%d…",   
  332.                         server->address, server->port);   
  333.                     if (server->requests < 2) {   
  334.                         zstr_sendm (server->snapshot, "ICANHAZ?");   
  335.                         zstr_send  (server->snapshot, self->subtree);   
  336.                         server->requests++;   
  337.                     }   
  338.                     server->expiry = zclock_time () + SERVER_TTL;   
  339.                     self->state = STATE_SYNCING;   
  340.                     poll_set [1].socket = server->snapshot;   
  341.                 }   
  342.                 else  
  343.                     poll_size = 1;   
  344.                 break;   
  345.             case STATE_SYNCING:   
  346.                 //  In this state we read from snapshot and we expect  
  347.                 //  the server to respond, else we fail over.  
  348.                 poll_set [1].socket = server->snapshot;   
  349.                 break;   
  350.             case STATE_ACTIVE:   
  351.                 //  In this state we read from subscriber and we expect  
  352.                 //  the server to give hugz, else we fail over.  
  353.                 poll_set [1].socket = server->subscriber;   
  354.                 break;   
  355.         }   
  356.         if (server) {   
  357.             poll_timer = (server->expiry - zclock_time ())   
  358.                        * ZMQ_POLL_MSEC;   
  359.             if (poll_timer < 0)   
  360.                 poll_timer = 0;   
  361.         }   
  362.         //  ------------------------------------------------------------  
  363.         //  Poll loop   
  364.         int rc = zmq_poll (poll_set, poll_size, poll_timer);   
  365.         if (rc == -1)   
  366.             break;              //  Context has been shut down  
  367.   
  368.         if (poll_set [0].revents & ZMQ_POLLIN) {   
  369.             if (agent_control_message (self))   
  370.                 break;          //  Interrupted  
  371.         }   
  372.         else  
  373.         if (poll_set [1].revents & ZMQ_POLLIN) {   
  374.             kvmsg_t *kvmsg = kvmsg_recv (poll_set [1].socket);   
  375.             if (!kvmsg)   
  376.                 break;          //  Interrupted  
  377.   
  378.             //  Anything from server resets its expiry time  
  379.             server->expiry = zclock_time () + SERVER_TTL;   
  380.             if (self->state == STATE_SYNCING) {   
  381.                 //  Store in snapshot until we're finished  
  382.                 server->requests = 0;   
  383.                 if (streq (kvmsg_key (kvmsg), "KTHXBAI")) {   
  384.                     self->sequence = kvmsg_sequence (kvmsg);   
  385.                     self->state = STATE_ACTIVE;   
  386.                     zclock_log ("I: received from %s:%d snapshot=%d",   
  387.                         server->address, server->port,   
  388.                         (int) self->sequence);   
  389.                     kvmsg_destroy (&kvmsg);   
  390.                 }   
  391.                 else  
  392.                     kvmsg_store (&kvmsg, self->kvmap);   
  393.             }   
  394.             else  
  395.             if (self->state == STATE_ACTIVE) {   
  396.                 //  Discard out-of-sequence updates, incl. hugz  
  397.                 if (kvmsg_sequence (kvmsg) > self->sequence) {   
  398.                     self->sequence = kvmsg_sequence (kvmsg);   
  399.                     kvmsg_store (&kvmsg, self->kvmap);   
  400.                     zclock_log ("I: received from %s:%d update=%d",   
  401.                         server->address, server->port,   
  402.                         (int) self->sequence);   
  403.                 }   
  404.                 else  
  405.                     kvmsg_destroy (&kvmsg);   
  406.             }   
  407.         }   
  408.         else {   
  409.             //  Server has died, failover to next  
  410.             zclock_log ("I: server at %s:%d didn't give hugz",   
  411.                     server->address, server->port);   
  412.             self->cur_server = (self->cur_server + 1) % self->nbr_servers;   
  413.             self->state = STATE_INITIAL;   
  414.         }   
  415.     }   
  416.     agent_destroy (&self);   
  417. }