mirror of
				https://github.com/MariaDB/server.git
				synced 2025-11-04 04:46:15 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			248 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			248 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 2012 Monty Program Ab
 | 
						|
 | 
						|
   This program is free software; you can redistribute it and/or modify
 | 
						|
   it under the terms of the GNU General Public License as published by
 | 
						|
   the Free Software Foundation; version 2 of the License.
 | 
						|
 | 
						|
   This program is distributed in the hope that it will be useful,
 | 
						|
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
   GNU General Public License for more details.
 | 
						|
 | 
						|
   You should have received a copy of the GNU General Public License
 | 
						|
   along with this program; if not, write to the Free Software
 | 
						|
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
 | 
						|
 | 
						|
 | 
						|
#ifndef FLOGGER_SKIP_INCLUDES
 | 
						|
#include "my_global.h"
 | 
						|
#include <my_sys.h>
 | 
						|
#include <m_string.h>
 | 
						|
#include <mysql/service_logger.h>
 | 
						|
#include <my_pthread.h>
 | 
						|
#endif /*FLOGGER_SKIP_INCLUDES*/
 | 
						|
 | 
						|
#ifndef flogger_mutex_init
 | 
						|
#define flogger_mutex_init(A,B,C) mysql_mutex_init(A,B,C)
 | 
						|
#define flogger_mutex_destroy(A) mysql_mutex_destroy(A)
 | 
						|
#define flogger_mutex_lock(A) mysql_mutex_lock(A)
 | 
						|
#define flogger_mutex_unlock(A) mysql_mutex_unlock(A)
 | 
						|
#endif /*flogger_mutex_init*/
 | 
						|
 | 
						|
#ifdef HAVE_PSI_INTERFACE
 | 
						|
/* These belong to the service initialization */
 | 
						|
static PSI_mutex_key key_LOCK_logger_service;
 | 
						|
static PSI_mutex_info mutex_list[]=
 | 
						|
{{ &key_LOCK_logger_service, "logger_service_file_st::lock", PSI_FLAG_GLOBAL}};
 | 
						|
#endif
 | 
						|
 | 
						|
typedef struct logger_handle_st {
 | 
						|
  File file;
 | 
						|
  char path[FN_REFLEN];
 | 
						|
  unsigned long long size_limit;
 | 
						|
  unsigned int rotations;
 | 
						|
  size_t path_len;
 | 
						|
  mysql_mutex_t lock;
 | 
						|
} LSFS;
 | 
						|
 | 
						|
 | 
						|
#define LOG_FLAGS (O_APPEND | O_CREAT | O_WRONLY)
 | 
						|
 | 
						|
