Blame source/uds/deltaMemory.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/uds-releases/jasper/src/uds/deltaMemory.c#3 $
Packit Service 310c69
 */
Packit Service 310c69
#include "deltaMemory.h"
Packit Service 310c69
Packit Service 310c69
#include "bits.h"
Packit Service 310c69
#include "buffer.h"
Packit Service 310c69
#include "compiler.h"
Packit Service 310c69
#include "errors.h"
Packit Service 310c69
#include "hashUtils.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
#include "timeUtils.h"
Packit Service 310c69
#include "typeDefs.h"
Packit Service 310c69
#include "uds.h"
Packit Service 310c69
Packit Service 310c69
/*
Packit Service 310c69
 * The DeltaMemory structure manages the memory that stores delta lists.
Packit Service 310c69
 *
Packit Service 310c69
 * The "mutable" form of DeltaMemory is used for the master index and for
Packit Service 310c69
 * an open chapter index.  The "immutable" form of DeltaMemory is used for
Packit Service 310c69
 * regular chapter indices.
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
// This is the number of guard bits that are needed in the tail guard list
Packit Service 310c69
enum { GUARD_BITS = POST_FIELD_GUARD_BYTES * CHAR_BIT };
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the offset of the first byte that a delta list bit stream resides in
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaList  The delta list
Packit Service 310c69
 *
Packit Service 310c69
 * @return the number byte offset
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE uint64_t getDeltaListByteStart(const DeltaList *deltaList)
Packit Service 310c69
{
Packit Service 310c69
  return getDeltaListStart(deltaList) / CHAR_BIT;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the actual number of bytes that a delta list bit stream resides in
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaList  The delta list
Packit Service 310c69
 *
Packit Service 310c69
 * @return the number of bytes
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE uint16_t getDeltaListByteSize(const DeltaList *deltaList)
Packit Service 310c69
{
Packit Service 310c69
  uint16_t startBitOffset = getDeltaListStart(deltaList) % CHAR_BIT;
Packit Service 310c69
  uint16_t bitSize = getDeltaListSize(deltaList);
Packit Service 310c69
  return ((unsigned int) startBitOffset + bitSize + CHAR_BIT - 1) / CHAR_BIT;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the number of bytes in the delta lists headers.
Packit Service 310c69
 *
Packit Service 310c69
 * @param numLists  The number of delta lists
Packit Service 310c69
 *
Packit Service 310c69
 * @return the number of bytes in the delta lists headers
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE size_t getSizeOfDeltaLists(unsigned int numLists)
Packit Service 310c69
{
Packit Service 310c69
  return (numLists + 2) * sizeof(DeltaList);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the size of the flags array (in bytes)
Packit Service 310c69
 *
Packit Service 310c69
 * @param numLists  The number of delta lists
Packit Service 310c69
 *
Packit Service 310c69
 * @return the number of bytes for an array that has one bit per delta
Packit Service 310c69
 *         list, plus the necessary guard bytes.
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE size_t getSizeOfFlags(unsigned int numLists)
Packit Service 310c69
{
Packit Service 310c69
  return (numLists + CHAR_BIT - 1) / CHAR_BIT + POST_FIELD_GUARD_BYTES;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the number of bytes of scratch memory for the delta lists.
Packit Service 310c69
 *
Packit Service 310c69
 * @param numLists  The number of delta lists
Packit Service 310c69
 *
Packit Service 310c69
 * @return the number of bytes of scratch memory for the delta lists
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE size_t getSizeOfTempOffsets(unsigned int numLists)
Packit Service 310c69
{
Packit Service 310c69
  return (numLists + 2) * sizeof(uint64_t);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Clear the transfers flags.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaMemory  The delta memory
Packit Service 310c69
 **/
