Blame source/vdo/base/compressionState.c

Packit Service 310c69
/*
Packit Service 310c69
 * Copyright (c) 2020 Red Hat, Inc.
Packit Service 310c69
 *
Packit Service 310c69
 * This program is free software; you can redistribute it and/or
Packit Service 310c69
 * modify it under the terms of the GNU General Public License
Packit Service 310c69
 * as published by the Free Software Foundation; either version 2
Packit Service 310c69
 * of the License, or (at your option) any later version.
Packit Service 310c69
 * 
Packit Service 310c69
 * This program is distributed in the hope that it will be useful,
Packit Service 310c69
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 310c69
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 310c69
 * GNU General Public License for more details.
Packit Service 310c69
 * 
Packit Service 310c69
 * You should have received a copy of the GNU General Public License
Packit Service 310c69
 * along with this program; if not, write to the Free Software
Packit Service 310c69
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
Packit Service 310c69
 * 02110-1301, USA. 
Packit Service 310c69
 *
Packit Service 310c69
 * $Id: //eng/vdo-releases/aluminum/src/c++/vdo/base/compressionState.c#2 $
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
#include "compressionStateInternals.h"
Packit Service 310c69
Packit Service 310c69
#include "dataVIO.h"
Packit Service 310c69
#include "packer.h"
Packit Service 310c69
Packit Service 310c69
static const uint32_t STATUS_MASK           = 0xff;
Packit Service 310c69
static const uint32_t MAY_NOT_COMPRESS_MASK = 0x80000000;
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
VIOCompressionState getCompressionState(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  uint32_t packedValue = atomicLoad32(&dataVIO->compression.state);
Packit Service 310c69
  return (VIOCompressionState) {
Packit Service 310c69
    .status         = packedValue & STATUS_MASK,
Packit Service 310c69
    .mayNotCompress = ((packedValue & MAY_NOT_COMPRESS_MASK) != 0),
Packit Service 310c69
  };
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Convert a VIOCompressionState into a uint32_t which may be stored
Packit Service 310c69
 * atomically.
Packit Service 310c69
 *
Packit Service 310c69
 * @param state  The state to convert
Packit Service 310c69
 *
Packit Service 310c69
 * @return The compression state packed into a uint32_t
Packit Service 310c69
 **/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static uint32_t packState(VIOCompressionState state)
Packit Service 310c69
{
Packit Service 310c69
  return state.status | (state.mayNotCompress ? MAY_NOT_COMPRESS_MASK : 0);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool setCompressionState(DataVIO             *dataVIO,
Packit Service 310c69
                         VIOCompressionState  state,
Packit Service 310c69
                         VIOCompressionState  newState)
Packit Service 310c69
{
Packit Service 310c69
  return compareAndSwap32(&dataVIO->compression.state, packState(state),
Packit Service 310c69
                          packState(newState));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Advance to the next compression state along the compression path.
Packit Service 310c69
 *
Packit Service 310c69
 * @param dataVIO  The DataVIO to advance
Packit Service 310c69
 *
Packit Service 310c69
 * @return The new compression status of the DataVIO
Packit Service 310c69
 **/
Packit Service 310c69
static VIOCompressionStatus advanceStatus(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  for (;;) {
Packit Service 310c69
    VIOCompressionState state = getCompressionState(dataVIO);
Packit Service 310c69
    if (state.status == VIO_POST_PACKER) {
Packit Service 310c69
      // We're already in the last state.
Packit Service 310c69
      return state.status;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    VIOCompressionState newState = state;
Packit Service 310c69
    if (state.mayNotCompress) {
Packit Service 310c69
      // Compression has been dis-allowed for this VIO, so skip the rest of the
Packit Service 310c69
      // path and go to the end.
Packit Service 310c69
      newState.status = VIO_POST_PACKER;
Packit Service 310c69
    } else {
Packit Service 310c69
      // Go to the next state.
Packit Service 310c69
      newState.status++;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    if (setCompressionState(dataVIO, state, newState)) {
Packit Service 310c69
      return newState.status;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    // Another thread changed the state out from under us so try again.
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool mayCompressDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  if (!hasAllocation(dataVIO)
Packit Service 310c69
      || ((getWritePolicy(getVDOFromDataVIO(dataVIO)) != WRITE_POLICY_SYNC)
Packit Service 310c69
          && vioRequiresFlushAfter(dataVIOAsVIO(dataVIO)))
Packit Service 310c69
      || !getVDOCompressing(getVDOFromDataVIO(dataVIO))) {
Packit Service 310c69
    /*
Packit Service 310c69
     * If this VIO didn't get an allocation, the compressed write probably
Packit Service 310c69
     * won't either, so don't try compressing it. Also, if compression is off,
Packit Service 310c69
     * don't compress.
Packit Service 310c69
     */
Packit Service 310c69
    setCompressionDone(dataVIO);
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (dataVIO->hashLock == NULL) {
Packit Service 310c69
    // DataVIOs without a HashLock (which should be extremely rare) aren't
Packit Service 310c69
    // able to share the packer's PBN lock, so don't try to compress them.
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return (advanceStatus(dataVIO) == VIO_COMPRESSING);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool mayPackDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  if (!isSufficientlyCompressible(dataVIO)
Packit Service 310c69
      || !getVDOCompressing(getVDOFromDataVIO(dataVIO))
Packit Service 310c69
      || getCompressionState(dataVIO).mayNotCompress) {
Packit Service 310c69
    // If the data in this VIO doesn't compress, or compression is off, or
Packit Service 310c69
    // compression for this VIO has been canceled, don't send it to the packer.
Packit Service 310c69
    setCompressionDone(dataVIO);
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return true;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool mayBlockInPacker(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  return (advanceStatus(dataVIO) == VIO_PACKING);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool mayWriteCompressedDataVIO(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  advanceStatus(dataVIO);
Packit Service 310c69
  return !getCompressionState(dataVIO).mayNotCompress;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void setCompressionDone(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  for (;;) {
Packit Service 310c69
    VIOCompressionState state = getCompressionState(dataVIO);
Packit Service 310c69
    if (state.status == VIO_POST_PACKER) {
Packit Service 310c69
      // The VIO is already done.
Packit Service 310c69
      return;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    // If compression was cancelled on this VIO, preserve that fact.
Packit Service 310c69
    VIOCompressionState newState = {
Packit Service 310c69
      .status         = VIO_POST_PACKER,
Packit Service 310c69
      .mayNotCompress = true,
Packit Service 310c69
    };
Packit Service 310c69
    if (setCompressionState(dataVIO, state, newState)) {
Packit Service 310c69
      return;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool cancelCompression(DataVIO *dataVIO)
Packit Service 310c69
{
Packit Service 310c69
  VIOCompressionState state;
Packit Service 310c69
  for (;;) {
Packit Service 310c69
    state = getCompressionState(dataVIO);
Packit Service 310c69
    if (state.mayNotCompress || (state.status == VIO_POST_PACKER)) {
Packit Service 310c69
      // This DataVIO is already set up to not block in the packer.
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    VIOCompressionState newState = {
Packit Service 310c69
      .status         = state.status,
Packit Service 310c69
      .mayNotCompress = true,
Packit Service 310c69
    };
Packit Service 310c69
    if (setCompressionState(dataVIO, state, newState)) {
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return ((state.status == VIO_PACKING) && !state.mayNotCompress);
Packit Service 310c69
}