static unsigned int n_dig(unsigned int i)
 | 
						|
{
 | 
						|
  return (i == 0) ? 0 : ((i < 10) ? 1 : ((i < 100) ? 2 : 3));
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
LOGGER_HANDLE *logger_open(const char *path,
 | 
						|
                           unsigned long long size_limit,
 | 
						|
                           unsigned int rotations)
 | 
						|
{
 | 
						|
  LOGGER_HANDLE new_log, *l_perm;
 | 
						|
  /*
 | 
						|
    I don't think we ever need more rotations,
 | 
						|
    but if it's so, the rotation procedure should be adapted to it.
 | 
						|
  */
 | 
						|
  if (rotations > 999)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  new_log.rotations= rotations;
 | 
						|
  new_log.size_limit= size_limit;
 | 
						|
  new_log.path_len= strlen(fn_format(new_log.path, path,
 | 
						|
        mysql_data_home, "", MY_UNPACK_FILENAME));
 | 
						|
 | 
						|
  if (new_log.path_len+n_dig(rotations)+1 > FN_REFLEN)
 | 
						|
  {
 | 
						|
    errno= ENAMETOOLONG;
 | 
						|
    /* File path too long */
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
  if ((new_log.file= my_open(new_log.path, LOG_FLAGS, MYF(0))) < 0)
 | 
						|
  {
 | 
						|
    errno= my_errno;
 | 
						|
    /* Check errno for the cause */
 | 
						|
    return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!(l_perm= (LOGGER_HANDLE *) my_malloc(PSI_INSTRUMENT_ME,
 | 
						|
                                            sizeof(LOGGER_HANDLE), MYF(0))))
 | 
						|
  {
 | 
						|
    my_close(new_log.file, MYF(0));
 | 
						|
    new_log.file= -1;
 | 
						|
    return 0; /* End of memory */
 | 
						|
  }
 | 
						|
  *l_perm= new_log;
 | 
						|
  flogger_mutex_init(key_LOCK_logger_service, &l_perm->lock,
 | 
						|
                     MY_MUTEX_INIT_FAST);
 | 
						|
  return l_perm;
 | 
						|
}
 | 
						|
 | 
						|
int logger_close(LOGGER_HANDLE *log)
 | 
						|
{
 | 
						|
  int result;
 | 
						|
  File file= log->file;
 | 
						|
  flogger_mutex_destroy(&log->lock);
 | 
						|
  my_free(log);
 | 
						|
  if ((result= my_close(file, MYF(0))))
 | 
						|
    errno= my_errno;
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static char *logname(LOGGER_HANDLE *log, char *buf, unsigned int n_log)
 | 
						|
{
 | 
						|
  sprintf(buf+log->path_len, ".%0*u", n_dig(log->rotations), n_log);
 | 
						|
  return buf;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int do_rotate(LOGGER_HANDLE *log)
 | 
						|
{
 | 
						|
  char namebuf[FN_REFLEN];
 | 
						|
  int result;
 | 
						|
  unsigned int i;
 | 
						|
  char *buf_old, *buf_new, *tmp;
 | 
						|
 | 
						|
  if (log->rotations == 0)
 | 
						|
    return 0;
 | 
						|
 | 
						|
  memcpy(namebuf, log->path, log->path_len);
 | 
						|
 | 
						|
  buf_new= logname(log, namebuf, log->rotations);
 | 
						|
  buf_old= log->path;
 | 
						|
  for (i=log->rotations-1; i>0; i--)
 | 
						|
  {
 | 
						|
    logname(log, buf_old, i);
 | 
						|
    if (!access(buf_old, F_OK) &&
 | 
						|
        (result= my_rename(buf_old, buf_new, MYF(0))))
 | 
						|
      goto exit;
 | 
						|
    tmp= buf_old;
 | 
						|
    buf_old= buf_new;
 | 
						|
    buf_new= tmp;
 | 
						|
  }
 | 
						|
  if ((result= my_close(log->file, MYF(0))))
 | 
						|
    goto exit;
 | 
						|
  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));
 | 
						|
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;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int logger_write_r(LOGGER_HANDLE *log, my_bool allow_rotations,
 | 
						|
                          const char *buffer, size_t size)
 | 
						|
{
 | 
						|
  int result;
 | 
						|
 | 
						|
  flogger_mutex_lock(&log->lock);
 | 
						|
  if (allow_rotations && logger_time_to_rotate(log) && do_rotate(log))
 | 
						|
  {
 | 
						|
    result= -1;
 | 
						|
    errno= my_errno;
 | 
						|
    goto exit; /* Log rotation needed but failed */
 | 
						|
  }
 | 
						|
 | 
						|
  result= (int)my_write(log->file, (uchar *) buffer, size, MYF(0));
 | 
						|
 | 
						|
exit:
 | 
						|
  flogger_mutex_unlock(&log->lock);
 | 
						|
  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);
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
int logger_printf(LOGGER_HANDLE *log, const char *fmt, ...)
 | 
						|
{
 | 
						|
  int result;
 | 
						|
  va_list args;
 | 
						|
  va_start(args,fmt);
 | 
						|
  result= logger_vprintf(log, fmt, args);
 | 
						|
  va_end(args);
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
void logger_init_mutexes()
 | 
						|
{
 | 
						|
#ifdef HAVE_PSI_INTERFACE
 | 
						|
  if (unlikely(PSI_server))
 | 
						|
    PSI_server->register_mutex("sql_logger", mutex_list, 1);
 | 
						|
#endif
 | 
						|
}
 | 
						|
 |