First version of log_writer and test. Includes objects : logfile, filewriter. Routines : skygw_message_t, simple_mutex.
Actual file handling is missing and some clean-up routines as well. Compiles and runs but doesn't do much.
This commit is contained in:
parent
a9e6e14e5d
commit
c5889b606a
417
log_writer/log_writer.cc
Normal file
417
log_writer/log_writer.cc
Normal file
@ -0,0 +1,417 @@
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <skygw_debug.h>
|
||||
#include <skygw_types.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_writer.h>
|
||||
|
||||
#define log_fname_prefix "skygw_log"
|
||||
#define log_fname_tail ".out"
|
||||
|
||||
const int nfiles = 10;
|
||||
const size_t log_file_size = (64*MB);
|
||||
|
||||
|
||||
/** Writer thread structure */
|
||||
struct filewriter_st {
|
||||
skygw_chk_t fwr_chk_top;
|
||||
slist_cursor_t* fwr_logfile_cursor;
|
||||
skygw_message_t* fwr_logmes;
|
||||
skygw_message_t* fwr_clientmes;
|
||||
simple_mutex_t* fwr_logfile_mutex;
|
||||
pthread_t fwr_tid;
|
||||
skygw_thread_t* fwr_thread;
|
||||
skygw_chk_t fwr_chk_tail;
|
||||
};
|
||||
|
||||
struct logfile_st {
|
||||
skygw_chk_t lf_chk_top;
|
||||
logfile_id_t lf_id;
|
||||
char* lf_directory;
|
||||
char* lf_name_prefix;
|
||||
char* lf_name_tail;
|
||||
int lf_nfiles_max;
|
||||
size_t lf_file_size;
|
||||
/** This must be protected */
|
||||
slist_cursor_t* lf_writebuf_cursor;
|
||||
slist_cursor_t* lf_files_cursor;
|
||||
int lf_npending_writes;
|
||||
skygw_chk_t lf_chk_tail;
|
||||
};
|
||||
|
||||
|
||||
static bool logfile_write_ex(
|
||||
logfile_t* logfile,
|
||||
char* logstr,
|
||||
bool force_flush);
|
||||
|
||||
|
||||
static logfile_t* logfile_init_nomutex(logfile_id_t logfile_id);
|
||||
|
||||
static char* get_logfile_directory(
|
||||
logfile_id_t logfile_id);
|
||||
|
||||
static char* get_logfile_name_prefix(
|
||||
logfile_id_t logfile_id);
|
||||
|
||||
static char* get_logfile_name_tail(
|
||||
logfile_id_t logfile_id);
|
||||
|
||||
static int get_logfile_nfiles(
|
||||
logfile_id_t logfile_id);
|
||||
|
||||
static size_t get_logfile_file_size(
|
||||
logfile_id_t logfile_id);
|
||||
|
||||
static filewriter_t* filewriter_init(void);
|
||||
|
||||
static void* thr_filewriter_fun(void* data);
|
||||
|
||||
static skygw_message_t* filewriter_get_logmes(filewriter_t* filewriter);
|
||||
|
||||
static skygw_message_t* filewriter_get_clientmes(filewriter_t* filewriter);
|
||||
|
||||
bool logfile_write(
|
||||
logfile_t* logfile,
|
||||
char* logstr)
|
||||
{
|
||||
CHK_LOGFILE(logfile);
|
||||
return logfile_write_ex(logfile, logstr, FALSE);
|
||||
}
|
||||
|
||||
bool logfile_write_flush(
|
||||
logfile_t* logfile,
|
||||
char* logstr)
|
||||
{
|
||||
CHK_LOGFILE(logfile);
|
||||
return logfile_write_ex(logfile, logstr, TRUE);
|
||||
}
|
||||
|
||||
|
||||
static bool logfile_write_ex(
|
||||
logfile_t* logfile,
|
||||
char* logstr,
|
||||
bool force_flush)
|
||||
{
|
||||
bool succp;
|
||||
CHK_LOGFILE(logfile);
|
||||
#if 0
|
||||
/** Attempt to get buffer for log writing */
|
||||
lf_buf = logfile_get_buffer(logfile);
|
||||
ss_dassert(lf_buf != NULL);
|
||||
/**
|
||||
* Add string to buffer.
|
||||
* Is it possible for this to fail ? */
|
||||
succp = logfile_write_to_buf(lf_buf, logstr);
|
||||
|
||||
if (force_flush) {
|
||||
/** Send flush message to filewriter */
|
||||
logfile_force_flush(logfile);
|
||||
}
|
||||
#else
|
||||
succp = TRUE;
|
||||
#endif
|
||||
return succp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @node Create logfile of a specified type for log writing.
|
||||
*
|
||||
* Parameters:
|
||||
* @param logfile_id - in, use
|
||||
* Specifies the type of logfile. Types are listed in
|
||||
* filewriter.h
|
||||
*
|
||||
* @return pointer to logfile object.
|
||||
*
|
||||
*
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
logfile_t* logfile_init(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
filewriter_t* filewriter;
|
||||
logfile_t* logfile;
|
||||
|
||||
/** If filewriter doesn't exists, this triggers its creation */
|
||||
filewriter = get_or_create_filewriter(logfile_id);
|
||||
CHK_FILEWRITER(filewriter);
|
||||
/**
|
||||
Pitäisikö ensin luoda uusi logfile ja lisätä se sitten
|
||||
filewriterin listalle?
|
||||
Selkeämpi?
|
||||
*/
|
||||
filewriter_enter_logfilemutex(filewriter);
|
||||
|
||||
/** Protected attempt to get logfile if it exists already */
|
||||
logfile = filewriter_get_logfile(logfile_id);
|
||||
|
||||
if (logfile == NULL) {
|
||||
logfile = logfile_init_nomutex(logfile_id);
|
||||
}
|
||||
CHK_LOGFILE(logfile);
|
||||
filewriter_exit_logfilemutex(filewriter);
|
||||
|
||||
return logfile;
|
||||
}
|
||||
|
||||
static logfile_t* logfile_init_nomutex(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
logfile_t* logfile;
|
||||
|
||||
logfile = (logfile_t *)malloc(sizeof(logfile_t));
|
||||
|
||||
if (logfile == NULL) {
|
||||
goto return_with_logfile;
|
||||
}
|
||||
|
||||
logfile->lf_chk_top = CHK_NUM_LOGFILE;
|
||||
logfile->lf_chk_tail = CHK_NUM_LOGFILE;
|
||||
logfile->lf_id = logfile_id;
|
||||
logfile->lf_directory = get_logfile_directory(logfile_id);
|
||||
logfile->lf_name_prefix = get_logfile_name_prefix(logfile_id);
|
||||
logfile->lf_name_tail = get_logfile_name_tail(logfile_id);
|
||||
logfile->lf_nfiles_max = get_logfile_nfiles(logfile_id);
|
||||
logfile->lf_file_size = get_logfile_file_size(logfile_id);
|
||||
/** filewriter reads and removes frop top, clients add to tail */
|
||||
logfile->lf_writebuf_cursor = slist_init();
|
||||
/** only filewriter reads or modifies */
|
||||
logfile->lf_files_cursor = slist_init();
|
||||
logfile->lf_npending_writes = 0;
|
||||
|
||||
return_with_logfile:
|
||||
return logfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* @node Filewriter is an object which is managed by file writer thread.
|
||||
* A filewriter is returned or - if it doesn't exist - created prior return.
|
||||
*
|
||||
* Parameters:
|
||||
* @param logfile_id - in, use
|
||||
* Logfile id is used only if there are multiple file writer threads.
|
||||
* NOTE that logfile creation is not triggered in this function.
|
||||
*
|
||||
*
|
||||
* @param WRITER - <usage>
|
||||
* <description>
|
||||
*
|
||||
* @return pointer to filewriter which is initialized only and so it has no
|
||||
* logfile set at this phase.
|
||||
*
|
||||
*
|
||||
* @details (write detailed description here)
|
||||
*
|
||||
*/
|
||||
filewriter_t* get_or_create_filewriter(
|
||||
logfile_id_t logfile_id /** NOT USED WITH 1 WRITER */)
|
||||
{
|
||||
/** global filewriter pointer */
|
||||
static filewriter_t* filewriter;
|
||||
static int a;
|
||||
static int b;
|
||||
static bool file_writer_initialized = FALSE;
|
||||
int my_a = 0;
|
||||
int wait_usec;
|
||||
bool just_wait = FALSE;
|
||||
|
||||
while (filewriter == NULL) {
|
||||
/** Someone else came before you, wait until filewriter has value */
|
||||
if (just_wait) {
|
||||
wait_usec = (rand()%10);
|
||||
usleep(wait_usec);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (my_a == a) {
|
||||
/** No-one has came since you read a last time, go on */
|
||||
|
||||
if (a == b) {
|
||||
a += 1;
|
||||
my_a += 1;
|
||||
} else {
|
||||
/** Someone's still in loop, wait until loop is empty */
|
||||
wait_usec = (rand()%10);
|
||||
usleep(wait_usec);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
just_wait = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (my_a != a) {
|
||||
/** Someone updated a after you. Inc. b and retry. */
|
||||
my_a = a;
|
||||
b += 1;
|
||||
wait_usec = (rand()%100);
|
||||
usleep(wait_usec);
|
||||
continue;
|
||||
}
|
||||
|
||||
/** Only one get this far. It is safe to initialize filewriter */
|
||||
ss_info_dassert(file_writer_initialized == FALSE,
|
||||
"File writer is already initialized. "
|
||||
"Concurrency problem\n");
|
||||
file_writer_initialized = TRUE;
|
||||
/**
|
||||
* Create filewriter struct and thread to run with it.
|
||||
* Wait until thread sends ack.
|
||||
*/
|
||||
filewriter = filewriter_init();
|
||||
skygw_message_wait(filewriter->fwr_clientmes);
|
||||
}
|
||||
CHK_FILEWRITER(filewriter);
|
||||
ss_info_dassert(skygw_thread_get_state(filewriter->fwr_thread) ==
|
||||
THR_RUNNING,
|
||||
"File writer thread is not running but filewriter "
|
||||
"is being returned.");
|
||||
return filewriter;
|
||||
}
|
||||
|
||||
|
||||
static filewriter_t* filewriter_init(void)
|
||||
{
|
||||
filewriter_t* filewriter;
|
||||
|
||||
filewriter = (filewriter_t *)malloc(sizeof(filewriter_t));
|
||||
filewriter->fwr_chk_top = CHK_NUM_FILEWRITER;
|
||||
filewriter->fwr_chk_tail = CHK_NUM_FILEWRITER;
|
||||
filewriter->fwr_logfile_cursor = slist_init();
|
||||
filewriter->fwr_logmes = skygw_message_init();
|
||||
filewriter->fwr_clientmes = skygw_message_init();
|
||||
filewriter->fwr_logfile_mutex = simple_mutex_init("logfile");
|
||||
filewriter->fwr_thread =
|
||||
skygw_thread_init("File writer thr",
|
||||
thr_filewriter_fun,
|
||||
(void *)filewriter);
|
||||
skygw_thread_start(filewriter->fwr_thread);
|
||||
return filewriter;
|
||||
}
|
||||
|
||||
void filewriter_enter_logfilemutex(
|
||||
filewriter_t* fwr)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
|
||||
for (i=0; i<100; i++) {
|
||||
err = simple_mutex_lock(fwr->fwr_logfile_mutex, FALSE);
|
||||
|
||||
if (err == 0) {
|
||||
break;
|
||||
}
|
||||
usleep(200);
|
||||
}
|
||||
ss_info_dassert(err == 0, "Can't enter logfilemutex");
|
||||
}
|
||||
|
||||
void filewriter_exit_logfilemutex(
|
||||
filewriter_t* fwr)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = simple_mutex_unlock(fwr->fwr_logfile_mutex);
|
||||
ss_info_dassert(err == 0, "Can't exit logfilemutex");
|
||||
}
|
||||
|
||||
|
||||
static skygw_message_t* filewriter_get_logmes(
|
||||
filewriter_t* filewriter)
|
||||
{
|
||||
CHK_FILEWRITER(filewriter);
|
||||
|
||||
return filewriter->fwr_logmes;
|
||||
}
|
||||
|
||||
static skygw_message_t* filewriter_get_clientmes(
|
||||
filewriter_t* filewriter)
|
||||
{
|
||||
CHK_FILEWRITER(filewriter);
|
||||
|
||||
return filewriter->fwr_clientmes;
|
||||
}
|
||||
|
||||
static void* thr_filewriter_fun(
|
||||
void* data)
|
||||
{
|
||||
skygw_thread_t* thr;
|
||||
filewriter_t* fwr;
|
||||
|
||||
thr = (skygw_thread_t *)data;
|
||||
fwr = (filewriter_t *)skygw_thread_get_data(thr);
|
||||
|
||||
skygw_thread_set_state(thr, THR_RUNNING);
|
||||
skygw_message_send(fwr->fwr_clientmes);
|
||||
|
||||
while(!skygw_thread_must_exit(thr)) {
|
||||
skygw_message_wait(fwr->fwr_logmes);
|
||||
/** Read files whose prefix and tail match with those specified in
|
||||
* logfiles and insert names
|
||||
*/
|
||||
/** Do what is needed and inform client then */
|
||||
/** Go wait messages from client it timely alarm */
|
||||
}
|
||||
skygw_thread_set_state(thr, THR_EXIT);
|
||||
skygw_message_send(fwr->fwr_clientmes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
logfile_t* filewriter_get_logfile(
|
||||
logfile_id_t id)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool filewriter_writebuf(
|
||||
filewriter_t* fw,
|
||||
void* buf)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static char* get_logfile_directory(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
return "/tmp/";
|
||||
}
|
||||
|
||||
static char* get_logfile_name_prefix(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
return "skygw";
|
||||
}
|
||||
|
||||
static char* get_logfile_name_tail(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
return ".msg";
|
||||
}
|
||||
|
||||
static int get_logfile_nfiles(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
static size_t get_logfile_file_size(
|
||||
logfile_id_t logfile_id)
|
||||
{
|
||||
return 3*KB;
|
||||
}
|
||||
|
||||
void logfile_done(
|
||||
logfile_id_t id)
|
||||
{
|
||||
fprintf(stderr, "logfile_done\n");
|
||||
}
|
||||
|
||||
bool logfile_flush(
|
||||
logfile_t* logfile)
|
||||
{
|
||||
fprintf(stderr, "logfile_flush\n");
|
||||
}
|
41
log_writer/log_writer.h
Normal file
41
log_writer/log_writer.h
Normal file
@ -0,0 +1,41 @@
|
||||
typedef struct filewriter_st filewriter_t;
|
||||
|
||||
EXTERN_C_BLOCK_BEGIN
|
||||
|
||||
typedef enum {
|
||||
LOGFILE_TRACE = 0,
|
||||
LOGFILE_MESSAGE,
|
||||
LOGFILE_ERROR
|
||||
} logfile_id_t;
|
||||
|
||||
typedef struct logfile_st logfile_t;
|
||||
|
||||
bool logfile_write(
|
||||
logfile_t* logfile,
|
||||
char* logstr);
|
||||
|
||||
bool logfile_write_flush(
|
||||
logfile_t* logfile,
|
||||
char* logstr);
|
||||
|
||||
bool logfile_flush(
|
||||
logfile_t* logfile);
|
||||
|
||||
logfile_t* logfile_init(
|
||||
logfile_id_t logfile_id);
|
||||
|
||||
void logfile_done(
|
||||
logfile_id_t id);
|
||||
|
||||
EXTERN_C_BLOCK_END
|
||||
|
||||
filewriter_t* get_or_create_filewriter(
|
||||
logfile_id_t logfile_id /** NOT USED WITH 1 WRITER */);
|
||||
|
||||
void filewriter_enter_logfilemutex(
|
||||
filewriter_t* fwr);
|
||||
|
||||
logfile_t* filewriter_get_logfile(logfile_id_t id);
|
||||
|
||||
void filewriter_exit_logfilemutex(filewriter_t* fwr);
|
||||
|
38
log_writer/makefile
Normal file
38
log_writer/makefile
Normal file
@ -0,0 +1,38 @@
|
||||
include ../build_gateway.inc
|
||||
include ../makefile.inc
|
||||
|
||||
CC = gcc
|
||||
CPP = g++
|
||||
|
||||
LOG_WRITER_PATH := $(shell pwd)
|
||||
|
||||
makeall: clean all
|
||||
|
||||
clean:
|
||||
make -C ../utils clean
|
||||
- $(DEL) *.o
|
||||
- $(DEL) *.so
|
||||
- $(DEL) *.so.1.0.1
|
||||
- $(DEL) *~
|
||||
|
||||
all: utils lib
|
||||
|
||||
utils:
|
||||
make -C $(ROOT_PATH)/utils clean all
|
||||
$(COPY) $(ROOT_PATH)/utils/skygw_utils.o ./
|
||||
|
||||
lib: libcomp liblink
|
||||
|
||||
libcomp:
|
||||
$(CPP) -c $(CFLAGS) \
|
||||
-I$(MARIADB_SRC_PATH)/include/ \
|
||||
-I../utils/ -I./ \
|
||||
-fPIC ./log_writer.cc -o log_writer.o
|
||||
|
||||
liblink:
|
||||
$(CPP) -shared \
|
||||
-Wl,-soname,liblog_writer.so \
|
||||
-o liblog_writer.so.1.0.1 log_writer.o \
|
||||
$(LDLIBS) $(CPP_LDLIBS)
|
||||
$(DEL) ./liblog_writer.so
|
||||
$(LINK) ./liblog_writer.so.1.0.1 ./liblog_writer.so
|
34
log_writer/test/makefile
Normal file
34
log_writer/test/makefile
Normal file
@ -0,0 +1,34 @@
|
||||
include ../../build_gateway.inc
|
||||
include ../../makefile.inc
|
||||
|
||||
CC = gcc
|
||||
CPP = g++
|
||||
|
||||
TESTPATH := $(shell pwd)
|
||||
LOG_WRITER_PATH := $(ROOT_PATH)/log_writer
|
||||
TESTAPP = $(TESTPATH)/testlog
|
||||
|
||||
runtest: makeall testall
|
||||
|
||||
makeall: clean all
|
||||
|
||||
clean:
|
||||
- $(DEL) *.o
|
||||
- $(DEL) testlog
|
||||
- $(DEL) *~
|
||||
|
||||
all: testcomp testall
|
||||
|
||||
testcomp:
|
||||
$(CC) $(CFLAGS) \
|
||||
-L$(LOG_WRITER_PATH) \
|
||||
-Wl,-rpath,$(LOG_WRITER_PATH)/ \
|
||||
-o testlog -DSS_DEBUG \
|
||||
-I$(SOLIDDB_SRC_PATH)/include \
|
||||
-I$(MARIADB_SRC_PATH)/include \
|
||||
-I$(LOG_WRITER_PATH) -I$(ROOT_PATH)/utils testlog.c \
|
||||
-llog_writer $(LDLIBS) \
|
||||
$(LOG_WRITER_PATH)/skygw_utils.o
|
||||
|
||||
testall:
|
||||
- $(LAUNCH_DEBUGGER) $(TESTAPP) $(BACKGR)
|
17
log_writer/test/testlog.c
Normal file
17
log_writer/test/testlog.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_writer.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
logfile_t* tracelog = logfile_init(LOGFILE_TRACE);
|
||||
logfile_t* messagelog = logfile_init(LOGFILE_MESSAGE);
|
||||
|
||||
logfile_write(tracelog, "My name is trace");
|
||||
logfile_write_flush(messagelog, "I'm the message!");
|
||||
logfile_flush(tracelog);
|
||||
|
||||
logfile_done(LOGFILE_TRACE);
|
||||
logfile_done(LOGFILE_MESSAGE);
|
||||
return 0;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user