Skip to content

File log_compress.c

File List > cubrid > src > transaction > log_compress.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_compress.c - log compression functions
 *
 * Note: Using lz4 library
 */

#ident "$Id$"

#include <string.h>
#include <assert.h>

#include "log_compress.h"
#include "error_manager.h"
#include "memory_alloc.h"
#include "perf_monitor.h"
// XXX: SHOULD BE THE LAST INCLUDE HEADER
#include "memory_wrapper.hpp"

/*
 * log_zip - compress(zip) log data into LOG_ZIP
 *   return: true on success, false on failure
 *   log_zip(in/out): LOG_ZIP structure allocated by log_zip_alloc
 *   length(in): length of given data
 *   data(in): log data to be compressed
 */
bool
log_zip (LOG_ZIP * log_zip, LOG_ZIP_SIZE_T length, const void *data)
{
  int zip_len = 0;
  LOG_ZIP_SIZE_T buf_size;
  bool compressed;
#if defined (SERVER_MODE) || defined (SA_MODE)
  PERF_UTIME_TRACKER time_track;
#endif

  assert (length > 0 && data != NULL);
  assert (log_zip != NULL);

  if (length > LZ4_MAX_INPUT_SIZE)
    {
      /* Can't compress beyonds max LZ4 max input size. */
      return false;
    }

  log_zip->data_length = 0;

  buf_size = LOG_ZIP_BUF_SIZE (LZ4, length);

  if (!log_zip_realloc_if_needed (*log_zip, buf_size))
    {
      return false;
    }

#if defined (SERVER_MODE) || defined (SA_MODE)
  PERF_UTIME_TRACKER_START (NULL, &time_track);
#endif

  compressed = false;

  /* save original data length */
  memcpy (log_zip->log_data, &length, sizeof (LOG_ZIP_SIZE_T));

  // *INDENT-OFF*
  zip_len =
    cubcompress::compress<cubcompress::LZ4> (data, length, log_zip->log_data + sizeof (LOG_ZIP_SIZE_T),
                         buf_size - sizeof (LOG_ZIP_SIZE_T));
  // *INDENT-ON*

  if (zip_len > 0)
    {
      log_zip->data_length = (LOG_ZIP_SIZE_T) zip_len + sizeof (LOG_ZIP_SIZE_T);
      /* if the compressed data length >= orginal length, then it means that compression failed */
      if (log_zip->data_length < length)
    {
      compressed = true;
    }
    }

#if defined (SERVER_MODE) || defined (SA_MODE)
  PERF_UTIME_TRACKER_TIME (NULL, &time_track, PSTAT_LOG_LZ4_COMPRESS_TIME_COUNTERS);
#endif

  return compressed;
}

/*
 * log_unzip - decompress(unzip) log data into LOG_ZIP
 *   return: true on success, false on failure
 *   log_unzip(out): LOG_ZIP structure allocated by log_zip_alloc
 *   length(in): length of given data
 *   data(in): compressed log data
 */
bool
log_unzip (LOG_ZIP * log_unzip, LOG_ZIP_SIZE_T length, const void *data)
{
  int unzip_len;
  LOG_ZIP_SIZE_T buf_size;
  bool decompressed;
#if defined (SERVER_MODE) || defined (SA_MODE)
  PERF_UTIME_TRACKER time_track;
#endif

  assert (length > 0 && data != NULL);
  assert (log_unzip != NULL);

  /* get original legnth from the compressed data */
  memcpy (&buf_size, data, sizeof (LOG_ZIP_SIZE_T));

  if (buf_size <= 0)
    {
      return false;
    }

  length -= sizeof (LOG_ZIP_SIZE_T);

  if (!log_zip_realloc_if_needed (*log_unzip, buf_size))
    {
      return false;
    }

#if defined (SERVER_MODE) || defined (SA_MODE)
  PERF_UTIME_TRACKER_START (NULL, &time_track);
#endif

  decompressed = false;

  // *INDENT-OFF*
  unzip_len =
    cubcompress::decompress<cubcompress::LZ4> ((const char *) data + sizeof (LOG_ZIP_SIZE_T), length,
                           (char *) log_unzip->log_data, buf_size);
  // *INDENT-ON*
  if (unzip_len >= 0)
    {
      log_unzip->data_length = (LOG_ZIP_SIZE_T) unzip_len;
      /* if the uncompressed data length != original length, then it means that uncompression failed */
      if (unzip_len == buf_size)
    {
      decompressed = true;
    }
    }

#if defined (SERVER_MODE) || defined (SA_MODE)
  PERF_UTIME_TRACKER_TIME (NULL, &time_track, PSTAT_LOG_LZ4_DECOMPRESS_TIME_COUNTERS);
#endif

  return decompressed;
}

