/** * Asynchronous mode we use a large ring buffer to hold the log messages data, * the format of log message is: * protocol_id(2 bytes) | data * * Currently, there are two protocols: 1) fetch msg, 2) thread quit * log_file_ptr(4/8 bytes) | len(2 bytes) | log message(len bytes) */ static size_t _log_async_write(flog_file_t* f, const char* header, size_t header_len, const char* log, size_t len) { int is_report_truncated = 0; if ( len > LOG_MAX_LEN_PER_MSG ) { len = LOG_MAX_LEN_PER_MSG; is_report_truncated = 1; } // check pipe buffer whether have enough space thread_data_t* th_data = _get_or_create_thdata(); size_t msg_body_len = header_len + len + 1; size_t total_msg_len = sizeof(log_fetch_msg_head_t) + msg_body_len; if ( fmbuf_free(th_data->plog_buf) < total_msg_len ) { _log_event_notice(FLOG_EVENT_BUFFER_FULL); return 0; } // wrap and push log message log_fetch_msg_head_t msg_header; msg_header.id = LOG_PTO_FETCH_MSG; msg_header.msgh.f = f; msg_header.msgh.len = (unsigned short)msg_body_len; if ( fmbuf_push(th_data->plog_buf, &msg_header, sizeof(log_fetch_msg_head_t)) ) { _log_event_notice(FLOG_EVENT_ERROR_ASYNC_PUSH); return 0; } if( fmbuf_push(th_data->plog_buf, header, header_len) ) { _log_event_notice(FLOG_EVENT_ERROR_ASYNC_PUSH); return 0; } if( fmbuf_push(th_data->plog_buf, log, len) ) { _log_event_notice(FLOG_EVENT_ERROR_ASYNC_PUSH); return 0; } if( fmbuf_push(th_data->plog_buf, "\n", 1) ) { _log_event_notice(FLOG_EVENT_ERROR_ASYNC_PUSH); return 0; } // notice fetcher to write log if ( eventfd_write(th_data->efd, 1) ) { _log_event_notice(FLOG_EVENT_ERROR_ASYNC_PUSH); return 0; } // this must be reported after async push if (is_report_truncated) { _log_event_notice(FLOG_EVENT_TRUNCATED); } return len; }
static void _log_async_write_f(flog_file_t* f, const char* header, size_t header_len, const char* fmt, va_list ap) { // check whether have private thread data, if not, create it thread_data_t* th_data = _get_or_create_thdata(); // check the pipe buffer whether have enough space size_t max_msg_len = sizeof(log_fetch_msg_head_t) + header_len + LOG_MAX_LEN_PER_MSG + 1; size_t total_free = fmbuf_free(th_data->plog_buf); if ( total_free < max_msg_len ) { _log_event_notice(FLOG_EVENT_BUFFER_FULL); return; } char* head = fmbuf_head(th_data->plog_buf); char* tail = fmbuf_tail(th_data->plog_buf); size_t tail_free_size = tail < head ? total_free : fmbuf_tail_free(th_data->plog_buf); if ( tail_free_size >= max_msg_len ) { // fill log message in mbuf directly char* buf = fmbuf_tail(th_data->plog_buf); size_t buff_size = _log_fill_async_msg(f, th_data, buf, header, header_len, fmt, ap); fmbuf_tail_seek(th_data->plog_buf, buff_size, FMBUF_SEEK_RIGHT); } else { // fill log message in tmp buffer char* buf = th_data->tmp_buf; size_t buff_size = _log_fill_async_msg(f, th_data, buf, header, header_len, fmt, ap); fmbuf_push(th_data->plog_buf, buf, buff_size); } // notice fetcher to write log if ( eventfd_write(th_data->efd, 1) ) { _log_event_notice(FLOG_EVENT_ERROR_ASYNC_PUSH); return; } }
// return 0 : post sucess // return 1 : post failed .. queue full int fthpool_post_task(fth_task pf, void* arg) { if ( !pf ) return 1; th_msg_t tmsg; tmsg.ev = TH_TASK; tmsg.pf = pf; tmsg.arg = arg; ++curr_post; curr_post = curr_post < max_num ? curr_post : 0; thread_data* pdata = pth_pool[curr_post]; if ( fmbuf_push(pdata->pbuf, &tmsg, sizeof(th_msg_t)) ) return 1; flock_cond_signal(&pdata->cond); return 0; }
// test fmbuf push and pop void test_mbuf1() { // create a mbuf with size == 0 { fmbuf* pbuf = fmbuf_create(0); FCUNIT_ASSERT(pbuf != NULL); FCUNIT_ASSERT(0 == fmbuf_size(pbuf)); FCUNIT_ASSERT(0 == fmbuf_used(pbuf)); FCUNIT_ASSERT(0 == fmbuf_free(pbuf)); fmbuf_delete(pbuf); } fmbuf* pbuf = fmbuf_create(10); FCUNIT_ASSERT(pbuf!=NULL); char* push_buf[20]; char* pop_buf[20]; // push 1 byte data { int ret = fmbuf_push(pbuf, push_buf, 1); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(1 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(0 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(9 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(9 == total_free); } // push 9 byte data { int ret = fmbuf_push(pbuf, push_buf, 9); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(10 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(0 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(0 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(0 == total_free); } // continue push 1 byte data when mbuf is full { int ret = fmbuf_push(pbuf, push_buf, 1); FCUNIT_ASSERT(1 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(10 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(0 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(0 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(0 == total_free); } // clear and seek mbuf and push 5 bytes { fmbuf_clear(pbuf); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(10 == total_free); fmbuf_head_seek(pbuf, 4, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(pbuf, 6, FMBUF_SEEK_RIGHT); int ret = fmbuf_push(pbuf, push_buf, 5); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(7 == used); total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(3 == total_free); } // push 4 bytes but the mbuf only have 3 bytes left { int ret = fmbuf_push(pbuf, push_buf, 4); FCUNIT_ASSERT(1 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(7 == used); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(3 == total_free); } // push 3 bytes the mbuf is full { int ret = fmbuf_push(pbuf, push_buf, 3); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(10 == used); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(0 == total_free); ret = fmbuf_push(pbuf, push_buf, 1); FCUNIT_ASSERT(1 == ret); } //---------------mbuf pop------------------- //pop 1 bytes { fmbuf_clear(pbuf); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); int ret = fmbuf_pop(pbuf, pop_buf, 1); FCUNIT_ASSERT(1 == ret); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(0 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(0 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(10 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(10 == total_free); } // push 5 bytes and pop 1 bytes { int ret = fmbuf_push(pbuf, push_buf, 5); FCUNIT_ASSERT(0 == ret); ret = fmbuf_pop(pbuf, pop_buf, 1); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(4 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(1 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(5 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(6 == total_free); } // pop 3 bytes and left 1 byte { int ret = fmbuf_pop(pbuf, pop_buf, 3); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(1 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(4 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(5 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(9 == total_free); } // pop 2 bytes { int ret = fmbuf_pop(pbuf, pop_buf, 2); FCUNIT_ASSERT(1 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(1 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(4 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(5 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(9 == total_free); } // clear mbuf and seek tail < head { fmbuf_clear(pbuf); fmbuf_head_seek(pbuf, 4, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(pbuf, 2, FMBUF_SEEK_RIGHT); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(9 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(4 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(8 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(1 == total_free); } // total 9 bytes, pop 7 bytes { int ret = fmbuf_pop(pbuf, pop_buf, 7); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(2 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(0 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(8 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(8 == total_free); } // pop 2 bytes and then the mbuf is empty { int ret = fmbuf_pop(pbuf, pop_buf, 2); FCUNIT_ASSERT(0 == ret); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(0 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(2 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(8 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(10 == total_free); } { fmbuf_clear(pbuf); fmbuf_head_seek(pbuf, 4, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(pbuf, 6, FMBUF_SEEK_RIGHT); int ret = fmbuf_pop(pbuf, NULL, 4); FCUNIT_ASSERT(ret == 1); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(2 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(4 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(4 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(8 == total_free); } // move 2 bytes { fmbuf_pop(pbuf, NULL, 2); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(0 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(6 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(4 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(10 == total_free); } // tail < head, tail_use == 5, but pop 6 bytes { fmbuf_clear(pbuf); fmbuf_head_seek(pbuf, 6, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(pbuf, 4, FMBUF_SEEK_RIGHT); size_t used = fmbuf_used(pbuf); FCUNIT_ASSERT(9 == used); fmbuf_pop(pbuf, NULL, 6); size_t size = fmbuf_size(pbuf); FCUNIT_ASSERT(10 == size); used = fmbuf_used(pbuf); FCUNIT_ASSERT(3 == used); size_t head_free = fmbuf_head_free(pbuf); FCUNIT_ASSERT(1 == head_free); size_t tail_free = fmbuf_tail_free(pbuf); FCUNIT_ASSERT(6 == tail_free); size_t total_free = fmbuf_free(pbuf); FCUNIT_ASSERT(7 == total_free); } fmbuf_delete(pbuf); }
// mbuf as a ring-buffer (the tailer location < header location) void test_mbuf2() { // mbuf: size = 10b, used = 2b // realloc it with same size { fmbuf* mbuf = fmbuf_create(10); int ret = fmbuf_push(mbuf, "11", 2); FCUNIT_ASSERT(ret == 0); fmbuf* new_buf = fmbuf_realloc(mbuf, 10); FCUNIT_ASSERT(new_buf == mbuf); fmbuf_delete(mbuf); } // mbuf: size = 10b, used = 9b // realloc it with new size = 20b // note: left used <= right used and left used <= increased sz { fmbuf* mbuf = fmbuf_create(10); fmbuf_head_seek(mbuf, 4, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(mbuf, 2, FMBUF_SEEK_RIGHT); FCUNIT_ASSERT(fmbuf_used(mbuf) == 9); fmbuf* new_buf = fmbuf_realloc(mbuf, 20); FCUNIT_ASSERT(9 == fmbuf_used(new_buf)); FCUNIT_ASSERT(11 == fmbuf_free(new_buf)); FCUNIT_ASSERT(20 == fmbuf_size(new_buf)); FCUNIT_ASSERT(4 == fmbuf_head_free(new_buf)); FCUNIT_ASSERT(7 == fmbuf_tail_free(new_buf)); fmbuf_delete(new_buf); } // mbuf: size = 10b, used = 9b // realloc it with new size = 20b // note: left used > right used, left used <= increased sz { fmbuf* mbuf = fmbuf_create(10); fmbuf_head_seek(mbuf, 8, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(mbuf, 6, FMBUF_SEEK_RIGHT); FCUNIT_ASSERT(fmbuf_used(mbuf) == 9); fmbuf* new_buf = fmbuf_realloc(mbuf, 20); FCUNIT_ASSERT(9 == fmbuf_used(new_buf)); FCUNIT_ASSERT(11 == fmbuf_free(new_buf)); FCUNIT_ASSERT(20 == fmbuf_size(new_buf)); FCUNIT_ASSERT(18 == fmbuf_head_free(new_buf)); FCUNIT_ASSERT(14 == fmbuf_tail_free(new_buf)); fmbuf_delete(new_buf); } // mbuf: size = 10b, used = 9b // realloc it with new size = 11b // note: left used <= right used, left used > increased sz { fmbuf* mbuf = fmbuf_create(10); fmbuf_head_seek(mbuf, 4, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(mbuf, 2, FMBUF_SEEK_RIGHT); FCUNIT_ASSERT(fmbuf_used(mbuf) == 9); fmbuf* new_buf = fmbuf_realloc(mbuf, 11); FCUNIT_ASSERT(9 == fmbuf_used(new_buf)); FCUNIT_ASSERT(2 == fmbuf_free(new_buf)); FCUNIT_ASSERT(11 == fmbuf_size(new_buf)); FCUNIT_ASSERT(5 == fmbuf_head_free(new_buf)); FCUNIT_ASSERT(9 == fmbuf_tail_free(new_buf)); fmbuf_delete(new_buf); } // mbuf: size = 10b, used = 9b // realloc it with new size = 11b // note: left used > right used, left used > increased sz { fmbuf* mbuf = fmbuf_create(10); fmbuf_head_seek(mbuf, 8, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(mbuf, 6, FMBUF_SEEK_RIGHT); FCUNIT_ASSERT(fmbuf_used(mbuf) == 9); fmbuf* new_buf = fmbuf_realloc(mbuf, 11); FCUNIT_ASSERT(9 == fmbuf_used(new_buf)); FCUNIT_ASSERT(2 == fmbuf_free(new_buf)); FCUNIT_ASSERT(11 == fmbuf_size(new_buf)); FCUNIT_ASSERT(9 == fmbuf_head_free(new_buf)); FCUNIT_ASSERT(5 == fmbuf_tail_free(new_buf)); fmbuf_delete(new_buf); } // mbuf: size = 10b, used = 2b // realloc it with new size = 5b { fmbuf* mbuf = fmbuf_create(10); fmbuf_head_seek(mbuf, 10, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(mbuf, 1, FMBUF_SEEK_RIGHT); FCUNIT_ASSERT(fmbuf_used(mbuf) == 2); fmbuf* new_buf = fmbuf_realloc(mbuf, 5); FCUNIT_ASSERT(2 == fmbuf_used(new_buf)); FCUNIT_ASSERT(3 == fmbuf_free(new_buf)); FCUNIT_ASSERT(5 == fmbuf_size(new_buf)); FCUNIT_ASSERT(5 == fmbuf_head_free(new_buf)); FCUNIT_ASSERT(4 == fmbuf_tail_free(new_buf)); fmbuf_delete(new_buf); } // mbuf: size = 10b, used = 2b // realloc it with new size = 1b { fmbuf* mbuf = fmbuf_create(10); fmbuf_head_seek(mbuf, 10, FMBUF_SEEK_RIGHT); fmbuf_tail_seek(mbuf, 1, FMBUF_SEEK_RIGHT); FCUNIT_ASSERT(fmbuf_used(mbuf) == 2); fmbuf* new_buf = fmbuf_realloc(mbuf, 1); FCUNIT_ASSERT(2 == fmbuf_used(new_buf)); FCUNIT_ASSERT(0 == fmbuf_free(new_buf)); FCUNIT_ASSERT(2 == fmbuf_size(new_buf)); FCUNIT_ASSERT(2 == fmbuf_head_free(new_buf)); FCUNIT_ASSERT(1 == fmbuf_tail_free(new_buf)); fmbuf_delete(new_buf); } }