Packit Service 310c69
static void clearTransferFlags(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  memset(deltaMemory->flags, 0, getSizeOfFlags(deltaMemory->numLists));
Packit Service 310c69
  deltaMemory->numTransfers = 0;
Packit Service 310c69
  deltaMemory->transferStatus = UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Set the transfer flags for delta lists that are not empty, and count how
Packit Service 310c69
 * many there are.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaMemory  The delta memory
Packit Service 310c69
 **/
Packit Service 310c69
static void flagNonEmptyDeltaLists(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  clearTransferFlags(deltaMemory);
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < deltaMemory->numLists; i++) {
Packit Service 310c69
    if (getDeltaListSize(&deltaMemory->deltaLists[i + 1]) > 0) {
Packit Service 310c69
      setOne(deltaMemory->flags, i, 1);
Packit Service 310c69
      deltaMemory->numTransfers++;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void emptyDeltaLists(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  // Zero all the delta list headers
Packit Service 310c69
  DeltaList *deltaLists = deltaMemory->deltaLists;
Packit Service 310c69
  memset(deltaLists, 0, getSizeOfDeltaLists(deltaMemory->numLists));
Packit Service 310c69
Packit Service 310c69
  /*
Packit Service 310c69
   * Initialize delta lists to be empty. We keep 2 extra delta list
Packit Service 310c69
   * descriptors, one before the first real entry and one after so that we
Packit Service 310c69
   * don't need to bounds check the array access when calculating
Packit Service 310c69
   * preceeding and following gap sizes.
Packit Service 310c69
   *
Packit Service 310c69
   * Because the delta list headers were zeroed, the head guard list is
Packit Service 310c69
   * already at offset zero and size zero.
Packit Service 310c69
   *
Packit Service 310c69
   * The end guard list contains guard bytes so that the bit field
Packit Service 310c69
   * utilities can safely read past the end of any byte we are interested
Packit Service 310c69
   * in.
Packit Service 310c69
   */
Packit Service 310c69
  uint64_t numBits = (uint64_t) deltaMemory->size * CHAR_BIT;
Packit Service 310c69
  deltaLists[deltaMemory->numLists + 1].startOffset = numBits - GUARD_BITS;
Packit Service 310c69
  deltaLists[deltaMemory->numLists + 1].size        = GUARD_BITS;
Packit Service 310c69
Packit Service 310c69
  // Set all the bits in the end guard list.  Do not use the bit field
Packit Service 310c69
  // utilities.
Packit Service 310c69
  memset(deltaMemory->memory + deltaMemory->size - POST_FIELD_GUARD_BYTES,
Packit Service 310c69
         ~0, POST_FIELD_GUARD_BYTES);
Packit Service 310c69
Packit Service 310c69
  // Evenly space out the real delta lists.  The sizes are already zero, so
Packit Service 310c69
  // we just need to set the starting offsets.
Packit Service 310c69
  uint64_t spacing = (numBits - GUARD_BITS) / deltaMemory->numLists;
Packit Service 310c69
  uint64_t offset = spacing / 2;
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 1; i <= deltaMemory->numLists; i++) {
Packit Service 310c69
    deltaLists[i].startOffset = offset;
Packit Service 310c69
    offset += spacing;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Update the statistics
Packit Service 310c69
  deltaMemory->discardCount  += deltaMemory->recordCount;
Packit Service 310c69
  deltaMemory->recordCount    = 0;
Packit Service 310c69
  deltaMemory->collisionCount = 0;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
/**
Packit Service 310c69
 * Compute the Huffman coding parameters for the given mean delta
Packit Service 310c69
 *
Packit Service 310c69
 * @param meanDelta  The mean delta value
Packit Service 310c69
 * @param minBits    The number of bits in the minimal key code
Packit Service 310c69
 * @param minKeys    The number of keys used in a minimal code
Packit Service 310c69
 * @param incrKeys   The number of keys used for another code bit
Packit Service 310c69
 **/
Packit Service 310c69
static void computeCodingConstants(unsigned int    meanDelta,
Packit Service 310c69
                                   unsigned short *minBits,
Packit Service 310c69
                                   unsigned int   *minKeys,
Packit Service 310c69
                                   unsigned int   *incrKeys)
Packit Service 310c69
{
Packit Service 310c69
  // We want to compute the rounded value of log(2) * meanDelta.  Since we
Packit Service 310c69
  // cannot always use floating point, use a really good integer approximation.
Packit Service 310c69
  *incrKeys = (836158UL * meanDelta + 603160UL) / 1206321UL;
Packit Service 310c69
  *minBits  = computeBits(*incrKeys + 1);
Packit Service 310c69
  *minKeys  = (1 << *minBits) - *incrKeys;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
/**
Packit Service 310c69
 * Rebalance a range of delta lists within memory.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaMemory  A delta memory structure
Packit Service 310c69
 * @param first        The first delta list index
Packit Service 310c69
 * @param last         The last delta list index
Packit Service 310c69
 **/
Packit Service 310c69
static void rebalanceDeltaMemory(const DeltaMemory *deltaMemory,
Packit Service 310c69
                                 unsigned int first, unsigned int last)
Packit Service 310c69
{
Packit Service 310c69
  if (first == last) {
Packit Service 310c69
    DeltaList *deltaList = &deltaMemory->deltaLists[first];
Packit Service 310c69
    uint64_t newStart = deltaMemory->tempOffsets[first];
Packit Service 310c69
    // We need to move only one list, and we know it is safe to do so
Packit Service 310c69
    if (getDeltaListStart(deltaList) != newStart) {
Packit Service 310c69
      // Compute the first source byte
Packit Service 310c69
      uint64_t source = getDeltaListByteStart(deltaList);
Packit Service 310c69
      // Update the delta list location
Packit Service 310c69
      deltaList->startOffset = newStart;
Packit Service 310c69
      // Now use the same computation to locate the first destination byte
Packit Service 310c69
      uint64_t destination = getDeltaListByteStart(deltaList);
Packit Service 310c69
      memmove(deltaMemory->memory + destination, deltaMemory->memory + source,
Packit Service 310c69
              getDeltaListByteSize(deltaList));
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    // There is more than one list.  Divide the problem in half, and use
Packit Service 310c69
    // recursive calls to process each half.  Note that after this
Packit Service 310c69
    // computation, first <= middle, and middle < last.
Packit Service 310c69
    unsigned int middle = (first + last) / 2;
Packit Service 310c69
    const DeltaList *deltaList = &deltaMemory->deltaLists[middle];
Packit Service 310c69
    uint64_t newStart = deltaMemory->tempOffsets[middle];
Packit Service 310c69
    // The direction that our middle list is moving determines which half
Packit Service 310c69
    // of the problem must be processed first.
Packit Service 310c69
    if (newStart > getDeltaListStart(deltaList)) {
Packit Service 310c69
      rebalanceDeltaMemory(deltaMemory, middle + 1, last);
Packit Service 310c69
      rebalanceDeltaMemory(deltaMemory, first, middle);
Packit Service 310c69
    } else {
Packit Service 310c69
      rebalanceDeltaMemory(deltaMemory, first, middle);
Packit Service 310c69
      rebalanceDeltaMemory(deltaMemory, middle + 1, last);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int initializeDeltaMemory(DeltaMemory *deltaMemory, size_t size,
Packit Service 310c69
                          unsigned int firstList, unsigned int numLists,
Packit Service 310c69
                          unsigned int meanDelta, unsigned int numPayloadBits)
Packit Service 310c69
{
Packit Service 310c69
  if (numLists == 0) {
Packit Service 310c69
    return logWarningWithStringError(UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                     "cannot initialize delta memory with 0 "
Packit Service 310c69
                                     "delta lists");
Packit Service 310c69
  }
Packit Service 310c69
  byte *memory = NULL;
Packit Service 310c69
  int result = ALLOCATE(size, byte, "delta list", &memory);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  uint64_t *tempOffsets = NULL;
Packit Service 310c69
  result = ALLOCATE(numLists + 2, uint64_t, "delta list temp",
Packit Service 310c69
                    &tempOffsets);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(memory);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  byte *flags = NULL;
Packit Service 310c69
  result = ALLOCATE(getSizeOfFlags(numLists), byte, "delta list flags",
Packit Service 310c69
                    &flags);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    FREE(memory);
Packit Service 310c69
    FREE(tempOffsets);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  computeCodingConstants(meanDelta, &deltaMemory->minBits,
Packit Service 310c69
                         &deltaMemory->minKeys, &deltaMemory->incrKeys);
Packit Service 310c69
  deltaMemory->valueBits       = numPayloadBits;
Packit Service 310c69
  deltaMemory->memory          = memory;
Packit Service 310c69
  deltaMemory->deltaLists      = NULL;
Packit Service 310c69
  deltaMemory->tempOffsets     = tempOffsets;
Packit Service 310c69
  deltaMemory->flags           = flags;
Packit Service 310c69
  deltaMemory->bufferedWriter  = NULL;
Packit Service 310c69
  deltaMemory->size            = size;
Packit Service 310c69
  deltaMemory->rebalanceTime   = 0;
Packit Service 310c69
  deltaMemory->rebalanceCount  = 0;
Packit Service 310c69
  deltaMemory->recordCount     = 0;
Packit Service 310c69
  deltaMemory->collisionCount  = 0;
Packit Service 310c69
  deltaMemory->discardCount    = 0;
Packit Service 310c69
  deltaMemory->overflowCount   = 0;
Packit Service 310c69
  deltaMemory->firstList       = firstList;
Packit Service 310c69
  deltaMemory->numLists        = numLists;
Packit Service 310c69
  deltaMemory->numTransfers    = 0;
Packit Service 310c69
  deltaMemory->transferStatus  = UDS_SUCCESS;
Packit Service 310c69
  deltaMemory->tag             = 'm';
Packit Service 310c69
Packit Service 310c69
  // Allocate the delta lists.
Packit Service 310c69
  result = ALLOCATE(deltaMemory->numLists + 2, DeltaList,
Packit Service 310c69
                    "delta lists", &deltaMemory->deltaLists);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    uninitializeDeltaMemory(deltaMemory);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  emptyDeltaLists(deltaMemory);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void uninitializeDeltaMemory(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  FREE(deltaMemory->flags);
Packit Service 310c69
  deltaMemory->flags = NULL;
Packit Service 310c69
  FREE(deltaMemory->tempOffsets);
Packit Service 310c69
  deltaMemory->tempOffsets = NULL;
Packit Service 310c69
  FREE(deltaMemory->deltaLists);
Packit Service 310c69
  deltaMemory->deltaLists = NULL;
Packit Service 310c69
  FREE(deltaMemory->memory);
Packit Service 310c69
  deltaMemory->memory = NULL;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void initializeDeltaMemoryPage(DeltaMemory *deltaMemory, byte *memory,
Packit Service 310c69
                               size_t size, unsigned int numLists,
Packit Service 310c69
                               unsigned int meanDelta,
Packit Service 310c69
                               unsigned int numPayloadBits)
Packit Service 310c69
{
Packit Service 310c69
  computeCodingConstants(meanDelta, &deltaMemory->minBits,
Packit Service 310c69
                         &deltaMemory->minKeys, &deltaMemory->incrKeys);
Packit Service 310c69
  deltaMemory->valueBits       = numPayloadBits;
Packit Service 310c69
  deltaMemory->memory          = memory;
Packit Service 310c69
  deltaMemory->deltaLists      = NULL;
Packit Service 310c69
  deltaMemory->tempOffsets     = NULL;
Packit Service 310c69
  deltaMemory->flags           = NULL;
Packit Service 310c69
  deltaMemory->bufferedWriter  = NULL;
Packit Service 310c69
  deltaMemory->size            = size;
Packit Service 310c69
  deltaMemory->rebalanceTime   = 0;
Packit Service 310c69
  deltaMemory->rebalanceCount  = 0;
Packit Service 310c69
  deltaMemory->recordCount     = 0;
Packit Service 310c69
  deltaMemory->collisionCount  = 0;
Packit Service 310c69
  deltaMemory->discardCount    = 0;
Packit Service 310c69
  deltaMemory->overflowCount   = 0;
Packit Service 310c69
  deltaMemory->firstList       = 0;
Packit Service 310c69
  deltaMemory->numLists        = numLists;
Packit Service 310c69
  deltaMemory->numTransfers    = 0;
Packit Service 310c69
  deltaMemory->transferStatus  = UDS_SUCCESS;
Packit Service 310c69
  deltaMemory->tag             = 'p';
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool areDeltaMemoryTransfersDone(const DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  return deltaMemory->numTransfers == 0;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int startRestoringDeltaMemory(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  // Extend and balance memory to receive the delta lists
Packit Service 310c69
  int result = extendDeltaMemory(deltaMemory, 0, 0, false);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return UDS_SUCCESS;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // The tail guard list needs to be set to ones
Packit Service 310c69
  DeltaList *deltaList = &deltaMemory->deltaLists[deltaMemory->numLists + 1];
Packit Service 310c69
  setOne(deltaMemory->memory, getDeltaListStart(deltaList),
Packit Service 310c69
         getDeltaListSize(deltaList));
Packit Service 310c69
Packit Service 310c69
  flagNonEmptyDeltaLists(deltaMemory);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int readDeltaListSaveInfo(BufferedReader *reader,
Packit Service 310c69
                                 DeltaListSaveInfo *dlsi)
Packit Service 310c69
{
Packit Service 310c69
  byte buffer[sizeof(DeltaListSaveInfo)];
Packit Service 310c69
  int result = readFromBufferedReader(reader, buffer, sizeof(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  dlsi->tag =  buffer[0];
Packit Service 310c69
  dlsi->bitOffset = buffer[1];
Packit Service 310c69
  dlsi->byteCount = getUInt16LE(&buffer[2]);
Packit Service 310c69
  dlsi->index = getUInt32LE(&buffer[4]);
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int readSavedDeltaList(DeltaListSaveInfo *dlsi,
Packit Service 310c69
                       byte data[DELTA_LIST_MAX_BYTE_COUNT],
Packit Service 310c69
                       BufferedReader *bufferedReader)
Packit Service 310c69
{
Packit Service 310c69
  int result = readDeltaListSaveInfo(bufferedReader, dlsi);
Packit Service 310c69
  if (result == UDS_END_OF_FILE) {
Packit Service 310c69
    return UDS_END_OF_FILE;
Packit Service 310c69
  }
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logWarningWithStringError(result, "failed to read delta list data");
Packit Service 310c69
  }
Packit Service 310c69
  if ((dlsi->bitOffset >= CHAR_BIT)
Packit Service 310c69
      || (dlsi->byteCount > DELTA_LIST_MAX_BYTE_COUNT)) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "corrupt delta list data");
Packit Service 310c69
  }
Packit Service 310c69
  if (dlsi->tag == 'z') {
Packit Service 310c69
    return UDS_END_OF_FILE;
Packit Service 310c69
  }
Packit Service 310c69
  result = readFromBufferedReader(bufferedReader, data, dlsi->byteCount);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logWarningWithStringError(result, "failed to read delta list data");
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int restoreDeltaList(DeltaMemory *deltaMemory, const DeltaListSaveInfo *dlsi,
Packit Service 310c69
                     const byte data[DELTA_LIST_MAX_BYTE_COUNT])
Packit Service 310c69
{
Packit Service 310c69
  unsigned int listNumber = dlsi->index - deltaMemory->firstList;
Packit Service 310c69
  if (listNumber >= deltaMemory->numLists) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "invalid delta list number %u not in"
Packit Service 310c69
                                     " range [%u,%u)",
Packit Service 310c69
                                     dlsi->index, deltaMemory->firstList,
Packit Service 310c69
                                     deltaMemory->firstList
Packit Service 310c69
                                     + deltaMemory->numLists);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (getField(deltaMemory->flags, listNumber, 1) == 0) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "unexpected delta list number %u",
Packit Service 310c69
                                     dlsi->index);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DeltaList *deltaList = &deltaMemory->deltaLists[listNumber + 1];
Packit Service 310c69
  uint16_t bitSize = getDeltaListSize(deltaList);
Packit Service 310c69
  unsigned int byteCount
Packit Service 310c69
    = ((unsigned int) dlsi->bitOffset + bitSize + CHAR_BIT - 1) / CHAR_BIT;
Packit Service 310c69
  if (dlsi->byteCount != byteCount) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "unexpected delta list size %u != %u",
Packit Service 310c69
                                     dlsi->byteCount, byteCount);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  moveBits(data, dlsi->bitOffset, deltaMemory->memory,
Packit Service 310c69
           getDeltaListStart(deltaList), bitSize);
Packit Service 310c69
  setZero(deltaMemory->flags, listNumber, 1);
Packit Service 310c69
  deltaMemory->numTransfers--;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void abortRestoringDeltaMemory(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  clearTransferFlags(deltaMemory);
Packit Service 310c69
  emptyDeltaLists(deltaMemory);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void startSavingDeltaMemory(DeltaMemory *deltaMemory,
Packit Service 310c69
                            BufferedWriter *bufferedWriter)
Packit Service 310c69
{
Packit Service 310c69
  flagNonEmptyDeltaLists(deltaMemory);
Packit Service 310c69
  deltaMemory->bufferedWriter = bufferedWriter;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int finishSavingDeltaMemory(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0;
Packit Service 310c69
       !areDeltaMemoryTransfersDone(deltaMemory)
Packit Service 310c69
         && (i < deltaMemory->numLists);
Packit Service 310c69
       i++) {
Packit Service 310c69
    lazyFlushDeltaList(deltaMemory, i);
Packit Service 310c69
  }
Packit Service 310c69
  if (deltaMemory->numTransfers > 0) {
Packit Service 310c69
    deltaMemory->transferStatus
Packit Service 310c69
      = logWarningWithStringError(UDS_CORRUPT_DATA,
Packit Service 310c69
                                  "Not all delta lists written");
Packit Service 310c69
  }
Packit Service 310c69
  deltaMemory->bufferedWriter = NULL;
Packit Service 310c69
  return deltaMemory->transferStatus;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void abortSavingDeltaMemory(DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  clearTransferFlags(deltaMemory);
Packit Service 310c69
  deltaMemory->bufferedWriter = NULL;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int writeDeltaListSaveInfo(BufferedWriter *bufferedWriter,
Packit Service 310c69
                                  DeltaListSaveInfo *dlsi)
Packit Service 310c69
{
Packit Service 310c69
  byte buffer[sizeof(DeltaListSaveInfo)];
Packit Service 310c69
  buffer[0] = dlsi->tag;
Packit Service 310c69
  buffer[1] = dlsi->bitOffset;
Packit Service 310c69
  storeUInt16LE(&buffer[2], dlsi->byteCount);
Packit Service 310c69
  storeUInt32LE(&buffer[4], dlsi->index);
Packit Service 310c69
  return writeToBufferedWriter(bufferedWriter, buffer, sizeof(buffer));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void flushDeltaList(DeltaMemory *deltaMemory, unsigned int flushIndex)
Packit Service 310c69
{
Packit Service 310c69
  ASSERT_LOG_ONLY((getField(deltaMemory->flags, flushIndex, 1) != 0),
Packit Service 310c69
                  "flush bit is set");
Packit Service 310c69
  setZero(deltaMemory->flags, flushIndex, 1);
Packit Service 310c69
  deltaMemory->numTransfers--;
Packit Service 310c69
Packit Service 310c69
  DeltaList *deltaList = &deltaMemory->deltaLists[flushIndex + 1];
Packit Service 310c69
  DeltaListSaveInfo dlsi;
Packit Service 310c69
  dlsi.tag       = deltaMemory->tag;
Packit Service 310c69
  dlsi.bitOffset = getDeltaListStart(deltaList) % CHAR_BIT;
Packit Service 310c69
  dlsi.byteCount = getDeltaListByteSize(deltaList);
Packit Service 310c69
  dlsi.index     = deltaMemory->firstList + flushIndex;
Packit Service 310c69
Packit Service 310c69
  int result = writeDeltaListSaveInfo(deltaMemory->bufferedWriter, &dlsi);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    if (deltaMemory->transferStatus == UDS_SUCCESS) {
Packit Service 310c69
      logWarningWithStringError(result, "failed to write delta list memory");
Packit Service 310c69
      deltaMemory->transferStatus = result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  result = writeToBufferedWriter(deltaMemory->bufferedWriter,
Packit Service 310c69
                                 deltaMemory->memory
Packit Service 310c69
                                 + getDeltaListByteStart(deltaList),
Packit Service 310c69
                                 dlsi.byteCount);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    if (deltaMemory->transferStatus == UDS_SUCCESS) {
Packit Service 310c69
      logWarningWithStringError(result, "failed to write delta list memory");
Packit Service 310c69
      deltaMemory->transferStatus = result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int writeGuardDeltaList(BufferedWriter *bufferedWriter)
Packit Service 310c69
{
Packit Service 310c69
  DeltaListSaveInfo dlsi;
Packit Service 310c69
  dlsi.tag       = 'z';
Packit Service 310c69
  dlsi.bitOffset = 0;
Packit Service 310c69
  dlsi.byteCount = 0;
Packit Service 310c69
  dlsi.index     = 0;
Packit Service 310c69
  int result = writeToBufferedWriter(bufferedWriter, (const byte *) &dlsi,
Packit Service 310c69
                                     sizeof(DeltaListSaveInfo));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    logWarningWithStringError(result, "failed to write guard delta list");
Packit Service 310c69
  }
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int extendDeltaMemory(DeltaMemory *deltaMemory, unsigned int growingIndex,
Packit Service 310c69
                      size_t growingSize, bool doCopy)
Packit Service 310c69
{
Packit Service 310c69
  if (!isMutable(deltaMemory)) {
Packit Service 310c69
    return logErrorWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                   "Attempt to read into an immutable delta"
Packit Service 310c69
                                   " list memory");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  AbsTime startTime = currentTime(CLOCK_MONOTONIC);
Packit Service 310c69
Packit Service 310c69
  // Calculate the amount of space that is in use.  Include the space that
Packit Service 310c69
  // has a planned use.
Packit Service 310c69
  DeltaList *deltaLists = deltaMemory->deltaLists;
Packit Service 310c69
  size_t usedSpace = growingSize;
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i <= deltaMemory->numLists + 1; i++) {
Packit Service 310c69
    usedSpace += getDeltaListByteSize(&deltaLists[i]);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (deltaMemory->size < usedSpace) {
Packit Service 310c69
    return UDS_OVERFLOW;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Compute the new offsets of the delta lists
Packit Service 310c69
  size_t spacing = (deltaMemory->size - usedSpace) / deltaMemory->numLists;
Packit Service 310c69
  deltaMemory->tempOffsets[0] = 0;
Packit Service 310c69
  for (i = 0; i <= deltaMemory->numLists; i++) {
Packit Service 310c69
    deltaMemory->tempOffsets[i + 1] = (deltaMemory->tempOffsets[i]
Packit Service 310c69
                                       + getDeltaListByteSize(&deltaLists[i])
Packit Service 310c69
                                       + spacing);
Packit Service 310c69
    deltaMemory->tempOffsets[i] *= CHAR_BIT;
Packit Service 310c69
    deltaMemory->tempOffsets[i]
Packit Service 310c69
      += getDeltaListStart(&deltaLists[i]) % CHAR_BIT;
Packit Service 310c69
    if (i == 0) {
Packit Service 310c69
      deltaMemory->tempOffsets[i + 1] -= spacing / 2;
Packit Service 310c69
    }
Packit Service 310c69
    if (i + 1 == growingIndex) {
Packit Service 310c69
      deltaMemory->tempOffsets[i + 1] += growingSize;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  deltaMemory->tempOffsets[deltaMemory->numLists + 1]
Packit Service 310c69
    = (deltaMemory->size * CHAR_BIT
Packit Service 310c69
       - getDeltaListSize(&deltaLists[deltaMemory->numLists + 1]));
Packit Service 310c69
  // When we rebalance the delta list, we will include the end guard list
Packit Service 310c69
  // in the rebalancing.  It contains the end guard data, which must be
Packit Service 310c69
  // copied.
Packit Service 310c69
  if (doCopy) {
Packit Service 310c69
    rebalanceDeltaMemory(deltaMemory, 1, deltaMemory->numLists + 1);
Packit Service 310c69
    AbsTime endTime = currentTime(CLOCK_MONOTONIC);
Packit Service 310c69
    deltaMemory->rebalanceCount++;
Packit Service 310c69
    deltaMemory->rebalanceTime += timeDifference(endTime, startTime);
Packit Service 310c69
  } else {
Packit Service 310c69
    for (i = 1; i <= deltaMemory->numLists + 1; i++) {
Packit Service 310c69
      deltaLists[i].startOffset = deltaMemory->tempOffsets[i];
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int validateDeltaLists(const DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  // Validate the delta index fields set by restoring a delta index
Packit Service 310c69
  if (deltaMemory->collisionCount > deltaMemory->recordCount) {
Packit Service 310c69
    return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                     "delta index contains more collisions"
Packit Service 310c69
                                     " (%ld) than records (%ld)",
Packit Service 310c69
                                     deltaMemory->collisionCount,
Packit Service 310c69
                                     deltaMemory->recordCount);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Validate the delta lists
Packit Service 310c69
  DeltaList *deltaLists = deltaMemory->deltaLists;
Packit Service 310c69
  if (getDeltaListStart(&deltaLists[0]) != 0) {
Packit Service 310c69
    return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                     "the head guard delta list does not start"
Packit Service 310c69
                                     " at 0: %llu",
Packit Service 310c69
                                     getDeltaListStart(&deltaLists[0]));
Packit Service 310c69
  }
Packit Service 310c69
  uint64_t numBits = getDeltaListEnd(&deltaLists[deltaMemory->numLists + 1]);
Packit Service 310c69
  if (numBits != deltaMemory->size * CHAR_BIT) {
Packit Service 310c69
    return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                     "the tail guard delta list does not end "
Packit Service 310c69
                                     "at end of allocated memory:  %" PRIu64
Packit Service 310c69
                                     " != %zd",
Packit Service 310c69
                                     numBits, deltaMemory->size * CHAR_BIT);
Packit Service 310c69
  }
Packit Service 310c69
  int numGuardBits = getDeltaListSize(&deltaLists[deltaMemory->numLists + 1]);
Packit Service 310c69
  if (numGuardBits < GUARD_BITS) {
Packit Service 310c69
    return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                     "the tail guard delta list does not "
Packit Service 310c69
                                     "contain sufficient guard bits:  %d < %d",
Packit Service 310c69
                                     numGuardBits, GUARD_BITS);
Packit Service 310c69
  }
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i <= deltaMemory->numLists + 1; i++) {
Packit Service 310c69
    if (getDeltaListStart(&deltaLists[i]) > getDeltaListEnd(&deltaLists[i])) {
Packit Service 310c69
      return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                       "invalid delta list %u: [%" PRIu64
Packit Service 310c69
                                       ", %llu)",
Packit Service 310c69
                                       i,
Packit Service 310c69
                                       getDeltaListStart(&deltaLists[i]),
Packit Service 310c69
                                       getDeltaListEnd(&deltaLists[i]));
Packit Service 310c69
    }
Packit Service 310c69
    if (i > deltaMemory->numLists) {
Packit Service 310c69
      // The rest of the checks do not apply to the tail guard list
Packit Service 310c69
      continue;
Packit Service 310c69
    }
Packit Service 310c69
    if (getDeltaListEnd(&deltaLists[i])
Packit Service 310c69
        > getDeltaListStart(&deltaLists[i + 1])) {
Packit Service 310c69
      return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                       "delta lists %u and %u overlap:  %"
Packit Service 310c69
                                       PRIu64 " > %llu",
Packit Service 310c69
                                       i, i + 1,
Packit Service 310c69
                                       getDeltaListEnd(&deltaLists[i]),
Packit Service 310c69
                                       getDeltaListStart(&deltaLists[i + 1]));
Packit Service 310c69
    }
Packit Service 310c69
    if (i == 0) {
Packit Service 310c69
      // The rest of the checks do not apply to the head guard list
Packit Service 310c69
      continue;
Packit Service 310c69
    }
Packit Service 310c69
    if (deltaLists[i].saveOffset > getDeltaListSize(&deltaLists[i])) {
Packit Service 310c69
      return logWarningWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                       "delta lists %u saved offset is larger"
Packit Service 310c69
                                       " than the list:  %u > %u",
Packit Service 310c69
                                       i, deltaLists[i].saveOffset,
Packit Service 310c69
                                       getDeltaListSize(&deltaLists[i]));
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
size_t getDeltaMemoryAllocated(const DeltaMemory *deltaMemory)
Packit Service 310c69
{
Packit Service 310c69
  return (deltaMemory->size
Packit Service 310c69
          + getSizeOfDeltaLists(deltaMemory->numLists)
Packit Service 310c69
          + getSizeOfFlags(deltaMemory->numLists)
Packit Service 310c69
          + getSizeOfTempOffsets(deltaMemory->numLists));
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
size_t getDeltaMemorySize(unsigned long numEntries, unsigned int meanDelta,
Packit Service 310c69
                          unsigned int numPayloadBits)
Packit Service 310c69
{
Packit Service 310c69
  unsigned short minBits;
Packit Service 310c69
  unsigned int incrKeys, minKeys;
Packit Service 310c69
  computeCodingConstants(meanDelta, &minBits, &minKeys, &incrKeys);
Packit Service 310c69
  // On average, each delta is encoded into about minBits+1.5 bits.
Packit Service 310c69
  return (numEntries * (numPayloadBits + minBits + 1) + numEntries / 2);
Packit Service 310c69
}