Skip to content

File log_comm.c

File List > cubrid > src > transaction > log_comm.c

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */

/*
 * log_comm.c - log and recovery manager (at client & server)
 */

#ident "$Id$"

#include "config.h"

#include <assert.h>
#if !defined(WINDOWS)
#include <sys/time.h>
#endif /* !WINDOWS */

#include "log_comm.h"

#include "memory_alloc.h"
#include "storage_common.h"
#include "error_manager.h"
#include "porting.h"
#include "environment_variable.h"
#include "system_parameter.h"
#include "misc_string.h"
#include "intl_support.h"
#include "log_common_impl.h"
#if defined (SERVER_MODE)
#include "vacuum.h"
#endif /* SERVER_MODE */
#if !defined(WINDOWS)
#if defined(CS_MODE)
#include "db.h"
#endif /* CS_MODE */
#if defined(SERVER_MODE)
#include "server_support.h"
#include "connection_defs.h"
#endif /* SERVER_MODE */
#endif /* !WINDOWS */
#if defined (SERVER_MODE)
#include "thread_manager.hpp"
#endif // SERVER_MODE
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

struct tran_state_name
{
  TRAN_STATE state;
  const char *name;
};
typedef struct tran_state_name TRAN_STATE_NAME;

static TRAN_STATE_NAME log_Tran_state_names[] = {
  {TRAN_RECOVERY,
   "TRAN_RECOVERY"},
  {TRAN_ACTIVE,
   "TRAN_ACTIVE"},
  {TRAN_UNACTIVE_COMMITTED,
   "TRAN_UNACTIVE_COMMITTED"},
  {TRAN_UNACTIVE_WILL_COMMIT,
   "TRAN_UNACTIVE_WILL_COMMIT"},
  {TRAN_UNACTIVE_COMMITTED_WITH_POSTPONE,
   "TRAN_UNACTIVE_COMMITTED_WITH_POSTPONE"},
  {TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE,
   "TRAN_UNACTIVE_TOPOPE_COMMITTED_WITH_POSTPONE"},
  {TRAN_UNACTIVE_ABORTED,
   "TRAN_UNACTIVE_ABORTED"},
  {TRAN_UNACTIVE_UNILATERALLY_ABORTED,
   "TRAN_UNACTIVE_UNILATERALLY_ABORTED"},
  {TRAN_UNACTIVE_2PC_PREPARE,
   "TRAN_UNACTIVE_2PC_PREPARE"},
  {TRAN_UNACTIVE_2PC_COLLECTING_PARTICIPANT_VOTES,
   "TRAN_UNACTIVE_2PC_COLLECTING_PARTICIPANT_VOTES"},
  {TRAN_UNACTIVE_2PC_ABORT_DECISION,
   "TRAN_UNACTIVE_2PC_ABORT_DECISION"},
  {TRAN_UNACTIVE_2PC_COMMIT_DECISION,
   "TRAN_UNACTIVE_2PC_COMMIT_DECISION"},
  {TRAN_UNACTIVE_COMMITTED_INFORMING_PARTICIPANTS,
   "TRAN_UNACTIVE_COMMITTED_INFORMING_PARTICIPANTS"},
  {TRAN_UNACTIVE_ABORTED_INFORMING_PARTICIPANTS,
   "TRAN_UNACTIVE_ABORTED_INFORMING_PARTICIPANTS"},
  {TRAN_UNACTIVE_UNKNOWN,
   "TRAN_STATE_UNKNOWN"}
};

struct isolation_name
{
  TRAN_ISOLATION isolation;
  const char *name;
};
typedef struct isolation_name TRAN_ISOLATION_NAME;

static TRAN_ISOLATION_NAME log_Isolation_names[] = {
  {TRAN_SERIALIZABLE, "SERIALIZABLE"},
  {TRAN_REPEATABLE_READ, "REPEATABLE READ"},
  {TRAN_READ_COMMITTED, "COMMITTED READ"},
  {TRAN_UNKNOWN_ISOLATION, "TRAN_UNKNOWN_ISOLATION"}
};

const int LOG_MIN_NBUFFERS = 3;

/*
 * log_state_string - Translate state into string representation
 *
 * return:
 *
 *   state(in): Transaction state
 *
 * NOTE: Translate state into a string representation.
 */
const char *
log_state_string (TRAN_STATE state)
{
  int num = sizeof (log_Tran_state_names) / sizeof (TRAN_STATE_NAME);
  int i;

  for (i = 0; i < num; i++)
    {
      if (log_Tran_state_names[i].state == state)
    {
      return log_Tran_state_names[i].name;
    }
    }

  return "TRAN_STATE_UNKNOWN";

}


