I've submitted the IO_CACHE version for your review. Below are the relievant answers. > > +int logger_sync(LOGGER_HANDLE *log) > Why did you introduce an explicit sync API? I added it mostly for the testing. If the log is in the buffer, i'm not sure how to add it to the result file. The customer usage is also possible - if the administrator wants to take a look the most recent log records and nobody works with the server.
> this could be an API call in the logger. Like "reinit(new params)" > and it'll close, change params, open - all under a log mutex, which doesn't > need to be destroyed and reinitialized. Probably. But for now i like the two calls better. Best regards. HF On Sat, Mar 8, 2025 at 9:26 PM Sergei Golubchik <s...@mariadb.org> wrote: > Hi, Alexey, > > See few comments below. > > But the main question, could you have used FILE or IO_CACHE instead of a > custom implementation? > > On Mar 08, Alexey Botchkov wrote: > > revision-id: b7dbe187b1a (mariadb-11.8.1-8-gb7dbe187b1a) > > parent(s): 6f1161aa34c > > author: Alexey Botchkov > > committer: Alexey Botchkov > > timestamp: 2025-03-02 16:27:23 +0400 > > message: > > > > MDEV-34680 Asynchronous and Buffered Logging for Audit Plugin. > > > > Buffering added to the file logger. > > Two buffers are created so writing to the file doesn't > > block other threads from logging. > > Operations isolated with two mutexes. > > > diff --git a/include/mysql/service_logger.h > b/include/mysql/service_logger.h > > index 35c2eb1e3a9..adce7bc9038 100644 > > --- a/include/mysql/service_logger.h > > +++ b/include/mysql/service_logger.h > > @@ -64,41 +64,44 @@ extern struct logger_service_st { > > void (*logger_init_mutexes)(); > > LOGGER_HANDLE* (*open)(const char *path, > > unsigned long long size_limit, > > - unsigned int rotations); > > + unsigned int rotations, size_t buffer_size); > > incompatible API change. MUST change the major service version. > > > int (*close)(LOGGER_HANDLE *log); > > int (*vprintf)(LOGGER_HANDLE *log, const char *fmt, va_list argptr) > > ATTRIBUTE_FORMAT_FPTR(printf, 2, 0); > > int (*printf)(LOGGER_HANDLE *log, const char *fmt, ...) > > ATTRIBUTE_FORMAT_FPTR(printf, 2, 3); > > - int (*write)(LOGGER_HANDLE *log, const char *buffer, size_t size); > > + int (*write)(LOGGER_HANDLE *log, const void *data, size_t size); > > int (*rotate)(LOGGER_HANDLE *log); > > + int (*sync)(LOGGER_HANDLE *log); > > } *logger_service; > > > > #ifdef MYSQL_DYNAMIC_PLUGIN > > > > #define logger_init_mutexes logger_service->logger_init_mutexes > > -#define logger_open(path, size_limit, rotations) \ > > - (logger_service->open(path, size_limit, rotations)) > > +#define logger_open(path, size_limit, rotations, buffer_size) \ > > + (logger_service->open(path, size_limit, rotations, buffer_size)) > > #define logger_close(log) (logger_service->close(log)) > > #define logger_rotate(log) (logger_service->rotate(log)) > > +#define logger_rsync(log) (logger_service->sync(log)) > > #define logger_vprintf(log, fmt, argptr) (logger_service->\ > > vprintf(log, fmt, argptr)) > > #define logger_printf (*logger_service->printf) > > -#define logger_write(log, buffer, size) \ > > - (logger_service->write(log, buffer, size)) > > +#define logger_write(log, data, size) \ > > + (logger_service->write(log, data, size)) > > #else > > > > void logger_init_mutexes(); > > LOGGER_HANDLE *logger_open(const char *path, > > unsigned long long size_limit, > > - unsigned int rotations); > > + unsigned int rotations, size_t > buffer_size); > > int logger_close(LOGGER_HANDLE *log); > > int logger_vprintf(LOGGER_HANDLE *log, const char *fmt, va_list > argptr) > > ATTRIBUTE_FORMAT(printf, 2, 0); > > int logger_printf(LOGGER_HANDLE *log, const char *fmt, ...) > > ATTRIBUTE_FORMAT(printf, 2, 3); > > - int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size); > > + int logger_write(LOGGER_HANDLE *log, const void *data, size_t size); > > int logger_rotate(LOGGER_HANDLE *log); > > + int logger_sync(LOGGER_HANDLE *log); > > #endif > > > > > > diff --git a/mysys/file_logger.c b/mysys/file_logger.c > > index a753c049f68..5464e43eddf 100644 > > --- a/mysys/file_logger.c > > +++ b/mysys/file_logger.c > > @@ -145,85 +230,108 @@ static int do_rotate(LOGGER_HANDLE *log) > > namebuf[log->path_len]= 0; > > result= my_rename(namebuf, logname(log, log->path, 1), MYF(0)); > > log->file= my_open(namebuf, LOG_FLAGS, MYF(0)); > > + log->in_file= 0; > > exit: > > errno= my_errno; > > return log->file < 0 || result; > > } > > > > > > -/* > > - Return 1 if we should rotate the log > > -*/ > > - > > -my_bool logger_time_to_rotate(LOGGER_HANDLE *log) > > -{ > > - my_off_t filesize; > > - if (log->rotations > 0 && > > - (filesize= my_tell(log->file, MYF(0))) != (my_off_t) -1 && > > - ((ulonglong) filesize >= log->size_limit)) > > - return 1; > > - return 0; > > -} > > - > > - > > int logger_vprintf(LOGGER_HANDLE *log, const char* fmt, va_list ap) > > { > > - int result; > > char cvtbuf[1024]; > > size_t n_bytes; > > > > - flogger_mutex_lock(&log->lock); > > - if (logger_time_to_rotate(log) && do_rotate(log)) > > - { > > - result= -1; > > - errno= my_errno; > > - goto exit; /* Log rotation needed but failed */ > > - } > > - > > n_bytes= my_vsnprintf(cvtbuf, sizeof(cvtbuf), fmt, ap); > > if (n_bytes >= sizeof(cvtbuf)) > > n_bytes= sizeof(cvtbuf) - 1; > > > > - result= (int)my_write(log->file, (uchar *) cvtbuf, n_bytes, MYF(0)); > > - > > -exit: > > - flogger_mutex_unlock(&log->lock); > > - return result; > > + return logger_write(log, cvtbuf, n_bytes); > > } > > > > > > -static int logger_write_r(LOGGER_HANDLE *log, my_bool allow_rotations, > > - const char *buffer, size_t size) > > +int logger_write(LOGGER_HANDLE *log, const void *data, size_t size) > > { > > int result; > > + size_t in_buffer; > > + > > + mysql_mutex_lock(&log->lock); > > > > - flogger_mutex_lock(&log->lock); > > - if (allow_rotations && logger_time_to_rotate(log) && do_rotate(log)) > > + if (log->buffer_left >= size) > > + { > > + memcpy(log->buffer_pos, data, size); > > + log->buffer_pos+= size; > > + log->buffer_left-= size; > > + mysql_mutex_unlock(&log->lock); > > + return size; > > + } > > + > > + mysql_mutex_lock(&log->lock_buffer); > > + > > + in_buffer= log->buffer_pos - log->buffer; > > + > > + { /* swap buffers. */ > > + uchar *tmp_buf= log->buffer; > > + log->buffer= log->idle_buffer; > > + log->idle_buffer= tmp_buf; > > + } > > + > > + set_buffer_pos_and_left(log); > > + > > + /* Now other threads can write to the new buffer. */ > > + mysql_mutex_unlock(&log->lock); > > + > > + if ((in_buffer && > > + my_write(log->file, log->idle_buffer, in_buffer, MYF(0)) != > in_buffer)|| > > + my_write(log->file, (uchar *) data, size, MYF(0)) != size) > > { > > result= -1; > > errno= my_errno; > > - goto exit; /* Log rotation needed but failed */ > > + goto exit_buf; > > } > > + else > > + result= 0; > > > > - result= (int)my_write(log->file, (uchar *) buffer, size, MYF(0)); > > + log->in_file+= in_buffer + size; > > + if (log->rotations > 0 && log->in_file >= log->size_limit) > > + { > > + if (do_rotate(log)) > > + { > > + result= -1; > > + errno= my_errno; > > + goto exit_buf; /* Log rotation needed but failed */ > > + } > > + } > > > > -exit: > > - flogger_mutex_unlock(&log->lock); > > +exit_buf: > > + mysql_mutex_unlock(&log->lock_buffer); > > return result; > > } > > > > > > -int logger_write(LOGGER_HANDLE *log, const char *buffer, size_t size) > > -{ > > - return logger_write_r(log, TRUE, buffer, size); > > -} > > - > > int logger_rotate(LOGGER_HANDLE *log) > > { > > int result; > > - flogger_mutex_lock(&log->lock); > > - result= do_rotate(log); > > - flogger_mutex_unlock(&log->lock); > > + mysql_mutex_lock(&log->lock); > > + mysql_mutex_lock(&log->lock_buffer); > > + result= flush_buffer(log) || do_rotate(log); > > I'd though you can switch buffers here too and flush/rotate > only under the lock_buffer mutex > > > + mysql_mutex_unlock(&log->lock_buffer); > > + mysql_mutex_unlock(&log->lock); > > + return result; > > +} > > + > > + > > +int logger_sync(LOGGER_HANDLE *log) > > Why did you introduce an explicit sync API? > > > +{ > > + int result; > > + mysql_mutex_lock(&log->lock); > > + mysql_mutex_lock(&log->lock_buffer); > > + if ((result= flush_buffer(log))) > > + { > > + result= fsync(log->file); > > + } > > + mysql_mutex_unlock(&log->lock_buffer); > > + mysql_mutex_unlock(&log->lock); > > return result; > > } > > > > diff --git a/plugin/server_audit/server_audit.c > b/plugin/server_audit/server_audit.c > > index 5fc0e3373f3..e51df7ab6b5 100644 > > --- a/plugin/server_audit/server_audit.c > > +++ b/plugin/server_audit/server_audit.c > > @@ -1393,26 +1401,15 @@ static void change_connection(struct > connection_info *cn, > > static int write_log(const char *message, size_t len, int take_lock) > > { > > int result= 0; > > + > > if (take_lock) > > - { > > - /* Start by taking a read lock */ > > mysql_prlock_rdlock(&lock_operations); > > - } > > > > if (output_type == OUTPUT_FILE) > > { > > if (logfile) > > { > > - my_bool allow_rotate= !take_lock; /* Allow rotate if caller write > lock */ > > - if (take_lock && logger_time_to_rotate(logfile)) > > - { > > - /* We have to rotate the log, change above read lock to write > lock */ > > - mysql_prlock_unlock(&lock_operations); > > - mysql_prlock_wrlock(&lock_operations); > > - allow_rotate= 1; > > - } > > - if (!(is_active= (logger_write_r(logfile, allow_rotate, message, > len) == > > - (int) len))) > > + if (!(is_active= (logger_write(logfile, message, len) == (int) > len))) > > nice, rotation is indeed the logger's headache, not the caller's > > > { > > ++log_write_failures; > > result= 1; > > @@ -2899,6 +2906,36 @@ static void update_file_rotations(MYSQL_THD thd > __attribute__((unused)), > > } > > > > > > +static void update_file_buffer_size(MYSQL_THD thd > __attribute__((unused)), > > + struct st_mysql_sys_var *var __attribute__((unused)), > > + void *var_ptr __attribute__((unused)), const void *save) > > +{ > > + file_buffer_size= *(unsigned int *) save; > > + > > + error_header(); > > + fprintf(stderr, "Log file buffer size was changed to '%d'.\n", > file_buffer_size); > > + > > + if (!logging || output_type != OUTPUT_FILE) > > + return; > > + > > + ADD_ATOMIC(internal_stop_logging, 1); > > + if (!maria_55_started || !debug_server_started) > > + mysql_prlock_wrlock(&lock_operations); > > + > > + stop_logging(); > > + if (start_logging()) > > this could be an API call in the logger. Like "reinit(new params)" > and it'll close, change params, open - all under a log mutex, which doesn't > need to be destroyed and reinitialized. > > > + { > > + error_header(); > > + fprintf(stderr, "Logging was disabled..\n"); > > + CLIENT_ERROR(1, "Logging was disabled.", MYF(ME_WARNING)); > > + } > > + > > + if (!maria_55_started || !debug_server_started) > > + mysql_prlock_unlock(&lock_operations); > > + ADD_ATOMIC(internal_stop_logging, -1); > > +} > > + > > + > > static void update_file_rotate_size(MYSQL_THD thd > __attribute__((unused)), > > struct st_mysql_sys_var *var __attribute__((unused)), > > void *var_ptr __attribute__((unused)), const void *save) > > Regards, > Sergei > Chief Architect, MariaDB Server > and secur...@mariadb.org >
_______________________________________________ developers mailing list -- developers@lists.mariadb.org To unsubscribe send an email to developers-le...@lists.mariadb.org