void set_sorted(Set *set, zval *obj) { Set *sorted = set_clone(set); htable_sort_by_key(sorted->table); set_init_zval_ex(obj, sorted); }
static void handle_gc_msg(unsigned code, unsigned gen, int fd, bool isclient) { char *source = isclient ? "client" : "worker"; word_t w; #if RPT >= 5 report(5, "Received GC message with code %u from fd %d (%s), while in state %u", code, fd, source, gc_state); #endif switch (gc_state) { case GC_READY: if (isclient && code == MSG_GC_START) { /* Garbage collection initiated by client */ #if RPT >= 4 report(4, "GC request by client"); #endif do_controller_collect_cmd(0, NULL); } else if (!isclient && code == MSG_GC_REQUEST) { if (gen == gc_generation+1) { #if RPT >= 4 report(4, "GC request by worker"); #endif do_controller_collect_cmd(0, NULL); } else { #if RPT >= 4 report(4, "Outdated (gen = %u, current generation = %u) GC request by worker", gen, gc_generation); #endif } } else { err(false, "Unexpected GC message. Code %u. In GC_READY state", code); } break; case GC_WAIT_WORKER_START: if (code == MSG_GC_START && !isclient) { need_worker_cnt--; if (need_worker_cnt == 0) { chunk_ptr msg = msg_new_gc_start(); set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { int cfd = (int) w; if (!chunk_write(cfd, msg)) { err(false, "Failed to send GC start message to client with fd %d", cfd); } } chunk_free(msg); need_client_fd_set = set_clone(client_fd_set, NULL); gc_state = GC_WAIT_CLIENT; #if RPT >= 3 report(3, "GC waiting for clients to finish"); #endif } } else if (code == MSG_GC_REQUEST) { #if RPT >= 4 report(4, "GC request by worker while waiting for workers to start. Ignored."); #endif } else { err(false, "Unexpected code %u from %s while waiting for workers to start", code, source); } break; case GC_WAIT_CLIENT: if (code == MSG_GC_FINISH && isclient) { if (set_member(need_client_fd_set, (word_t) fd, true)) { if (need_client_fd_set->nelements == 0) { set_free(need_client_fd_set); need_client_fd_set = NULL; chunk_ptr msg = msg_new_gc_finish(); set_iterstart(worker_fd_set); while (set_iternext(worker_fd_set, &w)) { int wfd = (int) w; if (!chunk_write(wfd, msg)) { err(false, "Failed to send GC Finish message to worker with fd %d", wfd); } } chunk_free(msg); gc_state = GC_WAIT_WORKER_FINISH; #if RPT >= 3 report(3, "GC waiting for workers to finish"); #endif need_worker_cnt = worker_fd_set->nelements; } } else { err(false, "Got unexpected GC_FINISH message from client with fd %d", fd); } } else if (code == MSG_GC_REQUEST) { #if RPT >= 4 report(4, "GC request by worker while waiting for client. Ignored."); #endif } else { err(false, "Unexpected code %u from %s while waiting for clients to finish", code, source); } break; case GC_WAIT_WORKER_FINISH: if (code == MSG_GC_FINISH && !isclient) { need_worker_cnt--; if (need_worker_cnt == 0) { chunk_ptr msg = msg_new_gc_finish(); set_iterstart(client_fd_set); while (set_iternext(client_fd_set, &w)) { int cfd = (int) w; if (!chunk_write(cfd, msg)) err(false, "Failed to send GC finish message to client with fd %d", fd); } chunk_free(msg); /* See if there are deferred client connections */ if (defer_client_fd_set != NULL) { set_iterstart(defer_client_fd_set); while (set_iternext(defer_client_fd_set, &w)) { int cfd = (int) w; set_insert(client_fd_set, (word_t) cfd); #if RPT >= 4 report(4, "Added deferred client with fd %d", cfd); #endif if (need_workers == 0) add_agent(cfd, true); } set_free(defer_client_fd_set); defer_client_fd_set = NULL; } gc_state = GC_READY; #if RPT >= 3 report(3, "GC completed"); #endif } } else if (code == MSG_GC_REQUEST) { #if RPT >= 4 report(4, "GC request by worker while waiting for workers to finish. Ignored."); #endif } else { err(false, "Unexpected code %u from %s while waiting for workers to finish", code, source); } break; default: err(false, "GC in unexpected state %u", gc_state); } }