void * fqd_worker_thread(void *arg) { struct incoming_message *m; int tindex = *(int*) arg; ck_fifo_spsc_t *q = &work_queues[tindex]; uint32_t *backlog = &work_queue_backlogs[tindex]; while (!worker_thread_shutdown) { if (!CK_FIFO_SPSC_ISEMPTY(q)) { if (ck_fifo_spsc_dequeue(q, &m)) { if (m != NULL) { ck_pr_dec_32(backlog); fq_msg *copy = fq_msg_alloc_BLANK(m->msg->payload_len); if (copy == NULL) { continue; } memcpy(copy, m->msg, sizeof(fq_msg) + m->msg->payload_len); /* reset the refcnt on the copy since the memcpy above will have overwritten it */ copy->refcnt = 1; /* the copy will be freed as normal so eliminate cleanup_stack pointer */ copy->cleanup_stack = NULL; /* we are done with the incoming message, deref */ fq_msg_deref(m->msg); fqd_inject_message(m->client, copy); fqd_remote_client_deref((remote_client *)m->client); free(m); } } } else { usleep(1000); } } /* drain the queue before exiting */ if (!CK_FIFO_SPSC_ISEMPTY(q)) { ck_fifo_spsc_dequeue_lock(q); if (ck_fifo_spsc_dequeue(q, &m)) { if (m != NULL) { ck_pr_dec_32(backlog); fq_msg *copy = fq_msg_alloc_BLANK(m->msg->payload_len); memcpy(copy, m->msg, sizeof(fq_msg) + m->msg->payload_len); /* the copy will be freed as normal so eliminate cleanup_stack pointer */ copy->cleanup_stack = NULL; /* we are done with the incoming message, drop it on it's cleanup stack */ fqd_inject_message(m->client, copy); fq_msg_deref(m->msg); free(m); } } ck_fifo_spsc_dequeue_unlock(q); } usleep(10); return NULL; }
buffered_msg_reader *fq_buffered_msg_reader_alloc(int fd, uint32_t peermode) { buffered_msg_reader *br; br = calloc(1, sizeof(*br)); br->fd = fd; br->peermode = peermode; br->msg = fq_msg_alloc_BLANK(0); return br; }
int main(int argc, char **argv) { hrtime_t s0, s, f, f0; uint64_t cnt = 0, icnt = 0; int psize = 0, i = 0; fq_client c; fq_msg *m; char *fq_debug = getenv("FQ_DEBUG"); if(fq_debug) fq_debug_set_bits(atoi(fq_debug)); signal(SIGPIPE, SIG_IGN); fq_client_init(&c, 0, logger); if(argc < 5) { fprintf(stderr, "%s <host> <port> <user> <pass> [size [count]]\n", argv[0]); exit(-1); } fq_client_creds(c, argv[1], atoi(argv[2]), argv[3], argv[4]); fq_client_heartbeat(c, 1000); fq_client_set_backlog(c, 10000, 100); fq_client_connect(c); if(argc > 5) { psize = atoi(argv[5]); } printf("payload size -> %d\n", psize); if(argc > 6) { send_count = atoi(argv[6]); } printf("message count -> %d\n", send_count); s0 = s = fq_gethrtime(); while(i < send_count || fq_client_data_backlog(c) > 0) { if(i < send_count) { m = fq_msg_alloc_BLANK(psize); memset(m->payload, 0, psize); fq_msg_exchange(m, "maryland", 8); fq_msg_route(m, "test.prefix.boo", 15); fq_msg_id(m, NULL); fq_client_publish(c, m); cnt++; i++; fq_msg_free(m); } else usleep(100); f = fq_gethrtime(); if(f-s > 1000000000) { print_rate(c, s, f, cnt, icnt); icnt = 0; cnt = 0; s = f; } } f0 = fq_gethrtime(); print_rate(c, s0, f0, i, 0); (void) argc; return 0; }
static int fqd_http_message_headers_complete(http_parser *p) { #define EXPECT_CONTINUE "HTTP/1.1 100 Continue\r\n\r\n" const char *clen; static char *expect_continue = EXPECT_CONTINUE; static int expect_continue_len = sizeof(EXPECT_CONTINUE)-1; struct http_req *req = p->data; if(req->expect_continue == HTTP_EXPECT_CONTINUE) { while(write(req->client->fd, expect_continue, expect_continue_len) == -1 && errno == EINTR); req->expect_continue = HTTP_EXPECT_SENT; } clen = fqd_http_header(req, "content-length"); if(!strcmp(req->url, "/submit") && clen) { req->body_len = atoi(clen); req->msg = fq_msg_alloc_BLANK(req->body_len); } return 0; }
int main(int argc, char **argv) { hrtime_t s0, s, f, f0; uint64_t cnt = 0, icnt = 0; int psize = 0, i = 0, rcvd = 0; fq_client c; fq_bind_req breq; fq_msg *m; signal(SIGPIPE, SIG_IGN); fq_client_init(&c, 0, logger); if(argc < 5) { fprintf(stderr, "%s <host> <port> <user> <pass> [size [count]]\n", argv[0]); exit(-1); } fq_client_creds(c, argv[1], atoi(argv[2]), argv[3], argv[4]); fq_client_heartbeat(c, 1000); fq_client_set_backlog(c, 10000, 100); fq_client_connect(c); memset(&breq, 0, sizeof(breq)); memcpy(breq.exchange.name, "maryland", 8); breq.exchange.len = 8; breq.peermode = 0; breq.program = (char *)"prefix:\"test.prefix.\""; fq_client_bind(c, &breq); while(breq.out__route_id == 0) usleep(100); printf("route set -> %u\n", breq.out__route_id); if(breq.out__route_id == FQ_BIND_ILLEGAL) { fprintf(stderr, "Failure to bind...\n"); exit(-1); } if(argc > 5) { psize = atoi(argv[5]); } printf("payload size -> %d\n", psize); if(argc > 6) { send_count = atoi(argv[6]); } printf("message count -> %d\n", send_count); s0 = s = fq_gethrtime(); while(i < send_count || fq_client_data_backlog(c) > 0) { if(i < send_count) { m = fq_msg_alloc_BLANK(psize); memset(m->payload, 0, psize); fq_msg_exchange(m, "maryland", 8); fq_msg_route(m, "test.prefix.foo", 15); fq_msg_id(m, NULL); fq_client_publish(c, m); cnt++; i++; fq_msg_free(m); } else usleep(100); f = fq_gethrtime(); while(m = fq_client_receive(c)) { icnt++; rcvd++; fq_msg_deref(m); } if(f-s > 1000000000) { print_rate(c, s, f, cnt, icnt); icnt = 0; cnt = 0; s = f; } } f0 = fq_gethrtime(); print_rate(c, s0, f0, i, 0); do { icnt=0; while(m = fq_client_receive(c)) { icnt++; rcvd++; fq_msg_deref(m); } } while(rcvd < send_count); f0 = fq_gethrtime(); print_rate(c, s0, f0, 0, rcvd); printf("Total received during test: %d\n", rcvd); (void) argc; return 0; }
/* * return 0: keep going (to write path) * return -1: busted */ int fq_buffered_msg_read(buffered_msg_reader *f, void (*f_msg_handler)(void *, fq_msg *), void *closure) { int rv; if(f->into_body < f->msg.payload_len) { assert(f->copy); /* we need to be reading a largish payload */ while((rv = read(f->fd, f->copy->payload + f->into_body, f->copy->payload_len - f->into_body)) == -1 && errno == EINTR); if(rv < 0 && errno == EAGAIN) return 0; if(rv <= 0) { fq_debug(FQ_DEBUG_IO, "read error: %s\n", rv < 0 ? strerror(errno) : "end-of-line"); return -1; } fq_debug(FQ_DEBUG_MSG, "%p <-- %d bytes for payload\n", (void *)f, rv); f->into_body += rv; if(f->into_body == f->copy->payload_len) { f->into_body = 0; goto message_done; } } while((rv = read(f->fd, f->scratch+f->nread, sizeof(f->scratch)-f->nread)) == -1 && errno == EINTR); fq_debug(FQ_DEBUG_IO, "%p <-- %d bytes @ %d (%d)\n", (void *)f, rv, (int)f->nread, (int)f->nread + (rv > 0) ? rv : 0); if(rv == -1 && errno == EAGAIN) return 0; if(rv <= 0) return -1; f->nread += rv; while(f->nread>0) { uint32_t body_available; int body_start; body_start = parse_message_headers(f->peermode, f->scratch+f->off, f->nread-f->off, &f->msg); f->into_body = 0; fq_debug(FQ_DEBUG_MSG, "%d = parse(+%d, %d) -> %d\n", body_start, f->off, (int)f->nread-f->off, body_start ? (int)f->msg.payload_len : 0); if(body_start < 0) return -1; if(!body_start) { fq_debug(FQ_DEBUG_MSG, "incomplete message header...\n"); memmove(f->scratch, f->scratch + f->off, f->nread - f->off); f->nread -= f->off; f->off = 0; return 0; } /* We have a message... or the formal beginnings of one */ f->copy = fq_msg_alloc_BLANK(f->msg.payload_len); memcpy(f->copy, &f->msg, sizeof(f->msg)); f->off += body_start; body_available = f->nread - f->off; if(f->copy->payload_len < body_available) body_available = f->copy->payload_len; memcpy(f->copy->payload, f->scratch+f->off, body_available); if(body_available == f->copy->payload_len) { f->off += body_available; message_done: f->copy->refcnt = 1; fq_debug(FQ_DEBUG_MSG, "message read... injecting\n"); f_msg_handler(closure, f->copy); f->copy = NULL; memset(&f->msg, 0, sizeof(f->msg)); } else { f->nread = 0; f->off = 0; f->into_body = body_available; fq_debug(FQ_DEBUG_MSG, "incomplete message... (%d needed)\n", (int)f->msg.payload_len - (int)f->into_body); return 0; } } return 0; }
/* * return 0: keep going (to write path) * return -1: busted * * Read into one of N buffers so the processing thread * can do the work separate from the read */ int fq_buffered_msg_read(buffered_msg_reader *f, void (*f_msg_handler)(void *, fq_msg *), void *closure) { int rv; static char scratch_buf[IN_READ_BUFFER_SIZE]; while(f->into_body < f->msg->payload_len) { fq_assert(f->copy); /* we need to be reading a largish payload */ if(f->into_body >= MAX_MESSAGE_SIZE) { /* read into a scratch buffer */ size_t readsize = f->copy->payload_len - f->into_body; if(readsize > sizeof(scratch_buf)) readsize = sizeof(scratch_buf); while((rv = read(f->fd, scratch_buf, readsize)) == -1 && errno == EINTR); } else { while((rv = read(f->fd, f->copy->payload + f->into_body, CAPPED(f->copy->payload_len) - f->into_body)) == -1 && errno == EINTR); } if(rv < 0 && errno == EAGAIN) return 0; if(rv <= 0) { fq_debug(FQ_DEBUG_IO, "read error: %s\n", rv < 0 ? strerror(errno) : "end-of-line"); return -1; } fq_debug(FQ_DEBUG_MSG, "%p <-- %d bytes for payload\n", (void *)f, rv); f->into_body += rv; if(f->into_body == f->copy->payload_len) { f->into_body = 0; goto message_done; } } while((rv = read(f->fd, f->scratch+f->nread, sizeof(f->scratch)-f->nread)) == -1 && errno == EINTR); fq_debug(FQ_DEBUG_IO, "%p <-- %d bytes @ %d (%d)\n", (void *)f, rv, (int)f->nread, (int)f->nread + ((rv > 0) ? rv : 0)); if(rv == -1 && errno == EAGAIN) return 0; if(rv <= 0) return -1; f->nread += rv; while(f->nread>0) { uint32_t body_available; int body_start; body_start = parse_message_headers(f->peermode, f->scratch+f->off, f->nread-f->off, f->msg); f->into_body = 0; fq_debug(FQ_DEBUG_MSG, "%d = parse(+%d, %d) -> %d\n", body_start, f->off, (int)f->nread-f->off, body_start ? (int)f->msg->payload_len : 0); if(body_start < 0) return -1; if(!body_start) { fq_debug(FQ_DEBUG_MSG, "incomplete message header...\n"); memmove(f->scratch, f->scratch + f->off, f->nread - f->off); f->nread -= f->off; f->off = 0; return 0; } free_message_stack *tls_free_message_stack = NULL; int msg_stack_idx = msg_free_stack_select(f->msg->payload_len); if(msg_stack_idx >= 0) { if(tls_free_message_handle == NULL) tls_free_message_handle = free_message_handle_acquire(); if(tls_free_message_handle->stacks[msg_stack_idx] == NULL) { /* lazy create/init the cleanup stack */ tls_free_message_handle->stacks[msg_stack_idx] = malloc(sizeof(free_message_stack)); fq_init_free_message_stack(tls_free_message_handle->stacks[msg_stack_idx], FREE_MSG_LIST_SIZE/(1 << (msg_stack_idx + MSG_FREE_BASE)), (1 << (msg_stack_idx + MSG_FREE_BASE))); } tls_free_message_stack = tls_free_message_handle->stacks[msg_stack_idx]; } if(tls_free_message_stack) { /* We have a message... or the formal beginnings of one */ f->copy = fq_pop_free_message_stack(tls_free_message_stack); if (f->copy == NULL) { /* ran out of entries in free list */ f->copy = fq_msg_alloc_BLANK(tls_free_message_stack->alloc_size); if (f->copy == NULL) { /* this is bad, we can't alloc */ fq_debug(FQ_DEBUG_MSG, "unable to malloc, OOM?\n"); return -1; } } /* always 1 as this msg only lives until it's copied by a worker thread */ memcpy(f->copy, f->msg, sizeof(fq_msg)); f->copy->refcnt = 1; f->copy->free_fn = fq_free_msg_fn; } else { f->copy = fq_msg_alloc_BLANK(CAPPED(f->msg->payload_len)); if (f->copy == NULL) { /* this is bad, we can't alloc */ fq_debug(FQ_DEBUG_MSG, "unable to malloc, OOM?\n"); return -1; } memcpy(f->copy, f->msg, sizeof(fq_msg)); f->copy->refcnt = 1; f->copy->free_fn = NULL; } /* assign the cleanup stack for this message */ f->copy->cleanup_handle = tls_free_message_stack ? tls_free_message_handle : NULL; memset(&f->copy->cleanup_stack_entry, 0, sizeof(ck_stack_entry_t)); f->off += body_start; body_available = f->nread - f->off; if(f->copy->payload_len < body_available) body_available = f->copy->payload_len; memcpy(f->copy->payload, f->scratch+f->off, CAPPED(body_available)); if(body_available == f->copy->payload_len) { f->off += body_available; message_done: f->copy->refcnt = 1; f->copy->payload_len = CAPPED(f->copy->payload_len); fq_debug(FQ_DEBUG_MSG, "message read... injecting\n"); f->copy->arrival_time = fq_gethrtime(); f_msg_handler(closure, f->copy); f->copy = NULL; memset(f->msg, 0, sizeof(fq_msg)); /* It is still allocated and we are the sole owner, refcnt must be 1 */ f->msg->refcnt = 1; } else { f->nread = 0; f->off = 0; f->into_body = body_available; fq_debug(FQ_DEBUG_MSG, "incomplete message... (%d needed)\n", (int)f->msg->payload_len - (int)f->into_body); return 0; } } return 0; }