Example #1
0
/* Accumulate worker messages with statistics */
static void add_stat_message(chunk_ptr msg) {
    size_t *stat_summary = NULL;
    stat_messages[stat_message_cnt++] = msg;
    /* See if we've accumulated a full set */
    if (stat_message_cnt >= worker_cnt) {
	size_t nstat = stat_messages[0]->length - 1;
	if (flush_requestor_fd >= 0)
	    stat_summary = calloc_or_fail(nstat * 3, sizeof(size_t),
					  "add_stat_message");
	/* Accumulate and print */
#if RPT >= 1
	report(1, "Worker statistics:");
#endif
	size_t i, w;
	for (i = 0; i < nstat; i++) {
	    chunk_ptr msg = stat_messages[0];
	    word_t minval, maxval, sumval;
	    minval = maxval = sumval = chunk_get_word(msg, i+1);
	    for (w = 1; w < worker_cnt; w++) {
		chunk_ptr msg = stat_messages[w];
		word_t val = chunk_get_word(msg, i+1);
		if (val < minval)
		    minval = val;
		if (val > maxval)
		    maxval = val;
		sumval += val;
	    }
	    if (stat_summary) {
		stat_summary[3*i + 0] = minval;
		stat_summary[3*i + 1] = maxval;
		stat_summary[3*i + 2] = sumval;
	    }
#if RPT >= 1
	    report(1,
"Parameter %d\tMin: %" PRIu64 "\tMax: %" PRIu64 "\tAvg: %.2f\tSum: %" PRIu64,
		   (int) i, minval, maxval, (double) sumval/worker_cnt, sumval);
#endif
	}
	if (flush_requestor_fd >= 0) {
	    chunk_ptr msg = msg_new_stat(worker_cnt, nstat*3, stat_summary);
	    if (chunk_write(flush_requestor_fd, msg)) {
#if RPT >= 5
		report(5, "Sent statistical summary to client at fd %d",
		       flush_requestor_fd);
#endif
	    } else {
		err(false, "Failed to send statistical summary to client at fd %d",
		    flush_requestor_fd);
	    }
	    chunk_free(msg);
	    free_array(stat_summary, nstat*3, sizeof(size_t));
	}
	for (w = 0; w < worker_cnt; w++) {
	    chunk_free(stat_messages[w]);
	    stat_messages[w] = NULL;
	}
	stat_message_cnt = 0;
	flush_requestor_fd = -1;
    }
}
Example #2
0
/* Insert an operand into an operation */
void op_insert_operand(chunk_ptr op, chunk_ptr oper, unsigned offset) {
    size_t i;
    size_t n = oper->length-OPER_HEADER_CNT;
#if RPT >= 5
    dword_t dh = chunk_get_dword(op, 0);
    unsigned opcode = msg_get_dheader_opcode(dh);
    word_t vmask = chunk_get_word(op, 2);
    report(5,
	   "Inserting operand with %u words into op with opcode %u at offset %u.  Mask 0x%lx",
	   (unsigned) n, opcode, offset, vmask);
#endif
    for (i = 0; i < n; i++) {
	word_t w = chunk_get_word(oper, i+OPER_HEADER_CNT);
	op_insert_word(op, w, i+offset);
    }
}
Example #3
0
/* Extract subchunk */
chunk_ptr chunk_get_chunk(chunk_ptr cp, size_t offset, size_t length) {
    chunk_ptr ncp = chunk_new(length);
    size_t i;
    for (i = 0; i < length; i++) {
	chunk_insert_word(ncp, chunk_get_word(cp, i+offset), i);
    }
    return ncp;
}
Example #4
0
/* Get string that has been stored as chunk */
char * chunk2str(chunk_ptr cp) {
    char buf[WORD_BYTES * CHUNK_MAX_LENGTH+1];
    /* Make sure string is terminated */
    buf[WORD_BYTES * cp->length] = '\0';
    word_t *wp = (word_t *) buf;
    size_t cidx;
    for (cidx = 0; cidx < cp->length; cidx++) {
	wp[cidx] = chunk_get_word(cp, cidx);
    }
    return strsave_or_fail(buf, "chunk2str");
}
Example #5
0
/* Check whether all fields an an operator are valid */
bool op_check_full(chunk_ptr op) {
    if (op == NULL) {
	err(false, "op_check_full given null pointer");
	return false;
    }
    word_t len = op->length;
    word_t vmask = chunk_get_word(op, 2);
    /* Create checking vmask */
    word_t cmask = len == OP_MAX_LENGTH ? ~0ULL : (1ULL << len) - 1;
    return vmask == cmask;
}
Example #6
0
/* Insert word into operator, updating its valid mask.
   Offset includes header size */
