Changed log_manager to use block-siuze buffers instead of small write buffers. Added new test cases and added iterations. Added possibility to test with dummy disk write which sleeps constantly for 5ms instead of performing disk write.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -35,8 +35,10 @@ typedef struct thread_st {
|
||||
} thread_t;
|
||||
|
||||
static void* thr_run(void* data);
|
||||
static void* thr_run_morelog(void* data);
|
||||
|
||||
#define NTHR 16
|
||||
#define NTHR 256
|
||||
#define NITER 100
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
@ -98,7 +100,11 @@ int main(int argc, char* argv[])
|
||||
|
||||
mes = skygw_message_init();
|
||||
mtx = simple_mutex_init(NULL, strdup("testmtx"));
|
||||
/** Test starts */
|
||||
|
||||
fprintf(stderr, "\nStarting test #1 \n");
|
||||
|
||||
/** 1 */
|
||||
for (i=0; i<NTHR; i++) {
|
||||
thr[i] = (thread_t*)calloc(1, sizeof(thread_t));
|
||||
thr[i]->mes = mes;
|
||||
@ -134,14 +140,67 @@ int main(int argc, char* argv[])
|
||||
for (i=0; i<NTHR; i++) {
|
||||
free(thr[i]);
|
||||
}
|
||||
|
||||
fprintf(stderr, "\nStarting test #2 \n");
|
||||
|
||||
/** 2 */
|
||||
for (i=0; i<NTHR; i++) {
|
||||
thr[i] = (thread_t*)calloc(1, sizeof(thread_t));
|
||||
thr[i]->mes = mes;
|
||||
thr[i]->mtx = mtx;
|
||||
thr[i]->nactive = &nactive;
|
||||
}
|
||||
nactive = NTHR;
|
||||
|
||||
fprintf(stderr,
|
||||
"\nLaunching %d threads, each iterating %d times.",
|
||||
NTHR,
|
||||
NITER);
|
||||
|
||||
for (i=0; i<NTHR; i++) {
|
||||
pthread_t p;
|
||||
pthread_create(&p, NULL, thr_run_morelog, thr[i]);
|
||||
thr[i]->tid = p;
|
||||
}
|
||||
|
||||
fprintf(stderr, ".. done");
|
||||
|
||||
fprintf(stderr, "\nStarting to wait threads.\n");
|
||||
|
||||
do {
|
||||
skygw_message_wait(mes);
|
||||
simple_mutex_lock(mtx, TRUE);
|
||||
if (nactive > 0) {
|
||||
simple_mutex_unlock(mtx);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} while(TRUE);
|
||||
|
||||
for (i=0; i<NTHR; i++) {
|
||||
pthread_join(thr[i]->tid, NULL);
|
||||
}
|
||||
/** This is to release memory */
|
||||
skygw_logmanager_done(NULL);
|
||||
|
||||
simple_mutex_unlock(mtx);
|
||||
|
||||
fprintf(stderr, "\nFreeing thread memory.");
|
||||
|
||||
for (i=0; i<NTHR; i++) {
|
||||
free(thr[i]);
|
||||
}
|
||||
|
||||
/** Test ended here */
|
||||
skygw_message_done(mes);
|
||||
simple_mutex_done(mtx);
|
||||
|
||||
fprintf(stderr, ".. done.\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void* thr_run(
|
||||
static void* thr_run(
|
||||
void* data)
|
||||
{
|
||||
thread_t* td = (thread_t *)data;
|
||||
@ -218,3 +277,57 @@ void* thr_run(
|
||||
skygw_message_send(td->mes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int nstr(
|
||||
char** str_arr)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; str_arr[i] != NULL; i++) {
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
char* logs[] = {
|
||||
"foo",
|
||||
"bar",
|
||||
"done",
|
||||
"critical test logging",
|
||||
"longer test l o g g g i n g",
|
||||
"reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line",
|
||||
"shoorter one",
|
||||
"two",
|
||||
"scrap : 834nuft984pnw8ynup4598yp8wup8upwn48t5gpn45",
|
||||
"more the same : f98uft5p8ut2p44449upnt5",
|
||||
"asdasd987987asdasd987987asdasd987987asdasd987987asdasd987987asdasd987987asdasd987987asdasd98987",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void* thr_run_morelog(
|
||||
void* data)
|
||||
{
|
||||
thread_t* td = (thread_t *)data;
|
||||
char* logstr;
|
||||
int err;
|
||||
int i;
|
||||
int nmsg;
|
||||
|
||||
nmsg = nstr(logs);
|
||||
|
||||
for (i=0; i<NITER; i++) {
|
||||
char* str = logs[rand()%nmsg];
|
||||
err = skygw_log_write(NULL,
|
||||
(logfile_id_t)(rand()%(LOGFILE_LAST+1)),
|
||||
"%s - iteration # %d",
|
||||
str,
|
||||
i);
|
||||
}
|
||||
simple_mutex_lock(td->mtx, TRUE);
|
||||
*td->nactive -= 1;
|
||||
simple_mutex_unlock(td->mtx);
|
||||
skygw_message_send(td->mes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@
|
||||
# define ss_prof(exp)
|
||||
#endif /* SS_DEBUG || SS_PROF */
|
||||
|
||||
#if defined(SS_DEBUG)
|
||||
#if defined(EI_SS_DEBUG)
|
||||
# define ss_debug(exp) exp
|
||||
# define ss_dfprintf fprintf
|
||||
# define ss_dfflush fflush
|
||||
@ -113,7 +113,7 @@ typedef enum skygw_chk_t {
|
||||
CHK_NUM_FNAMES,
|
||||
CHK_NUM_LOGMANAGER,
|
||||
CHK_NUM_FILE,
|
||||
CHK_NUM_WRITEBUF
|
||||
CHK_NUM_BLOCKBUF
|
||||
} skygw_chk_t;
|
||||
|
||||
# define STRBOOL(b) ((b) ? "TRUE" : "FALSE")
|
||||
@ -248,16 +248,12 @@ typedef enum skygw_chk_t {
|
||||
ss_info_dassert(lf->lf_id >= LOGFILE_FIRST && \
|
||||
lf->lf_id <= LOGFILE_LAST, \
|
||||
"Invalid logfile id\n"); \
|
||||
ss_info_dassert(lf->lf_writebuf_size > 0, \
|
||||
"Error, logfile's writebuf size is zero " \
|
||||
"or negative\n"); \
|
||||
(lf->lf_chk_top != CHK_NUM_LOGFILE || \
|
||||
lf->lf_chk_tail != CHK_NUM_LOGFILE ? \
|
||||
FALSE : \
|
||||
(lf->lf_logpath == NULL || \
|
||||
lf->lf_name_prefix == NULL || \
|
||||
lf->lf_name_suffix == NULL || \
|
||||
lf->lf_writebuf_size == 0 || \
|
||||
lf->lf_full_name == NULL ? FALSE : TRUE)); \
|
||||
}
|
||||
|
||||
@ -317,9 +313,10 @@ typedef enum skygw_chk_t {
|
||||
"File struct under- or overflow"); \
|
||||
}
|
||||
|
||||
#define CHK_WRITEBUF(w) { \
|
||||
ss_info_dassert(w->wb_chk_top == CHK_NUM_WRITEBUF, \
|
||||
"Writebuf under- or overflow"); \
|
||||
|
||||
#define CHK_BLOCKBUF(bb) { \
|
||||
ss_info_dassert(bb->bb_chk_top == CHK_NUM_BLOCKBUF, \
|
||||
"Block buf under- or overflow"); \
|
||||
}
|
||||
|
||||
#endif /* SKYGW_DEBUG_H */
|
||||
|
||||
@ -276,7 +276,8 @@ mlist_t* mlist_init(
|
||||
mlist_t* listp,
|
||||
mlist_cursor_t** cursor,
|
||||
char* name,
|
||||
void (*datadel)(void*))
|
||||
void (*datadel)(void*),
|
||||
int maxnodes)
|
||||
{
|
||||
mlist_cursor_t* c;
|
||||
mlist_t* list;
|
||||
@ -301,6 +302,8 @@ mlist_t* mlist_init(
|
||||
}
|
||||
list->mlist_chk_top = CHK_NUM_MLIST;
|
||||
list->mlist_chk_tail = CHK_NUM_MLIST;
|
||||
/** Set size limit for list. 0 means unlimited */
|
||||
list->mlist_nodecount_max = maxnodes;
|
||||
/** Set data deletion callback fun */
|
||||
list->mlist_datadel = datadel;
|
||||
if (name != NULL) {
|
||||
@ -462,11 +465,31 @@ void* mlist_cursor_get_data_nomutex(
|
||||
return (mc->mlcursor_pos->mlnode_data);
|
||||
}
|
||||
|
||||
void mlist_add_data_nomutex(
|
||||
/**
|
||||
* @node Adds data to list by allocating node for it. Checks list size limit.
|
||||
*
|
||||
* Parameters:
|
||||
* @param list - <usage>
|
||||
* <description>
|
||||
*
|
||||
* @param data - <usage>
|
||||
* <description>
|
||||
*
|
||||
* @return TRUE, if succeed, FALSE, if list had node limit and it is full.
|
||||
*
|
||||
*
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
bool mlist_add_data_nomutex(
|
||||
mlist_t* list,
|
||||
void* data)
|
||||
{
|
||||
mlist_add_node_nomutex(list, mlist_node_init(data, NULL));
|
||||
bool succp;
|
||||
|
||||
succp = mlist_add_node_nomutex(list, mlist_node_init(data, NULL));
|
||||
|
||||
return succp;
|
||||
}
|
||||
|
||||
|
||||
@ -512,7 +535,7 @@ mlist_node_t* mlist_detach_first(
|
||||
}
|
||||
|
||||
/**
|
||||
* @node Add new node to end of list
|
||||
* @node Add new node to end of list if there is space for it.
|
||||
*
|
||||
* Parameters:
|
||||
* @param list - <usage>
|
||||
@ -524,21 +547,26 @@ mlist_node_t* mlist_detach_first(
|
||||
* @param add_last - <usage>
|
||||
* <description>
|
||||
*
|
||||
* @return void
|
||||
* @return TRUE, if succeede, FALSE, if list size limit was exceeded.
|
||||
*
|
||||
*
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
void mlist_add_node_nomutex(
|
||||
bool mlist_add_node_nomutex(
|
||||
mlist_t* list,
|
||||
mlist_node_t* newnode)
|
||||
{
|
||||
bool succp = FALSE;
|
||||
|
||||
CHK_MLIST(list);
|
||||
CHK_MLIST_NODE(newnode);
|
||||
ss_dassert(!list->mlist_deleted);
|
||||
|
||||
/** List is full already. */
|
||||
if (list->mlist_nodecount == list->mlist_nodecount_max) {
|
||||
goto return_succp;
|
||||
}
|
||||
/** Find location for new node */
|
||||
if (list->mlist_last != NULL) {
|
||||
ss_dassert(!list->mlist_last->mlnode_deleted);
|
||||
@ -552,7 +580,10 @@ void mlist_add_node_nomutex(
|
||||
list->mlist_last = newnode;
|
||||
newnode->mlnode_list = list;
|
||||
list->mlist_nodecount += 1;
|
||||
succp = TRUE;
|
||||
return_succp:
|
||||
CHK_MLIST(list);
|
||||
return succp;
|
||||
}
|
||||
|
||||
|
||||
@ -1102,14 +1133,13 @@ bool skygw_thread_must_exit(
|
||||
void acquire_lock(
|
||||
int* l)
|
||||
{
|
||||
register short int misscount = 0;
|
||||
register int misscount = 0;
|
||||
|
||||
while (atomic_add(l, 1) != 0) {
|
||||
atomic_add(l, -1);
|
||||
misscount += 1;
|
||||
if (misscount > 10) {
|
||||
usleep(rand()%100);
|
||||
misscount = 0;
|
||||
usleep(rand()%misscount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1188,30 +1218,37 @@ return_sm:
|
||||
int simple_mutex_done(
|
||||
simple_mutex_t* sm)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
|
||||
CHK_SIMPLE_MUTEX(sm);
|
||||
|
||||
if (atomic_add(&sm->sm_enabled, -1) != 1) {
|
||||
atomic_add(&sm->sm_enabled, 1);
|
||||
}
|
||||
#if 0
|
||||
assert(!pthread_mutex_trylock(&sm->sm_mutex));
|
||||
assert(!pthread_mutex_unlock(&sm->sm_mutex));
|
||||
assert((err = pthread_mutex_destroy(&sm->sm_mutex)) == 0);
|
||||
#else
|
||||
err = pthread_mutex_destroy(&sm->sm_mutex);
|
||||
|
||||
#endif
|
||||
#if 0
|
||||
if (err != 0) {
|
||||
goto return_err;
|
||||
}
|
||||
#endif
|
||||
simple_mutex_free_memory(sm);
|
||||
|
||||
|
||||
return_err:
|
||||
if (err != 0) {
|
||||
perror("simple_mutex : ");
|
||||
fprintf(stderr,
|
||||
"FATAL : destroying simple mutex %s failed, "
|
||||
"errno %d : %s\n",
|
||||
sm->sm_name,
|
||||
err,
|
||||
strerror(errno));
|
||||
perror("simple_mutex : ");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
@ -1492,7 +1529,9 @@ static bool file_write_header(
|
||||
}
|
||||
len1 = strlen(header_buf1);
|
||||
len2 = strlen(header_buf2);
|
||||
|
||||
#if defined(LAPTOP_TEST)
|
||||
usleep(DISKWRITE_LATENCY);
|
||||
#else
|
||||
wbytes1=fwrite((void*)header_buf1, len1, 1, file->sf_file);
|
||||
wbytes2=fwrite((void*)header_buf2, len2, 1, file->sf_file);
|
||||
|
||||
@ -1505,7 +1544,7 @@ static bool file_write_header(
|
||||
perror("Logfile header write.\n");
|
||||
goto return_succp;
|
||||
}
|
||||
|
||||
#endif
|
||||
CHK_FILE(file);
|
||||
|
||||
succp = TRUE;
|
||||
@ -1521,20 +1560,37 @@ bool skygw_file_write(
|
||||
void* data,
|
||||
size_t nbytes)
|
||||
{
|
||||
size_t nwritten;
|
||||
bool succp = FALSE;
|
||||
#if !defined(LAPTOP_TEST)
|
||||
size_t nwritten;
|
||||
int fd;
|
||||
static int writecount;
|
||||
#endif
|
||||
|
||||
CHK_FILE(file);
|
||||
#if (LAPTOP_TEST)
|
||||
usleep(DISKWRITE_LATENCY);
|
||||
#else
|
||||
nwritten = fwrite(data, nbytes, 1, file->sf_file);
|
||||
|
||||
if (nwritten != 1) {
|
||||
perror("Logfile write.\n");
|
||||
fprintf(stderr,
|
||||
"Writing header %s to %s failed.\n",
|
||||
"Writing %ld bytes, %s to %s failed.\n",
|
||||
nbytes,
|
||||
(char *)data,
|
||||
file->sf_fname);
|
||||
perror("Logfile write.\n");
|
||||
goto return_succp;
|
||||
}
|
||||
|
||||
writecount += 1;
|
||||
|
||||
if (writecount == FSYNCLIMIT) {
|
||||
fd = fileno(file->sf_file);
|
||||
fsync(fd);
|
||||
writecount = 0;
|
||||
}
|
||||
#endif
|
||||
succp = TRUE;
|
||||
CHK_FILE(file);
|
||||
return_succp:
|
||||
@ -1565,7 +1621,16 @@ skygw_file_t* skygw_file_init(
|
||||
file = NULL;
|
||||
goto return_file;
|
||||
}
|
||||
file_write_header(file);
|
||||
|
||||
if (!file_write_header(file)) {
|
||||
fprintf(stderr,
|
||||
"Writing header of log file %s failed.\n",
|
||||
file->sf_fname);
|
||||
perror("SkyGW file open\n");
|
||||
free(file);
|
||||
file = NULL;
|
||||
goto return_file;
|
||||
}
|
||||
CHK_FILE(file);
|
||||
ss_dfprintf(stderr, "Opened %s\n", file->sf_fname);
|
||||
return_file:
|
||||
|
||||
@ -4,10 +4,13 @@
|
||||
#define MLIST
|
||||
#define MIN(a,b) (a<b ? a : b)
|
||||
#define MAX(a,b) (a>b ? a : b)
|
||||
#define FSYNCLIMIT 10
|
||||
|
||||
#include "skygw_types.h"
|
||||
#include "skygw_debug.h"
|
||||
|
||||
#define DISKWRITE_LATENCY (5*MSEC_USEC)
|
||||
|
||||
typedef struct slist_node_st slist_node_t;
|
||||
typedef struct slist_st slist_t;
|
||||
typedef struct slist_cursor_st slist_cursor_t;
|
||||
@ -38,13 +41,16 @@ typedef struct skygw_rwlock_st {
|
||||
typedef struct mlist_st {
|
||||
skygw_chk_t mlist_chk_top;
|
||||
char* mlist_name;
|
||||
void (*mlist_datadel)(void *);
|
||||
/** CREW concurrency, protects node updates and clean-up */
|
||||
simple_mutex_t mlist_mutex;
|
||||
void (*mlist_datadel)(void *); /**< clean-up function for data */
|
||||
simple_mutex_t mlist_mutex; /**< protect node updates and clean-up */
|
||||
bool mlist_uselock;
|
||||
bool mlist_islocked;
|
||||
bool mlist_deleted;
|
||||
size_t mlist_nodecount;
|
||||
size_t mlist_nodecount_max; /**< size limit. 0 == no limit */
|
||||
#if 1
|
||||
size_t mlist_versno;
|
||||
#endif
|
||||
bool mlist_flat;
|
||||
mlist_node_t* mlist_first;
|
||||
mlist_node_t* mlist_last;
|
||||
@ -87,10 +93,12 @@ EXTERN_C_BLOCK_END
|
||||
mlist_t* mlist_init(mlist_t* mlist,
|
||||
mlist_cursor_t** cursor,
|
||||
char* name,
|
||||
void (*datadel)(void*));
|
||||
void (*datadel)(void*),
|
||||
int maxnodes);
|
||||
|
||||
void mlist_done(mlist_t* list);
|
||||
void mlist_add_data_nomutex(mlist_t* list, void* data);
|
||||
void mlist_add_node_nomutex(mlist_t* list, mlist_node_t* newnode);
|
||||
bool mlist_add_data_nomutex(mlist_t* list, void* data);
|
||||
bool mlist_add_node_nomutex(mlist_t* list, mlist_node_t* newnode);
|
||||
void* mlist_node_get_data(mlist_node_t* node);
|
||||
mlist_node_t* mlist_detach_nodes(mlist_t* ml);
|
||||
mlist_node_t* mlist_detach_first(mlist_t* ml);
|
||||
|
||||
Reference in New Issue
Block a user