/*
 * log_state_short_string - Translate state into string representation
 *                      without TRAN_ prefix
 *
 * return:
 *
 *   state(in): Transaction state
 */
const char *
log_state_short_string (TRAN_STATE state)
{
  const char *state_string;
  int skip_len;

  skip_len = sizeof ("TRAN_") - 1;
  state_string = log_state_string (state) + skip_len;

  return state_string;
}

/*
 * log_isolation_string - Translate isolation level into string representation
 *
 * return:
 *
 *   isolation(in): Isolation level. One of the following:
 *                         TRAN_REPEATABLE_READ
 *                         TRAN_READ_COMMITTED
 *                         TRAN_SERIALIZABLE
 *
 * NOTE:Translate degree of consistency into a string representation.
 */
const char *
log_isolation_string (TRAN_ISOLATION isolation)
{
  int num = sizeof (log_Isolation_names) / sizeof (TRAN_ISOLATION_NAME);
  int i;

  for (i = 0; i < num; i++)
    {
      if (log_Isolation_names[i].isolation == isolation)
    {
      return log_Isolation_names[i].name;
    }
    }

  return "TRAN_UNKNOWN_ISOLATION";
}

/*
 * log_dump_log_info - Dump log information
 *
 * return: nothing
 *
 *   logname_info(in): Name of the log information file
 *   also_stdout(in):
 *   fmt(in): Format for the variable list of arguments (like printf)
 *   va_alist: Variable number of arguments
 *
 * NOTE:Dump some log information
 */
int
log_dump_log_info (const char *logname_info, bool also_stdout, const char *fmt, ...)
{
  FILE *fp;         /* Pointer to file */
  va_list ap;           /* Point to each unnamed arg in turn */
  time_t log_time;
  struct tm log_tm;
  struct tm *log_tm_p = &log_tm;
  struct timeval tv;
  char time_array[128];
  char time_array_of_log_info[255];

  va_start (ap, fmt);

  if (logname_info == NULL)
    {
      return ER_FAILED;
    }

  fp = fopen (logname_info, "a");
  if (fp == NULL)
    {
      er_set (ER_WARNING_SEVERITY, ARG_FILE_LINE, ER_LOG_MOUNT_FAIL, 1, logname_info);
      va_end (ap);
      return ER_LOG_MOUNT_FAIL;
    }

  log_time = time (NULL);
  log_tm_p = localtime_r (&log_time, &log_tm);
  if (log_tm_p == NULL)
    {
      strcpy (time_array_of_log_info, "Time: 00/00/00 00:00:00.000 - ");
    }
  else
    {
      gettimeofday (&tv, NULL);
      strftime (time_array, 128, "%m/%d/%y %H:%M:%S", log_tm_p);
      snprintf (time_array_of_log_info, 255, "Time: %s.%03ld - ", time_array, tv.tv_usec / 1000);
    }

  if (strlen (time_array_of_log_info) != TIME_SIZE_OF_DUMP_LOG_INFO)
    {
      strcpy (time_array_of_log_info, "Time: 00/00/00 00:00:00.000 - ");
    }

  fprintf (fp, "%s", time_array_of_log_info);

  (void) vfprintf (fp, fmt, ap);
  fflush (fp);
  fclose (fp);

#if !defined(NDEBUG)
  if (also_stdout && prm_get_bool_value (PRM_ID_LOG_TRACE_DEBUG))
    {
      va_start (ap, fmt);
      (void) vfprintf (stdout, fmt, ap);
      fflush (stdout);
    }
#endif

  va_end (ap);

  return NO_ERROR;
}

bool
log_does_allow_replication (void)
{
#if defined(WINDOWS) || defined(SA_MODE)
  return false;

#elif defined(CS_MODE)      /* WINDOWS || SA_MODE */
  int client_type;

  client_type = db_get_client_type ();
  if (client_type == DB_CLIENT_TYPE_LOG_COPIER || client_type == DB_CLIENT_TYPE_LOG_APPLIER)
    {
      return false;
    }

  return true;

#elif defined(SERVER_MODE)  /* CS_MODE */
  HA_SERVER_STATE ha_state;

  /* Vacuum workers are not allowed to reach this code */
  if (LOG_FIND_CURRENT_TDES () == NULL || !LOG_FIND_CURRENT_TDES ()->is_active_worker_transaction ())
    {
      return false;
    }

  if (HA_DISABLED ())
    {
      return false;
    }

  ha_state = css_ha_server_state ();
  if (ha_state != HA_SERVER_STATE_ACTIVE && ha_state != HA_SERVER_STATE_TO_BE_STANDBY)
    {
      return false;
    }

  assert (db_Disable_modifications == 0);

  return true;
#else /* SERVER_MODE */

  return false;
#endif
}