void caml_empty_minor_heap_domain (struct domain* domain) { CAMLnoalloc; caml_domain_state* domain_state = domain->state; struct caml_minor_tables *minor_tables = domain_state->minor_tables; unsigned rewrite_successes = 0; unsigned rewrite_failures = 0; char* young_ptr = domain_state->young_ptr; char* young_end = domain_state->young_end; uintnat minor_allocated_bytes = young_end - young_ptr; struct oldify_state st = {0}; value **r; struct caml_ephe_ref_elt *re; struct caml_custom_elt *elt; st.promote_domain = domain; if (minor_allocated_bytes != 0) { uintnat prev_alloc_words = domain_state->allocated_words; #ifdef DEBUG /* In DEBUG mode, verify that the minor_ref table contains all young-young pointers from older to younger objects */ { struct addrmap young_young_ptrs = ADDRMAP_INIT; mlsize_t i; value iter; for (r = minor_tables->minor_ref.base; r < minor_tables->minor_ref.ptr; r++) { *caml_addrmap_insert_pos(&young_young_ptrs, (value)*r) = 1; } for (iter = (value)young_ptr; iter < (value)young_end; iter = next_minor_block(domain_state, iter)) { value hd = Hd_hp(iter); if (hd != 0) { value curr = Val_hp(iter); tag_t tag = Tag_hd (hd); if (tag < No_scan_tag && tag != Cont_tag) { // FIXME: should scan Cont_tag for (i = 0; i < Wosize_hd(hd); i++) { value* f = Op_val(curr) + i; if (Is_block(*f) && is_in_interval(*f, young_ptr, young_end) && *f < curr) { CAMLassert(caml_addrmap_contains(&young_young_ptrs, (value)f)); } } } } } caml_addrmap_clear(&young_young_ptrs); } #endif caml_gc_log ("Minor collection of domain %d starting", domain->state->id); caml_ev_begin("minor_gc"); caml_ev_begin("minor_gc/roots"); caml_do_local_roots(&oldify_one, &st, domain, 0); caml_scan_stack(&oldify_one, &st, domain_state->current_stack); for (r = minor_tables->major_ref.base; r < minor_tables->major_ref.ptr; r++) { value x = **r; oldify_one (&st, x, &x); } caml_ev_end("minor_gc/roots"); caml_ev_begin("minor_gc/promote"); oldify_mopup (&st); caml_ev_end("minor_gc/promote"); caml_ev_begin("minor_gc/ephemerons"); for (re = minor_tables->ephe_ref.base; re < minor_tables->ephe_ref.ptr; re++) { CAMLassert (Ephe_domain(re->ephe) == domain); if (re->offset == CAML_EPHE_DATA_OFFSET) { /* Data field has already been handled in oldify_mopup. Handle only * keys here. */ continue; } value* key = &Op_val(re->ephe)[re->offset]; if (*key != caml_ephe_none && Is_block(*key) && is_in_interval(*key, young_ptr, young_end)) { resolve_infix_val(key); if (Hd_val(*key) == 0) { /* value copied to major heap */ *key = Op_val(*key)[0]; } else { CAMLassert(!ephe_check_alive_data(re,young_ptr,young_end)); *key = caml_ephe_none; Ephe_data(re->ephe) = caml_ephe_none; } } } caml_ev_end("minor_gc/ephemerons"); caml_ev_begin("minor_gc/update_minor_tables"); for (r = minor_tables->major_ref.base; r < minor_tables->major_ref.ptr; r++) { value v = **r; if (Is_block (v) && is_in_interval ((value)Hp_val(v), young_ptr, young_end)) { value vnew; header_t hd = Hd_val(v); int offset = 0; if (Tag_hd(hd) == Infix_tag) { offset = Infix_offset_hd(hd); v -= offset; } CAMLassert (Hd_val(v) == 0); vnew = Op_val(v)[0] + offset; CAMLassert (Is_block(vnew) && !Is_minor(vnew)); CAMLassert (Hd_val(vnew)); if (Tag_hd(hd) == Infix_tag) { CAMLassert(Tag_val(vnew) == Infix_tag); v += offset; } if (caml_domain_alone()) { **r = vnew; ++rewrite_successes; } else { if (atomic_compare_exchange_strong((atomic_value*)*r, &v, vnew)) ++rewrite_successes; else ++rewrite_failures; } } } CAMLassert (!caml_domain_alone() || rewrite_failures == 0); caml_ev_end("minor_gc/update_minor_tables"); caml_ev_begin("minor_gc/finalisers"); caml_final_update_last_minor(domain); /* Run custom block finalisation of dead minor values */ for (elt = minor_tables->custom.base; elt < minor_tables->custom.ptr; elt++) { value v = elt->block; if (Hd_val(v) == 0) { /* !!caml_adjust_gc_speed(elt->mem, elt->max); */ } else { /* Block will be freed: call finalisation function, if any */ void (*final_fun)(value) = Custom_ops_val(v)->finalize; if (final_fun != NULL) final_fun(v); } } caml_final_empty_young(domain); caml_ev_end("minor_gc/finalisers"); clear_table ((struct generic_table *)&minor_tables->major_ref); clear_table ((struct generic_table *)&minor_tables->minor_ref); clear_table ((struct generic_table *)&minor_tables->ephe_ref); clear_table ((struct generic_table *)&minor_tables->custom); domain_state->young_ptr = domain_state->young_end; domain_state->stat_minor_words += Wsize_bsize (minor_allocated_bytes); domain_state->stat_minor_collections++; domain_state->stat_promoted_words += domain_state->allocated_words - prev_alloc_words; caml_ev_end("minor_gc"); caml_gc_log ("Minor collection of domain %d completed: %2.0f%% of %u KB live, rewrite: successes=%u failures=%u", domain->state->id, 100.0 * (double)st.live_bytes / (double)minor_allocated_bytes, (unsigned)(minor_allocated_bytes + 512)/1024, rewrite_successes, rewrite_failures); } else { caml_final_empty_young(domain); caml_gc_log ("Minor collection of domain %d: skipping", domain->state->id); } #ifdef DEBUG { value *p; for (p = (value *) domain_state->young_start; p < (value *) domain_state->young_end; ++p){ *p = Debug_free_minor; } } #endif }
CAMLexport value caml_promote(struct domain* domain, value root) { value **r; value iter, f; mlsize_t i; caml_domain_state* domain_state = domain->state; struct caml_minor_tables *minor_tables = domain_state->minor_tables; char* young_ptr = domain_state->young_ptr; char* young_end = domain_state->young_end; float percent_to_scan; uintnat prev_alloc_words = domain_state->allocated_words; struct oldify_state st = {0}; struct caml_ephe_ref_elt *re; /* Integers are already shared */ if (Is_long(root)) return root; /* Objects which are in the major heap are already shared. */ if (!Is_minor(root)) return root; st.oldest_promoted = (value)domain_state->young_start; st.promote_domain = domain; CAMLassert(caml_owner_of_young_block(root) == domain); oldify_one (&st, root, &root); oldify_mopup (&st); CAMLassert (!Is_minor(root)); /* FIXME: surely a newly-allocated root is already darkened? */ caml_darken(0, root, 0); percent_to_scan = st.oldest_promoted <= (value)young_ptr ? 0.0 : (((float)(st.oldest_promoted - (value)young_ptr)) * 100.0 / ((value)young_end - (value)domain_state->young_start)); if (percent_to_scan > Percent_to_promote_with_GC) { caml_gc_log("caml_promote: forcing minor GC. %%_minor_to_scan=%f", percent_to_scan); // ??? caml_empty_minor_heap_domain (domain); } else { caml_do_local_roots (&forward_pointer, st.promote_domain, domain, 1); caml_scan_stack (&forward_pointer, st.promote_domain, domain_state->current_stack); /* Scan major to young pointers. */ for (r = minor_tables->major_ref.base; r < minor_tables->major_ref.ptr; r++) { value old_p = **r; if (Is_block(old_p) && is_in_interval(old_p,young_ptr,young_end)) { value new_p = old_p; forward_pointer (st.promote_domain, new_p, &new_p); if (old_p != new_p) { if (caml_domain_alone()) **r = new_p; else atomic_compare_exchange_strong((atomic_value*)*r, &old_p, new_p); } } } /* Scan ephemeron ref table */ for (re = minor_tables->ephe_ref.base; re < minor_tables->ephe_ref.ptr; re++) { value* key = &Op_val(re->ephe)[re->offset]; if (Is_block(*key) && is_in_interval(*key,young_ptr,young_end)) { forward_pointer (st.promote_domain, *key, key); } } /* Scan young to young pointers */ for (r = minor_tables->minor_ref.base; r < minor_tables->minor_ref.ptr; r++) { forward_pointer (st.promote_domain, **r, *r); } /* Scan newer objects */ for (iter = (value)young_ptr; iter <= st.oldest_promoted; iter = next_minor_block(domain_state, iter)) { value hd = Hd_hp(iter); value curr = Val_hp(iter); if (hd != 0) { tag_t tag = Tag_hd (hd); if (tag == Cont_tag) { struct stack_info* stk = Ptr_val(Op_val(curr)[0]); if (stk != NULL) caml_scan_stack(&forward_pointer, st.promote_domain, stk); } else if (tag < No_scan_tag) { for (i = 0; i < Wosize_hd (hd); i++) { f = Op_val(curr)[i]; if (Is_block(f)) { forward_pointer (st.promote_domain, f,((value*)curr) + i); } } } } } } domain_state->stat_promoted_words += domain_state->allocated_words - prev_alloc_words; return root; }
/* Finish the work that was put off by [oldify_one]. Note that [oldify_one] itself is called by oldify_mopup, so we have to be careful to remove the first entry from the list before oldifying its fields. */ static void oldify_mopup (struct oldify_state* st) { value v, new_v, f; mlsize_t i; caml_domain_state* domain_state = st->promote_domain ? st->promote_domain->state : Caml_state; struct caml_ephe_ref_table ephe_ref_table = domain_state->minor_tables->ephe_ref; struct caml_ephe_ref_elt *re; char* young_ptr = domain_state->young_ptr; char* young_end = domain_state->young_end; int redo = 0; while (st->todo_list != 0) { v = st->todo_list; /* Get the head. */ CAMLassert (Hd_val (v) == 0); /* It must be forwarded. */ new_v = Op_val (v)[0]; /* Follow forward pointer. */ st->todo_list = Op_val (new_v)[1]; /* Remove from list. */ f = Op_val (new_v)[0]; CAMLassert (!Is_debug_tag(f)); if (Is_block (f) && is_in_interval((value)Hp_val(v), young_ptr, young_end)) { oldify_one (st, f, Op_val (new_v)); } for (i = 1; i < Wosize_val (new_v); i++){ f = Op_val (v)[i]; CAMLassert (!Is_debug_tag(f)); if (Is_block (f) && is_in_interval((value)Hp_val(v), young_ptr, young_end)) { oldify_one (st, f, Op_val (new_v) + i); } else { Op_val (new_v)[i] = f; } } CAMLassert (Wosize_val(new_v)); } /* Oldify the data in the minor heap of alive ephemeron During minor collection keys outside the minor heap are considered alive */ for (re = ephe_ref_table.base; re < ephe_ref_table.ptr; re++) { /* look only at ephemeron with data in the minor heap */ if (re->offset == CAML_EPHE_DATA_OFFSET) { value *data = &Ephe_data(re->ephe); if (*data != caml_ephe_none && Is_block(*data) && is_in_interval(*data, young_ptr, young_end)) { resolve_infix_val(data); if (Hd_val(*data) == 0) { /* Value copied to major heap */ *data = Op_val(*data)[0]; } else { if (ephe_check_alive_data(re, young_ptr, young_end)) { oldify_one(st, *data, data); redo = 1; /* oldify_todo_list can still be 0 */ } } } } } if (redo) oldify_mopup (st); }
/* Note that the tests on the tag depend on the fact that Infix_tag, Forward_tag, and No_scan_tag are contiguous. */ static void oldify_one (void* st_v, value v, value *p) { struct oldify_state* st = st_v; value result; header_t hd; mlsize_t sz, i; mlsize_t infix_offset; tag_t tag; caml_domain_state* domain_state = st->promote_domain ? st->promote_domain->state : Caml_state; char* young_ptr = domain_state->young_ptr; char* young_end = domain_state->young_end; CAMLassert (domain_state->young_start <= domain_state->young_ptr && domain_state->young_ptr <= domain_state->young_end); tail_call: if (!(Is_block(v) && is_in_interval((value)Hp_val(v), young_ptr, young_end))) { /* not a minor block */ *p = v; return; } infix_offset = 0; do { hd = Hd_val (v); if (hd == 0) { /* already forwarded, forward pointer is first field. */ *p = Op_val(v)[0] + infix_offset; return; } tag = Tag_hd (hd); if (tag == Infix_tag) { /* Infix header, retry with the real block */ CAMLassert (infix_offset == 0); infix_offset = Infix_offset_hd (hd); CAMLassert(infix_offset > 0); v -= infix_offset; } } while (tag == Infix_tag); if (((value)Hp_val(v)) > st->oldest_promoted) { st->oldest_promoted = (value)Hp_val(v); } if (tag == Cont_tag) { struct stack_info* stk = Ptr_val(Op_val(v)[0]); CAMLassert(Wosize_hd(hd) == 1 && infix_offset == 0); result = alloc_shared(1, Cont_tag); *p = result; Op_val(result)[0] = Val_ptr(stk); *Hp_val (v) = 0; Op_val(v)[0] = result; if (stk != NULL) caml_scan_stack(&oldify_one, st, stk); } else if (tag < Infix_tag) { value field0; sz = Wosize_hd (hd); st->live_bytes += Bhsize_hd(hd); result = alloc_shared (sz, tag); *p = result + infix_offset; field0 = Op_val(v)[0]; CAMLassert (!Is_debug_tag(field0)); *Hp_val (v) = 0; /* Set forward flag */ Op_val(v)[0] = result; /* and forward pointer. */ if (sz > 1){ Op_val (result)[0] = field0; Op_val (result)[1] = st->todo_list; /* Add this block */ st->todo_list = v; /* to the "to do" list. */ }else{ CAMLassert (sz == 1); p = Op_val(result); v = field0; goto tail_call; } } else if (tag >= No_scan_tag) { sz = Wosize_hd (hd); st->live_bytes += Bhsize_hd(hd); result = alloc_shared(sz, tag); for (i = 0; i < sz; i++) { value curr = Op_val(v)[i]; Op_val (result)[i] = curr; } *Hp_val (v) = 0; /* Set forward flag */ Op_val (v)[0] = result; /* and forward pointer. */ CAMLassert (infix_offset == 0); *p = result; } else { CAMLassert (tag == Forward_tag); CAMLassert (infix_offset == 0); value f = Forward_val (v); tag_t ft = 0; if (Is_block (f)) { ft = Tag_val (Hd_val (f) == 0 ? Op_val (f)[0] : f); } if (ft == Forward_tag || ft == Lazy_tag || ft == Double_tag) { /* Do not short-circuit the pointer. Copy as a normal block. */ CAMLassert (Wosize_hd (hd) == 1); st->live_bytes += Bhsize_hd(hd); result = alloc_shared (1, Forward_tag); *p = result; *Hp_val (v) = 0; /* Set (GC) forward flag */ Op_val (v)[0] = result; /* and forward pointer. */ p = Op_val (result); v = f; goto tail_call; } else { v = f; /* Follow the forwarding */ goto tail_call; /* then oldify. */ } } }
/*-----------------------------------------------------------------*/ void make_layer(struct layer_t *layer, struct mesh_t *mesh) { struct cell_t *last_m = NULL; struct cell_t *first_m = NULL; struct cell_t *m = NULL; struct cell_t *c1, *c2, *first_cell; struct cell_t *cell2return = NULL; struct mesh_parameter_t *mp; int n, nb_meridian, nb_max_meridian, nl; float c1_lon; float plon; /* lon step */ mp = mesh->parameter; layer->ncells = 0; nb_meridian = layer->nlon; nb_max_meridian = (int) (360. / (layer->lon_unit * mp->lon_unit_size)); if (DEBUG) fprintf(stderr, "make_layer : nb meridians to make = %d\n", nb_meridian); n = 0; c1_lon = mp->lon_min; plon = mp->lon_unit_size * layer->lon_unit; while (n < nb_meridian) { m = make_meridian(layer, mesh); if (first_m == NULL) { first_m = m; if (is_in_interval(modulo360(mp->lon_min, 0), 0., 180. - plon)) { if (DEBUG) fprintf(stderr, "make_layer : init cell in [0-180[\n"); layer->cell = first_m; } else { if (DEBUG) fprintf(stderr, "make_layer : init cell in [180-360[\n"); cell2return = first_m; while (cell2return->neighbour_list[NSD_1]) { cell2return = get_cell_from_list(cell2return->neighbour_list [NSD_1], 0); } layer->cell = cell2return; } } else { if (modulo360(c1_lon, 0) > 180. - EPS && modulo360(c1_lon, 0) < 180. + EPS) { if (DEBUG) fprintf(stderr, "make_layer : link_meridian_2 (%.1f-%.1f)\n", c1_lon, c1_lon + plon); nl = link_meridian_2(last_m, m); } else if (modulo360(c1_lon, 1) > 360. - EPS && modulo360(c1_lon, 1) < 360. + EPS) { if (DEBUG) fprintf(stderr, "make_layer : link_meridian_3 (%.1f-%.1f)\n", c1_lon, c1_lon + plon); nl = link_meridian_3(last_m, m); } else { if (DEBUG) fprintf(stderr, "make_layer : link_meridian_1 (%.1f-%.1f)\n", c1_lon, c1_lon + plon); nl = link_meridian_1(last_m, m); } if (DEBUG) fprintf(stderr, "make_layer : nb links made = %d\n", nl); } last_m = m; n++; c1_lon += plon; } /*----------------------------*/ /* link last & first meridian */ /*----------------------------*/ if ((int) (mp->lon_max - mp->lon_min) == 360) { if (DEBUG) fprintf(stderr, "make_layer : link first and last meridian\n"); if (is_in_interval (0., modulo360(c1_lon, 0) - EPS, modulo360(c1_lon + plon, 0) - EPS)) { if (DEBUG) fprintf(stderr, "make_layer : link_meridian_3 (%.1f-%.1f)\n", c1_lon, c1_lon + plon); link_meridian_3(last_m, first_m); } else if (is_in_interval (180., modulo360(c1_lon, 0) - EPS, modulo360(c1_lon + plon, 1) - EPS)) { if (DEBUG) fprintf(stderr, "make_layer : link_meridian_2 (%.1f-%.1f)\n", c1_lon, c1_lon + plon); link_meridian_2(last_m, first_m); } else { if (DEBUG) fprintf(stderr, "make_layer : link_meridian_1 (%.1f-%.1f)\n", c1_lon, c1_lon + plon); link_meridian_1(last_m, first_m); } } /*return; */ /*---------------------*/ /* link South Pole ... */ /*---------------------*/ if ((int) (mp->lat_min) == -90) { if (DEBUG) fprintf(stderr, "make_layer : link south (topo)\n"); if (cell2return) { c1 = first_cell = cell2return; } else { c1 = first_cell = first_m; } c1_lon = mp->lon_min; plon = mp->lon_unit_size * layer->lon_unit; /* dump couronne */ /*if (DEBUG) { n = 0; fprintf(stderr, "\ncouronne = "); c2 = c1; while (n < nb_meridian) { n++; fprintf(stderr, "%p(%d), ", c2, n); c2 = get_cell_from_list(c2->neighbour_list[EAST_D], 0); } fprintf(stderr, "\n"); } */ nl = 0; /* number of move to complete the pole link */ do { if (c1_lon + 180. < mp->lon_max - plon + EPS) { /* link is possible */ /* we go on the cell to link with c1 */ n = 0; c2 = c1; if (VERBOSE) fprintf(stderr, "make_layer : going to cell c2 to link with c1 : "); while (n < nb_max_meridian / 2) { /* nb_max_meridian must be = 2*k */ if (VERBOSE) fprintf(stderr, "+"); c2 = get_cell_from_list(c2->neighbour_list[EAST_D], 0); n++; } if (VERBOSE) fprintf(stderr, "\n"); /*if (DEBUG) fprintf(stderr, "with c2 = %p\n", c2); */ /* the link */ if (is_in_interval (modulo360(c1_lon, 0), 0. - EPS, 180. - EPS) && !is_in_interval(180., modulo360(c1_lon, 0) - EPS, modulo360(c1_lon + plon, 1) - EPS)) { if (VERBOSE) { fprintf(stderr, "make_layer : c1 is in [0,180[\n"); fprintf(stderr, "make_layer : c1=%p c2=%p\n", c1, c2); fprintf(stderr, "make_layer : c1->nsd2 = %p, c2->nsd1 = %p\n", get_cell_from_list(c1->neighbour_list [NSD_2], 0), get_cell_from_list(c2->neighbour_list [NSD_1], 0)); } c1->neighbour_list[NSD_2] = add_neighbour_to_cell(c1, c2, NSD_2); c2->neighbour_list[NSD_1] = add_neighbour_to_cell(c2, c1, NSD_1); /*c2->neighbour_list[NSD_2] = add_neighbour_to_cell(c2, c1, NSD_2); */ if (VERBOSE) { fprintf(stderr, "make_layer : c1=%p c2=%p\n", c1, c2); fprintf(stderr, "make_layer : c1->nsd2 = %p, c2->nsd1 = %p\n", get_cell_from_list(c1->neighbour_list [NSD_2], 0), get_cell_from_list(c2->neighbour_list [NSD_1], 0)); } } else { if (VERBOSE) { fprintf(stderr, "make_layer : c1 is in [180,360\n"); } c1->neighbour_list[NSD_1] = add_neighbour_to_cell(c1, c2, NSD_1); c2->neighbour_list[NSD_2] = add_neighbour_to_cell(c2, c1, NSD_2); /*c2->neighbour_list[NSD_1] = add_neighbour_to_cell(c2, c1, NSD_1); */ } } c1 = get_cell_from_list(c1->neighbour_list[EAST_D], 0); c1_lon += plon; nl++; } while (c1 && nl < nb_meridian / 2); } /*----------------*/ /* and North Pole */ /*----------------*/ if ((int) (mp->lat_max) == 90) { if (DEBUG) fprintf(stderr, "make_layer : link north (topo)\n"); c1 = first_m; if (!cell2return) { while (c1->neighbour_list[NSD_1]) { c1 = get_cell_from_list(c1->neighbour_list[NSD_1], 0); } } /* dump couronne */ /*if (DEBUG) { n = 0; fprintf(stderr, "\ncouronne = "); c2 = c1; while (n < nb_meridian) { n++; fprintf(stderr, "%p(%d), ", c2, n); c2 = get_cell_from_list(c2->neighbour_list[EAST_D], 0); } fprintf(stderr, "\n"); } */ first_cell = c1; c1_lon = mp->lon_min; plon = mp->lon_unit_size * layer->lon_unit; nl = 0; /* number of move to complete the pole link */ do { if (c1_lon + 180. < mp->lon_max - plon + EPS) { /* link is possible */ /*if (DEBUG) fprintf(stderr, "link possible for cell c1 = %p (lon=%.1f)", c1, c1_lon); */ /* we go on the cell to link with c1 */ n = 0; c2 = c1; if (VERBOSE) fprintf(stderr, "make_layer : going to cell c2 to link with c1 : "); while (n < nb_max_meridian / 2) { if (VERBOSE) fprintf(stderr, "+"); c2 = get_cell_from_list(c2->neighbour_list[EAST_D], 0); n++; } if (VERBOSE) fprintf(stderr, "\n"); /*if (DEBUG) fprintf(stderr, "with c2 = %p\n", c2); */ /* the link */ if (is_in_interval (modulo360(c1_lon, 0), 0. - EPS, 180. - EPS) && !is_in_interval(180., modulo360(c1_lon, 0) - EPS, modulo360(c1_lon + plon, 1) - EPS)) { if (VERBOSE) fprintf(stderr, "make_layer : c1 is in [0,180[\n"); c1->neighbour_list[NSD_1] = add_neighbour_to_cell(c1, c2, NSD_1); c2->neighbour_list[NSD_2] = add_neighbour_to_cell(c2, c1, NSD_2); /*c2->neighbour_list[NSD_1] = add_neighbour_to_cell(c2, c1, NSD_1); */ } else { if (VERBOSE) fprintf(stderr, "make_layer : c1 is in [180,360\n"); c1->neighbour_list[NSD_2] = add_neighbour_to_cell(c1, c2, NSD_2); c2->neighbour_list[NSD_1] = add_neighbour_to_cell(c2, c1, NSD_1); /*c2->neighbour_list[NSD_2] = add_neighbour_to_cell(c2, c1, NSD_2); */ } } c1 = get_cell_from_list(c1->neighbour_list[EAST_D], 0); c1_lon += plon; nl++; } while (c1 && nl < nb_meridian / 2); } }
/* This function is called when a node receives a message. * * \param message the message to handle (don't touch it afterward: it will be destroyed, reused or forwarded) */ void Node::handleMessage(ChordMessage* message) { switch (message->type) { case FIND_SUCCESSOR: XBT_DEBUG("Received a 'Find Successor' request from %s for id %d", message->issuer_host_name.c_str(), message->request_id); // is my successor the successor? if (is_in_interval(message->request_id, id_ + 1, fingers_[0])) { message->type = FIND_SUCCESSOR_ANSWER; message->answer_id = fingers_[0]; XBT_DEBUG("Sending back a 'Find Successor Answer' to %s (mailbox %s): the successor of %d is %d", message->issuer_host_name.c_str(), message->answer_to->get_cname(), message->request_id, message->answer_id); message->answer_to->put_init(message, 10)->detach(ChordMessage::destroy); } else { // otherwise, forward the request to the closest preceding finger in my table int closest = closestPrecedingFinger(message->request_id); XBT_DEBUG("Forwarding the 'Find Successor' request for id %d to my closest preceding finger %d", message->request_id, closest); simgrid::s4u::MailboxPtr mailbox = simgrid::s4u::Mailbox::by_name(std::to_string(closest)); mailbox->put_init(message, 10)->detach(ChordMessage::destroy); } break; case GET_PREDECESSOR: XBT_DEBUG("Receiving a 'Get Predecessor' request from %s", message->issuer_host_name.c_str()); message->type = GET_PREDECESSOR_ANSWER; message->answer_id = pred_id_; XBT_DEBUG("Sending back a 'Get Predecessor Answer' to %s via mailbox '%s': my predecessor is %d", message->issuer_host_name.c_str(), message->answer_to->get_cname(), message->answer_id); message->answer_to->put_init(message, 10)->detach(ChordMessage::destroy); break; case NOTIFY: // someone is telling me that he may be my new predecessor XBT_DEBUG("Receiving a 'Notify' request from %s", message->issuer_host_name.c_str()); notify(message->request_id); delete message; break; case PREDECESSOR_LEAVING: // my predecessor is about to quit XBT_DEBUG("Receiving a 'Predecessor Leaving' message from %s", message->issuer_host_name.c_str()); // modify my predecessor setPredecessor(message->request_id); delete message; /*TODO : >> notify my new predecessor >> send a notify_predecessors !! */ break; case SUCCESSOR_LEAVING: // my successor is about to quit XBT_DEBUG("Receiving a 'Successor Leaving' message from %s", message->issuer_host_name.c_str()); // modify my successor FIXME : this should be implicit ? setFinger(0, message->request_id); delete message; /* TODO >> notify my new successor >> update my table & predecessors table */ break; case PREDECESSOR_ALIVE: XBT_DEBUG("Receiving a 'Predecessor Alive' request from %s", message->issuer_host_name.c_str()); message->type = PREDECESSOR_ALIVE_ANSWER; XBT_DEBUG("Sending back a 'Predecessor Alive Answer' to %s (mailbox %s)", message->issuer_host_name.c_str(), message->answer_to->get_cname()); message->answer_to->put_init(message, 10)->detach(ChordMessage::destroy); break; default: XBT_DEBUG("Ignoring unexpected message: %d from %s", message->type, message->issuer_host_name.c_str()); delete message; } }