/*
 * log_diff - make log diff - redo data XORed with undo data
 *   return: true
 *   undo_length(in): length of undo data
 *   undo_data(in): undo log data
 *   redo_length(in): length of redo data
 *   redo_data(in/out) redo log data; set as side effect
 */
bool
log_diff (LOG_ZIP_SIZE_T undo_length, const void *undo_data, LOG_ZIP_SIZE_T redo_length, void *redo_data)
{
  LOG_ZIP_SIZE_T i, size;
  unsigned char *p, *q;

  assert (undo_length > 0 && undo_data != NULL);
  assert (redo_length > 0 && redo_data != NULL);

  size = MIN (undo_length, redo_length);

  /* redo = redo xor undo */
  p = (unsigned char *) redo_data;
  q = (unsigned char *) undo_data;
  for (i = 0; i < size; i++)
    {
      *(p++) ^= *(q++);
    }

  return true;
}

/* log_zip_realloc_if_needed - re-alloc the internal buffer, if needed, and adjust members
 *  return: true if operation succeeded regardless of whether the allocation was needed or not
 *  log_zip(in/out): structure to allocate members of
 *  new_size(in): new buffer to allocate, if the value is greater than the current buffer size, the buffer is re
 */
bool
log_zip_realloc_if_needed (LOG_ZIP & log_zip, LOG_ZIP_SIZE_T new_size)
{
  assert (new_size <= LZ4_MAX_INPUT_SIZE);

  if (new_size > 0 && new_size > log_zip.buf_size)
    {
      const LOG_ZIP_SIZE_T buf_size = LOG_ZIP_BUF_SIZE (LZ4, new_size);
      assert (buf_size <= LZ4_MAX_INPUT_SIZE);

      log_zip.log_data = (char *) realloc (log_zip.log_data, buf_size);
      if (log_zip.log_data == nullptr)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) buf_size);
    }
      log_zip.buf_size = buf_size;
    }

  if (new_size > 0 && log_zip.log_data == nullptr)
    {
      log_zip.data_length = 0;
      log_zip.buf_size = 0;
      return false;
    }

  return true;
}

/*
 * log_zip_alloc - allocate LOG_ZIP structure
 *   return: LOG_ZIP structure or NULL if error
 *   length(in): log_zip data buffer to be allocated
 *
 * Note:
 */
LOG_ZIP *
log_zip_alloc (LOG_ZIP_SIZE_T size)
{
  LOG_ZIP *log_zip = NULL;

  assert (size <= LZ4_MAX_INPUT_SIZE);

  log_zip = (LOG_ZIP *) malloc (sizeof (LOG_ZIP));
  if (log_zip == NULL)
    {
      er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, sizeof (LOG_ZIP));

      return NULL;
    }
  log_zip->data_length = 0;
  log_zip->buf_size = 0;
  log_zip->log_data = nullptr;

  if (!log_zip_realloc_if_needed (*log_zip, size))
    {
      free_and_init (log_zip);
      return nullptr;
    }

  return log_zip;
}

void
log_zip_free_data (LOG_ZIP & log_zip)
{
  if (log_zip.log_data != nullptr)
    {
      free_and_init (log_zip.log_data);
    }
}

/*
 * log_zip_free - free LOG_ZIP structure
 *   return: none
 *   log_zip(in): LOG_ZIP structure to be freed
 */
void
log_zip_free (LOG_ZIP * log_zip)
{
  assert (log_zip != NULL);
  log_zip_free_data (*log_zip);
  free_and_init (log_zip);
}