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); }
int buzzvm_vstig_get(buzzvm_t vm) { buzzvm_lnum_assert(vm, 1); /* 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); /* Look for virtual stigmergy */ buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t); if(vs) { /* Virtual stigmergy found */ /* Look for key and push result */ buzzvstig_elem_t* e = buzzvstig_fetch(*vs, &k); if(e) { /* Key found */ buzzvm_push(vm, (*e)->data); /* Append the message to the out message queue */ buzzoutmsg_queue_append_vstig(vm->outmsgs, BUZZMSG_VSTIG_QUERY, id, k, *e); } else { /* Key not found, add a new one containing nil */ buzzvm_pushnil(vm); buzzvstig_elem_t x = buzzvstig_elem_new(buzzvm_stack_at(vm, 1), 1, vm->robot); /* Append the message to the out message queue */ buzzoutmsg_queue_append_vstig(vm->outmsgs, BUZZMSG_VSTIG_QUERY, id, k, x); } } else { /* No virtual stigmergy found, just push false */ /* If this happens, its a bug */ buzzvm_pushnil(vm); fprintf(stderr, "[BUG] [ROBOT %u] Can't find virtual stigmergy %u\n", vm->robot, id); } /* Return the value found */ return buzzvm_ret1(vm); }
int buzzvstig_get(buzzvm_t vm) { buzzvm_lnum_assert(vm, 1); /* Get vstig id */ id_get(); /* Get key */ buzzvm_lload(vm, 1); buzzobj_t k = buzzvm_stack_at(vm, 1); /* Look for virtual stigmergy */ const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t); if(vs) { /* Virtual stigmergy found */ /* Look for key and push result */ const buzzvstig_elem_t* e = buzzvstig_fetch(*vs, &k); if(e) { /* Key found */ buzzvm_push(vm, (*e)->data); /* Append the message to the out message queue */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, *e); } else { /* Key not found, make a new one containing nil */ buzzvm_pushnil(vm); buzzvstig_elem_t x = buzzvstig_elem_new(buzzvm_stack_at(vm, 1), // nil value 0, // timestamp vm->robot); // robot id /* Append the message to the out message queue */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, x); free(x); } } else { /* No virtual stigmergy found, just push false */ /* If this happens, its a bug */ buzzvm_pushnil(vm); } /* Return the value found */ return buzzvm_ret1(vm); }
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); }
buzzvstig_elem_t buzzvstig_onconflict_call(buzzvm_t vm, buzzvstig_t vs, buzzobj_t k, buzzvstig_elem_t lv, buzzvstig_elem_t rv) { /* Was a conflict manager defined? */ if(vs->onconflict) { /* Push closure */ buzzvm_push(vm, vs->onconflict); /* Push key */ buzzvm_push(vm, k); /* Make table for local value */ buzzvm_pusht(vm); add_field(robot, lv, pushi); add_field(data, lv, push); add_field(timestamp, lv, pushi); /* Make table for remote value */ buzzvm_pusht(vm); add_field(robot, rv, pushi); add_field(data, rv, push); add_field(timestamp, rv, pushi); /* Call closure (key, lv, rv on the stack) */ buzzvm_closure_call(vm, 3); /* Make new entry with return value */ /* Make sure it's a table */ if(buzzvm_stack_at(vm, 1)->o.type != BUZZTYPE_TABLE) { fprintf(stderr, "[WARNING] [ROBOT %u] virtual stigmergy onconflict(): Return value type is %s, expected table\n", vm->robot, buzztype_desc[buzzvm_stack_at(vm, 1)->o.type]); return NULL; } /* Get the robot id */ buzzobj_t ret = buzzvm_stack_at(vm, 1); buzzvm_pushs(vm, buzzvm_string_register(vm, "robot", 1)); buzzvm_tget(vm); if(buzzvm_stack_at(vm, 1)->o.type != BUZZTYPE_INT) return NULL; uint16_t robot = buzzvm_stack_at(vm, 1)->i.value; buzzvm_pop(vm); /* Get the data */ buzzvm_push(vm, ret); buzzvm_pushs(vm, buzzvm_string_register(vm, "data", 1)); buzzvm_tget(vm); buzzobj_t data = buzzvm_stack_at(vm, 1); buzzvm_pop(vm); /* Make new entry */ return buzzvstig_elem_new(data, lv->timestamp, robot); } else { /* No conflict manager, use default behavior */ /* If both values are not nil, keep the value of the robot with the higher id */ if(((lv->data->o.type == BUZZTYPE_NIL) && (rv->data->o.type == BUZZTYPE_NIL)) || ((lv->data->o.type != BUZZTYPE_NIL) && (rv->data->o.type != BUZZTYPE_NIL))) { if(lv->robot > rv->robot) return buzzvstig_elem_clone(vm, lv); else return buzzvstig_elem_clone(vm, rv); } /* If my value is not nil, keep mine */ if(lv->data->o.type != BUZZTYPE_NIL) return buzzvstig_elem_clone(vm, lv); /* If the other value is not nil, keep that one */ if(rv->data->o.type != BUZZTYPE_NIL) return buzzvstig_elem_clone(vm, rv); /* Otherwise nothing to do */ return NULL; } }
buzzvstig_elem_t buzzvm_vstig_onconflict(buzzvm_t vm, buzzvstig_t vs, buzzobj_t k, buzzvstig_elem_t lv, buzzvstig_elem_t rv) { /* Was a conflict manager defined? */ if(vs->onconflict) { /* Push closure */ buzzvm_push(vm, vs->onconflict); /* Push key */ buzzvm_push(vm, k); /* Make table for local value */ buzzvm_pusht(vm); buzzobj_t loc = buzzvm_stack_at(vm, 1); buzzvm_pushs(vm, buzzvm_string_register(vm, "robot")); buzzvm_pushi(vm, lv->robot); buzzvm_tput(vm); buzzvm_push(vm, loc); buzzvm_pushs(vm, buzzvm_string_register(vm, "data")); buzzvm_push(vm, lv->data); buzzvm_tput(vm); buzzvm_push(vm, loc); buzzvm_pushs(vm, buzzvm_string_register(vm, "timestamp")); buzzvm_pushi(vm, lv->timestamp); buzzvm_tput(vm); /* Make table for remote value */ buzzvm_pusht(vm); buzzobj_t rem = buzzvm_stack_at(vm, 1); buzzvm_pushs(vm, buzzvm_string_register(vm, "robot")); buzzvm_pushi(vm, rv->robot); buzzvm_tput(vm); buzzvm_push(vm, rem); buzzvm_pushs(vm, buzzvm_string_register(vm, "data")); buzzvm_push(vm, rv->data); buzzvm_tput(vm); buzzvm_push(vm, rem); buzzvm_pushs(vm, buzzvm_string_register(vm, "timestamp")); buzzvm_pushi(vm, rv->timestamp); buzzvm_tput(vm); /* Call closure with 3 arguments */ buzzvm_push(vm, loc); buzzvm_push(vm, rem); buzzvm_closure_call(vm, 3); /* Make new entry with return value */ /* Make sure it's a table */ if(buzzvm_stack_at(vm, 1)->o.type != BUZZTYPE_TABLE) { fprintf(stderr, "[WARNING] [ROBOT %u] Return value type is %d\n", vm->robot, buzzvm_stack_at(vm, 1)->o.type); return NULL; } /* Get the robot id */ buzzobj_t ret = buzzvm_stack_at(vm, 1); buzzvm_pushs(vm, buzzvm_string_register(vm, "robot")); buzzvm_tget(vm); if(buzzvm_stack_at(vm, 1)->o.type != BUZZTYPE_INT) return NULL; uint16_t robot = buzzvm_stack_at(vm, 1)->i.value; buzzvm_pop(vm); /* Get the data */ buzzvm_push(vm, ret); buzzvm_pushs(vm, buzzvm_string_register(vm, "data")); buzzvm_tget(vm); buzzobj_t data = buzzvm_stack_at(vm, 1); buzzvm_pop(vm); /* Make new entry */ return buzzvstig_elem_new(data, lv->timestamp, robot); } else { /* No conflict manager, use default behavior */ if(lv->robot > rv->robot) return buzzvstig_elem_clone(lv); else return buzzvstig_elem_clone(rv); } }