Example #1
0
int buzzvstig_put(buzzvm_t vm) {
   buzzvm_lnum_assert(vm, 2);
   /* Get vstig id */
   id_get();
   /* Get key */
   buzzvm_lload(vm, 1);
   buzzobj_t k = buzzvm_stack_at(vm, 1);
   /* Get value */
   buzzvm_lload(vm, 2);
   buzzobj_t v = buzzvm_stack_at(vm, 1);
   /* Look for virtual stigmergy */
   const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t);
   if(vs) {
      /* Look for the element */
      const buzzvstig_elem_t* x = buzzvstig_fetch(*vs, &k);
      if(x) {
         /* Element found */
         if(v->o.type != BUZZTYPE_NIL) {
            /* New value is not nil, update the existing element */
            (*x)->data = v;
            ++((*x)->timestamp);
            (*x)->robot = vm->robot;
            /* Append a PUT message to the out message queue */
            buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, *x);
         }
         else {
            /* New value is nil, must delete the existing element */
            /* Make a new element with nil as value to update neighbors */
            buzzvstig_elem_t y = buzzvstig_elem_new(
               buzzobj_new(BUZZTYPE_NIL), // nil value
               (*x)->timestamp + 1,       // new timestamp
               vm->robot);                // robot id
            /* Append a PUT message to the out message queue with nil in it */
            buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, y);
            /* Delete the existing element */
            buzzvstig_remove(*vs, &k);
         }
      }
      else if(v->o.type != BUZZTYPE_NIL) {
         /* Element not found and new value is not nil, store it */
         buzzvstig_elem_t y = buzzvstig_elem_new(v, 1, vm->robot);
         buzzvstig_store(*vs, &k, &y);
         /* Append a PUT message to the out message queue */
         buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, y);
      }
   }
   /* Return */
   return buzzvm_ret0(vm);
}
Example #2
0
int buzzvm_vstig_put(buzzvm_t vm) {
    buzzvm_lnum_assert(vm, 2);
    /* Get vstig id */
    buzzvm_lload(vm, 0);
    buzzvm_pushs(vm, buzzvm_string_register(vm, "id"));
    buzzvm_tget(vm);
    uint16_t id = buzzvm_stack_at(vm, 1)->i.value;
    /* Get key */
    buzzvm_lload(vm, 1);
    buzzobj_t k = buzzvm_stack_at(vm, 1);
    /* Get value */
    buzzvm_lload(vm, 2);
    buzzobj_t v = buzzvm_stack_at(vm, 1);
    /* Look for virtual stigmergy */
    buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t);
    if(vs) {
        /* Look for the element */
        buzzvstig_elem_t* x = buzzvstig_fetch(*vs, &k);
        if(x) {
            /* Element found, update it */
            (*x)->data = v;
            ++((*x)->timestamp);
            (*x)->robot = vm->robot;
            /* Append a PUT message to the out message queue */
            buzzoutmsg_queue_append_vstig(vm->outmsgs, BUZZMSG_VSTIG_PUT, id, k, *x);
        }
        else {
            /* Element not found, create a new one */
            buzzvstig_elem_t y = buzzvstig_elem_new(v, 1, vm->robot);
            buzzvstig_store(*vs, &k, &y);
            /* Append a PUT message to the out message queue */
            buzzoutmsg_queue_append_vstig(vm->outmsgs, BUZZMSG_VSTIG_PUT, id, k, y);
        }
    }
    /* Return */
    return buzzvm_ret0(vm);
}
Example #3
0
void buzzvm_process_inmsgs(buzzvm_t vm) {
   /* Go through the messages */
   while(!buzzinmsg_queue_isempty(vm->inmsgs)) {
      /* Make sure the VM is in the right state */
      if(vm->state != BUZZVM_STATE_READY) return;
      /* Extract the message data */
      uint16_t rid;
      buzzmsg_payload_t msg;
      buzzinmsg_queue_extract(vm, &rid, &msg);
      /* Dispatch the message wrt its type in msg->payload[0] */
      switch(buzzmsg_payload_get(msg, 0)) {
         case BUZZMSG_BROADCAST: {
            /* Deserialize the topic */
            buzzobj_t topic;
            int64_t pos = buzzobj_deserialize(&topic, msg, 1, vm);
            /* Make sure there's a listener to call */
            const buzzobj_t* l = buzzdict_get(vm->listeners, &topic->s.value.sid, buzzobj_t);
            if(!l) {
               /* No listener, ignore message */
               break;
            }
            /* Deserialize value */
            buzzobj_t value;
            pos = buzzobj_deserialize(&value, msg, pos, vm);
            /* Make an object for the robot id */
            buzzobj_t rido = buzzheap_newobj(vm, BUZZTYPE_INT);
            rido->i.value = rid;
            /* Call listener */
            buzzvm_push(vm, *l);
            buzzvm_push(vm, topic);
            buzzvm_push(vm, value);
            buzzvm_push(vm, rido);
            buzzvm_closure_call(vm, 3);
            break;
         }
         case BUZZMSG_VSTIG_PUT: {
            /* Deserialize the vstig id */
            uint16_t id;
            int64_t pos = buzzmsg_deserialize_u16(&id, msg, 1);
            if(pos < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_PUT message received\n", vm->robot);
               break;
            }
            /* Look for virtual stigmergy */
            const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t);
            if(!vs) break;
            /* Virtual stigmergy found */
            /* Deserialize key and value from msg */
            buzzobj_t k;          // key
            buzzvstig_elem_t v =  // value
               (buzzvstig_elem_t)malloc(sizeof(struct buzzvstig_elem_s));
            if(buzzvstig_elem_deserialize(&k, &v, msg, pos, vm) < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_PUT message received\n", vm->robot);
               free(v);
               break;
            }
            /* Deserialization successful */
            /* Fetch local vstig element */
            const buzzvstig_elem_t* l = buzzvstig_fetch(*vs, &k);
            if((!l)                             || /* Element not found */
               ((*l)->timestamp < v->timestamp)) { /* Local element is older */
               /* Local element must be updated */
               /* Store element */
               buzzvstig_store(*vs, &k, &v);
               buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v);
            }
            else if(((*l)->timestamp == v->timestamp) && /* Same timestamp */
                    ((*l)->robot != v->robot)) {         /* Different robot */
               /* Conflict! */
               /* Call conflict manager */
               buzzvstig_elem_t c =
                  buzzvstig_onconflict_call(vm, *vs, k, *l, v);
               if(!c) {
                  fprintf(stderr, "[WARNING] [ROBOT %u] Error resolving PUT conflict\n", vm->robot);
                  break;
               }
               /* Get rid of useless vstig element */
               free(v);
               /* Did this robot lose the conflict? */
               if((c->robot != vm->robot) &&
                  ((*l)->robot == vm->robot)) {
                  /* Yes */
                  /* Save current local entry */
                  buzzvstig_elem_t ol = buzzvstig_elem_clone(vm, *l);
                  /* Store winning value */
                  buzzvstig_store(*vs, &k, &c);
                  /* Call conflict lost manager */
                  buzzvstig_onconflictlost_call(vm, *vs, k, ol);
               }
               else {
                  /* This robot did not lose the conflict */
                  /* Just propagate the PUT message */
                  buzzvstig_store(*vs, &k, &c);
               }
               buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, c);
            }
            else {
               /* Remote element is older, ignore it */
               /* Get rid of useless vstig element */
               free(v);
            }
            break;
         }
         case BUZZMSG_VSTIG_QUERY: {
            /* Deserialize the vstig id */
            uint16_t id;
            int64_t pos = buzzmsg_deserialize_u16(&id, msg, 1);
            if(pos < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_QUERY message received (1)\n", vm->robot);
               break;
            }
            /* Deserialize key and value from msg */
            buzzobj_t k;         // key
            buzzvstig_elem_t v = // value
               (buzzvstig_elem_t)malloc(sizeof(struct buzzvstig_elem_s));
            if(buzzvstig_elem_deserialize(&k, &v, msg, pos, vm) < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_QUERY message received (2)\n", vm->robot);
               free(v);
               break;
            }
            /* Look for virtual stigmergy */
            const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t);
            if(!vs) {
               /* Virtual stigmergy not found, simply propagate the message */
               buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, v);
               free(v);
               break;
            }
            /* Virtual stigmergy found */
            /* Fetch local vstig element */
            const buzzvstig_elem_t* l = buzzvstig_fetch(*vs, &k);
            if(!l) {
               /* Element not found */
               if(v->data->o.type == BUZZTYPE_NIL) {
                  /* This robot knows nothing about the query, just propagate it */
                  buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, v);
                  free(v);
               }
               else {
                  /* Store element and propagate PUT message */
                  buzzvstig_store(*vs, &k, &v);
                  buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v);
               }
               break;
            }
            /* Element found */
            if((*l)->timestamp < v->timestamp) {
               /* Local element is older */
               /* Store element */
               buzzvstig_store(*vs, &k, &v);
               buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v);
            }
            else if((*l)->timestamp > v->timestamp) {
               /* Local element is newer */
               /* Append a PUT message to the out message queue */
               buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, *l);
               free(v);
            }
            else if(((*l)->timestamp == v->timestamp) && /* Same timestamp */
                    ((*l)->robot != v->robot)) {         /* Different robot */
               /* Conflict! */
               /* Call conflict manager */
               buzzvstig_elem_t c =
                  buzzvstig_onconflict_call(vm, *vs, k, *l, v);
               free(v);
               /* Make sure conflict manager returned with an element to process */
               if(!c) break;
               /* Did this robot lose the conflict? */
               if((c->robot != vm->robot) &&
                  ((*l)->robot == vm->robot)) {
                  /* Yes */
                  /* Save current local entry */
                  buzzvstig_elem_t ol = buzzvstig_elem_clone(vm, *l);
                  /* Store winning value */
                  buzzvstig_store(*vs, &k, &c);
                  /* Call conflict lost manager */
                  buzzvstig_onconflictlost_call(vm, *vs, k, ol);
               }
               else {
                  /* This robot did not lose the conflict */
                  /* Just propagate the PUT message */
                  buzzvstig_store(*vs, &k, &c);
               }
               buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, c);
            }
            else {
               /* Remote element is same as local, ignore it */
               /* Get rid of useless vstig element */
               free(v);
            }
            break;
         }
         case BUZZMSG_SWARM_LIST: {
            /* Deserialize number of swarm ids */
            uint16_t nsids;
            int64_t pos = buzzmsg_deserialize_u16(&nsids, msg, 1);
            if(pos < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LIST message received\n", vm->robot);
               break;
            }
            if(nsids < 1) break;
            /* Deserialize swarm ids */
            buzzdarray_t sids = buzzdarray_new(nsids, sizeof(uint16_t), NULL);
            uint16_t i;
            for(i = 0; i < nsids; ++i) {
               pos = buzzmsg_deserialize_u16(buzzdarray_makeslot(sids, i), msg, pos);
               if(pos < 0) {
                  fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LIST message received\n", vm->robot);
                  break;
               }
            }
            /* Update the information */
            buzzswarm_members_refresh(vm->swarmmembers, rid, sids);
            break;
         }
         case BUZZMSG_SWARM_JOIN: {
            /* Deserialize swarm id */
            uint16_t sid;
            int64_t pos = buzzmsg_deserialize_u16(&sid, msg, 1);
            if(pos < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_JOIN message received\n", vm->robot);
               break;
            }
            /* Update the information */
            buzzswarm_members_join(vm->swarmmembers, rid, sid);
            break;
         }
         case BUZZMSG_SWARM_LEAVE: {
            /* Deserialize swarm id */
            uint16_t sid;
            int64_t pos = buzzmsg_deserialize_u16(&sid, msg, 1);
            if(pos < 0) {
               fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LEAVE message received\n", vm->robot);
               break;
            }
            /* Update the information */
            buzzswarm_members_leave(vm->swarmmembers, rid, sid);
            break;
         }
      }
      /* Get rid of the message */
      buzzmsg_payload_destroy(&msg);
   }
   /* Update swarm membership */
   buzzswarm_members_update(vm->swarmmembers);
}