void op_insert_word(chunk_ptr op, word_t wd, size_t offset) {
    word_t vmask = chunk_get_word(op, 2);
    word_t nvmask;
    word_t idx = (word_t) 1 << offset;
    if (vmask & idx) {
	err(false,
"Inserting into already filled position in operator.  Offset = %lu", offset);
    }
    chunk_insert_word(op, wd, offset);
    nvmask = vmask | idx;
    chunk_insert_word(op, nvmask, 2);
#if RPT >= 6
    dword_t dh = chunk_get_dword(op, 0);
    word_t id = msg_get_dheader_op_id(dh);
    report(6,
	   "Inserted word, offset %d, operation with id 0x%lx.\n"
	   "  Total size = %d.  Vmask 0x%lx --> 0x%lx",
	   (int) offset, id, op->length, vmask, nvmask);
#endif
}
Example #7
0
void run_worker() {
    while (true) {
	/* Select among controller port, and connections to routers */
	FD_ZERO(&cset);
	maxcfd = 0;
	add_cfd(controller_fd);
	unsigned ridx;
	for (ridx = 0; ridx < nrouters; ridx++)
	    add_cfd(router_fd_array[ridx]);

	buf_select(maxcfd+1, &cset, NULL, NULL, NULL);
	int fd;
	for (fd = 0; fd <= maxcfd; fd++) {
	    if (!FD_ISSET(fd, &cset))
		continue;
	    bool eof;
	    chunk_ptr msg = chunk_read(fd, &eof);
	    if (eof) {
		/* Unexpected EOF */
		if (fd == controller_fd) {
		    err(true, "Unexpected EOF from controller (fatal)");
		} else {
		    err(false,
			"Unexpected EOF from router with fd %d (shutting down)", fd);
		    finish_cmd();
		    exit(0);
		}
		close(fd);
		continue;
	    }
	    if (msg == NULL) {
		err(false, "Could not read chunk from fd %d (ignored)", fd);
		continue;
	    }
	    word_t h = chunk_get_word(msg, 0);
	    /* Rely on fact that following message fields in same location
	       for both single and double-word headers */
	    unsigned code = msg_get_header_code(h);
	    unsigned agent = msg_get_header_agent(h); 
	    unsigned opcode = msg_get_header_opcode(h);
	    if (fd == controller_fd) {
		/* Message from controller */
		switch(code) {
		case MSG_KILL:
		    chunk_free(msg);
#if RPT >= 1
		    report(1, "Received kill message from controller");
#endif
		    quit_agent(0, NULL);
		    return;
		case MSG_DO_FLUSH:
		    chunk_free(msg);
#if RPT >= 5
		    report(5, "Received flush message from controller");
#endif
		    if (flush_helper) {
			chunk_ptr msg = flush_helper();
			if (!msg)
			    break;
			if (chunk_write(controller_fd, msg)) {
#if RPT >= 5
			    report(5,
				   "Sent statistics information to controller");
#endif
			} else {
			    err(false,
"Failed to send statistics information to controller");
			}
			chunk_free(msg);
		    }
		    break;
		case MSG_CLIOP_DATA:
		    report(5,
			   "Received client operation data.  Agent = %u", agent);
		    word_t *data = &msg->words[1];
		    unsigned nword = msg->length - 1;
		    if (gop_start_helper)
			gop_start_helper(agent, opcode, nword, data);
		    chunk_free(msg);
		    chunk_ptr rmsg = msg_new_cliop_ack(agent);
		    if (chunk_write(controller_fd, rmsg)) {
#if RPT >= 5
			report(5,
			       "Acknowledged client operation data.  Agent = %u",
			       agent);
#endif
		    } else {
			err(false,
"Failed to acknowledge client operation data.  Agent = %u",
			    agent);
		    }
		    chunk_free(rmsg);
		    break;
		case MSG_CLIOP_ACK:
#if RPT >= 5
		    report(5, "Received client operation ack.  Agent = %u", agent);
#endif
		    if (gop_finish_helper)
			gop_finish_helper(agent);
		    chunk_free(msg);
		    break;
		case MSG_GC_START:
		    chunk_free(msg);
		    gc_start(code);
		    break;
		case MSG_GC_FINISH:
		    chunk_free(msg);
		    gc_finish(code);
		    break;
		default:
		    chunk_free(msg);
		    err(false,
"Unknown message code %u from controller (ignored)", code);
		}
	    } else {
		/* Must be message from router */
		switch (code) {
		case MSG_OPERATION:
		    receive_operation(msg);
		    break;
		case MSG_OPERAND:
		    receive_operand(msg);
		    break;
		default:
		    chunk_free(msg);
		    err(false,
"Received message with unknown code %u (ignored)", code);
		}
	    }
	}
    }
    quit_agent(0, NULL);
}
Example #8
0
/*
  Initiate global operation from client.
  Returns to client when all workers ready to perform their operations
*/
bool start_client_global(unsigned opcode, unsigned nword, word_t *data) {
    chunk_ptr rmsg = msg_new_cliop_data(own_agent, opcode, nword, data);
    if (!chunk_write(controller_fd, rmsg)) {
	err(false, "Could not send client operation message to controller");
	chunk_free(rmsg);
	return false;
    }
    chunk_free(rmsg);
    /* Read ACK, as well as any other messages the controller might have */
    bool done = false;
    bool ok = true;
    while (!done) {
	bool eof = false;
	chunk_ptr msg = chunk_read_unbuffered(controller_fd, &eof);
	if (eof) {
	    /* Unexpected EOF */
	    err(true, "Unexpected EOF from controller (fatal)");
	    close(controller_fd);
	    done = true; ok = false;
	}
	word_t h = chunk_get_word(msg, 0);
	unsigned code = msg_get_header_code(h);
	switch (code) {
	case MSG_DO_FLUSH:
	    chunk_free(msg);
#if RPT >= 5
	    report(5,
"Received flush message from controller, superceding client global operation");
#endif
	    if (flush_helper) {
		flush_helper();
	    }
	    done = true; ok = false;
	    break;
	case MSG_STAT:
#if RPT >= 5
	    report(5, "Received summary statistics from controller");
#endif
	    if (stat_helper) {
		/* Get a copy of the byte usage from memory allocator */
		stat_helper(msg);
	    }
	    chunk_free(msg);
	    break;
	case MSG_KILL:
	    chunk_free(msg);
#if RPT >= 1
	    report(1,
"Received kill message from controller, superceding client global operation");
#endif
	    finish_cmd();
	    done = true; ok = false;
	    break;
	case MSG_CLIOP_ACK:
	    chunk_free(msg);
#if RPT >= 5
	    report(5,
"Received acknowledgement for client global operation");
#endif
	    done = true; ok = true;
	    break;
	case MSG_GC_START:
	    /* Got notice that should initiate garbage collection.
	       Defer until current operation done */
#if RPT >= 3
	    report(3, "Deferring GC start");
#endif
	    chunk_free(msg);
	    gc_state = GC_DEFER;
	    break;
	default:
	    chunk_free(msg);
	    err(false,
"Unknown message code %u from controller (ignored)", code);
	}
    }
    return ok;
}
Example #9
0
void init_agent(bool iscli, char *controller_name, unsigned controller_port,
		bool try_self_route, bool try_local_router) {
    operator_table = word_keyvalue_new();
    deferred_operand_table = word_keyvalue_new();
    size_t i;
    for (i = 0; i < NSTATA; i++)
	agent_stat_counter[i] = 0;

    chunk_ptr msg;
    bool eof;
    isclient = iscli;
    self_route = try_self_route;
    controller_fd = open_clientfd(controller_name, controller_port);
    if (controller_fd < 0)
	err(true, 
	    "Cannot create connection to controller at %s:%u",
	    controller_name, controller_port);
    else {
#if RPT >= 2
	report(2, "Connection to controller has descriptor %d", controller_fd);
#endif
    }
    msg = isclient ? msg_new_register_client() : msg_new_register_worker();
    bool sok = chunk_write(controller_fd, msg);
#if RPT >= 3
    report(3, "Sent %s registration to controller",
	   isclient ? "client" : "worker");
#endif
    chunk_free(msg);
    if (!sok)
	err(true, "Could not send registration message to controller");
    /* Get acknowledgement from controller */
    bool first = true;
    /* Anticipated number of routers 
      (Will be updated when get first message from controller) */
    nrouters = 1;
    chunk_ptr amsg = NULL;
    unsigned ridx = 0;;
    while (ridx < nrouters) {
	msg = chunk_read_unbuffered(controller_fd, &eof);
	if (eof) {
	    err(true,
		"Unexpected EOF from controller while getting router map");
	}
	word_t h = chunk_get_word(msg, 0);
	unsigned code = msg_get_header_code(h);
	switch (code) {
	case MSG_ACK_AGENT:
	    if (first) {
		own_agent = msg_get_header_agent(h);
		amsg = msg_new_register_agent(own_agent);
		nworkers = msg_get_header_workercount(h);
		nrouters = msg_get_header_wordcount(h);
		router_fd_array = calloc_or_fail(nrouters, sizeof(int),
						 "init_agent");
#if RPT >= 3
		report(3,
"Ack from controller.  Agent Id %u.  %d workers.  %d routers.",
		       own_agent, nworkers, nrouters);
#endif
		first = false;
	    }
	    int i;
	    for (i = 1; i < msg->length; i++) {
		word_t h = chunk_get_word(msg, i);
		int fd;
		unsigned ip = msg_get_header_ip(h);
		unsigned port = msg_get_header_port(h);
#if RPT >= 4
		report(4, "Attempting to add router %u with ip 0x%x, port %d",
		       ridx, ip, port);
#endif
		fd = open_clientfd_ip(ip, port);
		if (fd < 0) {
		    err(true, "Couldn't add router with ip 0x%x, port %d",
			ip, port);
		} else {
		    router_fd_array[ridx++] = fd;
#if RPT >= 3
		    report(3, "Added router %u with ip 0x%x, port %d, fd %d",
			   ridx, ip, port, fd);
#endif
		    if (!chunk_write(fd, amsg)) {
			err(true, 
"Couldn't send agent registration message to router with ip 0x%x, port %u",
			    ip, port);
		    }

                    if (try_local_router && local_router_fd == -1 &&
			match_self_ip(ip))
                    {
                        local_router_fd = fd;
#if RPT >= 5
                        report(5,
"Router with fd %d designated as local router and prioritized for sending packets",
			       fd);
#endif
                    }
		}
	    }
	    chunk_free(msg);
	    break;
	case MSG_NACK:
	    err(true, "Connection request refused.");
	    break;
	default:
	    err(false,
"Unexpected message code %u while getting router information", code);
	    chunk_free(msg);
	    break;
	}
    }
    chunk_free(amsg);
#if RPT >= 2
    report(2, "All %d routers connected", nrouters);
#endif
    if (isclient) {
	add_quit_helper(quit_agent);
	add_cmd("kill", do_agent_kill,
		"              | Shutdown system");
	add_cmd("flush", do_agent_flush,   
		"              | Flush system");
	add_cmd("collect", do_agent_gc,
		"              | Initiate garbage collection");
    } else {
	/* Worker must notify controller that it's ready */
	chunk_ptr rmsg = msg_new_worker_ready(own_agent);
	if (chunk_write(controller_fd, rmsg)) {
#if RPT >= 3
	    report(3, "Notified controller that worker is ready");
#endif
	} else {
	    err(true, "Couldn't notify controller that worker is ready");
	}
	chunk_free(rmsg);
    }
}
Example #10
0
/* Client command loop only considers console inputs + controller messages */
void run_client(char *infile_name) {
    if (!start_cmd(infile_name))
	return;
    while (!cmd_done()) {
	/* Select among controller port, and connections to routers */
	FD_ZERO(&cset);
	maxcfd = 0;
	add_cfd(controller_fd);
	cmd_select(maxcfd+1, &cset, NULL, NULL, NULL);
	if (cmd_done())
	    break;
	int fd;
	for (fd = 0; fd <= maxcfd; fd++) {
	    if (!FD_ISSET(fd, &cset))
		continue;
	    bool eof;
	    chunk_ptr msg = chunk_read(fd, &eof);
	    if (eof) {
		/* Unexpected EOF */
		if (fd == controller_fd) {
		    err(true, "Unexpected EOF from controller (fatal)");
		} else {
		    err(false,
"Unexpected EOF from unexpected source. fd %d (ignored)", fd);
		}
		close(fd);
		continue;
	    }
	    if (msg == NULL) {
		err(false, "Could not read chunk from fd %d (ignored)", fd);
		continue;
	    }
	    word_t h = chunk_get_word(msg, 0);
	    unsigned code = msg_get_header_code(h);
	    if (fd == controller_fd) {
		/* Message from controller */
		switch(code) {
		case MSG_DO_FLUSH:
		    chunk_free(msg);
#if RPT >= 5
		    report(5, "Received flush message from controller");
#endif
		    if (flush_helper) {
			flush_helper();
		    }
		    break;
		case MSG_STAT:
#if RPT >= 5
		    report(5, "Received summary statistics from controller");
#endif
		    if (stat_helper) {
			/* Get a copy of the byte usage from mem. allocator */
			stat_helper(msg);
		    }
		    chunk_free(msg);
		    /* Client can proceed with next command */
		    unblock_console();
		    break;
		case MSG_KILL:
		    chunk_free(msg);
#if RPT >= 1
		    report(1, "Received kill message from controller");
#endif
		    finish_cmd();
		    break;
		case MSG_GC_START:
		    chunk_free(msg);
		    gc_start(code);
		    break;
		case MSG_GC_FINISH:
		    chunk_free(msg);
		    gc_finish(code);
		    break;
		default:
		    chunk_free(msg);
		    err(false,
			"Unknown message code %u from controller (ignored)",
			code);
		}
	    } else {
		err(false,
		    "Received message from unknown source.  fd %d (ignored)",
		    fd);
		close(fd);
		continue;
	    }
	}
    }
}
Example #11
0
/* Fire an operation and wait for returned operand */
chunk_ptr fire_and_wait_defer(chunk_ptr msg) {
    chunk_ptr rval = NULL;
    if (!send_op(msg)) {
	err(false, "Failed to send message");
	return NULL;
    }
    bool local_done = false;
    while (!(local_done || cmd_done())) {
	/* Select among controller port, and connections to routers.
	   Do not accept console input */
	FD_ZERO(&rset);
	maxrfd = 0;
	add_rfd(controller_fd);
	unsigned ridx;
	for (ridx = 0; ridx < nrouters; ridx++)
	    add_rfd(router_fd_array[ridx]);

	buf_select(maxrfd+1, &rset, NULL, NULL, NULL);
	int fd;
	for (fd = 0; fd <= maxrfd; fd++) {
	    if (!FD_ISSET(fd, &rset))
		continue;
	    bool eof;
	    chunk_ptr msg = chunk_read(fd, &eof);
	    if (eof) {
		/* Unexpected EOF */
		if (fd == controller_fd) {
		    err(true, "Unexpected EOF from controller (fatal)");
		} else {
		    err(false,
			"Unexpected EOF from router with fd %d (shutting down)", fd);
		    finish_cmd();
		    exit(0);
		}
		close(fd);
		continue;
	    }
	    if (msg == NULL) {
		err(false, "Could not read chunk from fd %d (ignored)", fd);
		continue;
	    }
	    word_t h = chunk_get_word(msg, 0);
	    unsigned code = msg_get_header_code(h);
	    if (fd == controller_fd) {
		/* Message from controller */
		switch(code) {
		case MSG_KILL:
		    chunk_free(msg);
#if RPT >= 1
		    report(1, "Received kill message from controller");
#endif
		    quit_agent(0, NULL);
		    break;
		case MSG_DO_FLUSH:
		    chunk_free(msg);
#if RPT >= 2
		    report(2, "Received flush message from controller");
#endif
		    if (flush_helper) {
			flush_helper(0, NULL);
		    }
		    break;
		case MSG_GC_START:
		    /* Got notice that should initiate garbage collection.
		       Defer until current operation done */
#if RPT >= 3
		    report(3, "Deferring GC start");
#endif
		    chunk_free(msg);
		    gc_state = GC_DEFER;
		    break;
		case MSG_GC_FINISH:
#if RPT >= 3
		    report(3,
"Unexpected GC_FINISH message from controller when waiting for result (ignored)");
#endif
		    chunk_free(msg);
		    break;
		default:
		    chunk_free(msg);
		    err(false,
"Unknown message code %u from controller (ignored)", code);
		}
	    } else {
		dword_t dh;
		word_t id = 0;
		/* Must be message from router */
		switch (code) {
		case MSG_OPERATION:
		    chunk_free(msg);
		    err(false, "Received unexpected operation.  Ignored.");
		    local_done = true;
		    break;
		case MSG_OPERAND:
#if RPT >= 5
		    dh = chunk_get_dword(msg, 0);
		    id = msg_get_dheader_op_id(dh);
		    report(5, "Received operand with id 0x%lx", id);
#endif
		    rval = msg;
		    local_done = true;
		    break;
		default:
		    chunk_free(msg);
		    err(false,
"Received message with unknown code %u (ignored)", code);
		    local_done = true;
		}
	    }
	}
    }
    return rval;
}
Example #12
0
static void run_controller(char *infile_name) {
    if (!start_cmd(infile_name))
	return;
    while (!cmd_done()) {
	FD_ZERO(&set);
	int fd;
	word_t w;
	unsigned ip;
	unsigned port;
	add_fd(listen_fd);
	keyvalue_iterstart(new_conn_map);
	/* Check for messages from newly connected clients, workers, and routers */
	while (keyvalue_iternext(new_conn_map, &w, NULL)) {
	    fd = w;
	    add_fd(fd);
	}
	if (need_routers == 0) {
	    /* Accept messages from workers */
	    set_iterstart(worker_fd_set);
	    while (set_iternext(worker_fd_set, &w)) {
		fd = w;
		add_fd(fd);
	    }
	    /* Accept messages from clients */
	    set_iterstart(client_fd_set);
	    while (set_iternext(client_fd_set, &w)) {
		fd = w;
		add_fd(fd);
	    }
	}

	cmd_select(maxfd+1, &set, NULL, NULL, NULL);

	for (fd = 0; fd <= maxfd; fd++) {
	    if (!FD_ISSET(fd, &set))
		continue;
	    if (fd == listen_fd) {
		unsigned ip;
		int connfd = accept_connection(fd, &ip);
		keyvalue_insert(new_conn_map, (word_t) connfd, (word_t) ip);
#if RPT >= 4
		report(4, "Accepted new connection.  Connfd = %d, IP = 0x%x",
		       connfd, ip);
#endif
		continue;
	    }
	    bool eof;
	    chunk_ptr msg = chunk_read(fd, &eof);
	    if (eof) {
		/* Unexpected EOF */
		if (keyvalue_remove(new_conn_map, (word_t) fd, NULL, NULL)) {
		    err(false, "Unexpected EOF from new connection, fd %d", fd);
		} else if (set_member(worker_fd_set, (word_t) fd, true)) {
		    err(false, "Unexpected EOF from connected worker, fd %d.  Shutting down", fd);
		    /* Shut down system */
		    finish_cmd();
		} else if (set_member(client_fd_set, (word_t) fd, true)) {
#if RPT >= 3
		    report(3, "Disconnection from client (fd %d)", fd);
#endif
		    if (need_client_fd_set && set_member(need_client_fd_set,
							 (word_t) fd, false)) {
#if RPT >= 3
			report(3, "Removing client from GC activities");
#endif
			handle_gc_msg(MSG_GC_FINISH, 0, fd, true);
		    }
		} else {
		    err(false, "Unexpected EOF from unknown source, fd %d", fd);
		}
		close(fd);
		continue;
	    }
	    if (msg == NULL) {
		err(false, "Could not read chunk from fd %d (ignored)", fd);
		continue;
	    }
	    word_t h = chunk_get_word(msg, 0);
	    unsigned code = msg_get_header_code(h);
#if RPT >= 5
	    report(5, "Received message with code %d from fd %d", code, fd);
#endif
	    if (keyvalue_remove(new_conn_map, (word_t) fd, NULL, &w)) {
		ip = w;
		chunk_free(msg);
		/* Should be a registration message */
		switch (code) {
		case MSG_REGISTER_ROUTER:
		    if (need_routers == 0) {
			err(false, "Unexpected router registration.  (Ignored)");
			close(fd);
			break;
		    }
		    port = msg_get_header_port(h);
		    word_t node_id = msg_build_node_id(port, ip);
		    set_insert(router_addr_set, node_id);
		    set_insert(router_fd_set, (word_t) fd);
#if RPT >= 4
		    report(4, "Added router with fd %d.  IP 0x%x.  Port %u",
			   fd, ip, port);
#endif
		    need_routers --;
		    if (need_routers == 0) {
#if RPT >= 2
			report(2, "All routers connected");
#endif
			/* Have gotten all of the necessary routers.
			   Notify any registered workers */
			set_iterstart(worker_fd_set);
			int wfd;
			while (set_iternext(worker_fd_set, &w)) {
			    wfd = w;
			    add_agent(wfd, false);
			}
		    }
		    break;
		case MSG_REGISTER_WORKER:
		    if (worker_fd_set->nelements >= worker_cnt) {
			err(false, "Unexpected worker registration.  (Ignored)");
			close(fd);
			break;
		    }
		    set_insert(worker_fd_set, (word_t) fd);
#if RPT >= 4
		    report(4, "Added worker with fd %d", fd);
#endif
		    if (need_routers == 0)
			add_agent(fd, false);
		    break;
		case MSG_REGISTER_CLIENT:
		    if (gc_state == GC_READY) {
			set_insert(client_fd_set, (word_t) fd);
#if RPT >= 4
			report(4, "Added client with fd %d", fd);
#endif
			if (need_workers == 0)
			    add_agent(fd, true);
		    } else {
			if (!defer_client_fd_set) {
			    defer_client_fd_set = word_set_new();
			}
			set_insert(defer_client_fd_set, (word_t) fd);
#if RPT >= 3
			report(3, "Deferring client with fd %d until GC completed",
			       fd);
#endif
		    }
		    break;
		default:
		    err(false, "Unexpected message code %u from new connection",
			code);
		    break;
		}
	    } else if (set_member(worker_fd_set, (word_t) fd, false)) {
		/* Message from worker */
		switch (code) {
		    unsigned agent;
		    unsigned gen;
		case MSG_READY_WORKER:
		    chunk_free(msg);
		    if (need_workers == 0) {
			err(false, "Unexpected worker ready.  (Ignored)");
			close(fd);
			break;
		    }
		    need_workers--;
		    if (need_workers == 0) {
#if RPT >= 2
			report(2, "All workers connected");
#endif			
			/* Notify any pending clients */
			set_iterstart(client_fd_set);
			int cfd;
			while (set_iternext(client_fd_set, &w)) {
			    cfd = w;
			    add_agent(cfd, true);
			}
		    }
		    break;
		case MSG_STAT:
		    /* Message gets stashed away.  Don't free it */
		    add_stat_message(msg);
		    break;
		case MSG_CLIOP_ACK:
		    /* Worker acknowledging receipt of global operation info */
		    agent = msg_get_header_agent(h);
		    int client_fd = receive_global_op_worker_ack(agent);
		    if (client_fd >= 0) {
			/* Have received complete set of acknowledgements. */
			/* Send ack to client */
			if (chunk_write(client_fd, msg)) {
#if RPT >= 6
			    report(6,
"Sent ack to client for global operation with id %u", agent);
#endif
			} else {
			    err(false,
"Failed to send ack to client for global operation with id %u.  Fd %d",
				agent, client_fd);
			}
		    }
		    chunk_free(msg);
		    break;
		case MSG_GC_START:
		case MSG_GC_FINISH:
		    handle_gc_msg(code, 0, fd, false);
		    chunk_free(msg);
		    break;
		case MSG_GC_REQUEST:
		    gen = msg_get_header_generation(h);
		    chunk_free(msg);
		    handle_gc_msg(code, gen, fd, false);
		    break;
		default:
		    chunk_free(msg);
		    err(false, "Unexpected message code %u from worker", code);
		}
	    } else if (set_member(client_fd_set, (word_t) fd, false)) {
		/* Message from client */
		switch(code){
		    unsigned agent;
		    word_t w;
		case MSG_KILL:
		    /* Shutdown entire system */
		    chunk_free(msg);
#if RPT >= 2
		    report(2, "Remote request to kill system");
#endif
		    finish_cmd();
		    return;
		case MSG_DO_FLUSH:
		    /* Initiate a flush operation */
		    chunk_free(msg);
		    flush_requestor_fd = fd;
		    do_controller_flush_cmd(0, NULL);
		    break;
		case MSG_CLIOP_DATA:
		    /* Request for global operation from client */
		    agent = msg_get_header_agent(h);
		    add_global_op(agent, fd);
		    /* Send message to all workers */
		    set_iterstart(worker_fd_set);
		    while (set_iternext(worker_fd_set, &w)) {
			int worker_fd = (int) w;
			if (chunk_write(worker_fd, msg)) {
#if RPT >= 6
			    report(6,
"Sent global operation information with id %u to worker with fd %d",
				   agent, worker_fd);
#endif
			} else {
			    err(false,
"Failed to send global operation information with id %u to worker with fd %d",
				agent, worker_fd);
			}
		    }
		    chunk_free(msg);
		    break;
		case MSG_CLIOP_ACK:
		    /* Completion of global operation by client */
		    agent = msg_get_header_agent(h);
		    /* Send message to all workers */
		    set_iterstart(worker_fd_set);
		    while (set_iternext(worker_fd_set, &w)) {
			int worker_fd = (int) w;
			if (chunk_write(worker_fd, msg)) {
#if RPT >= 6
			    report(6,
"Sent global operation acknowledgement with id %u to worker with fd %d",
				   agent, worker_fd);
#endif
			} else {
			    err(false,
"Failed to send global operation acknowledgement with id %u to worker with fd %d",
				agent, worker_fd);
			}
		    }
		    chunk_free(msg);
		    break;
		case MSG_GC_START:
		case MSG_GC_FINISH:
		    handle_gc_msg(code, 0, fd, true);
		    chunk_free(msg);
		    break;
		default:
		    err(false, "Unexpected message code %u from client", code);
		}

	    } else {
		chunk_free(msg);
		err(false, "Unexpected message on fd %d (Ignored)", fd);
	    }
	}
    }
}