Blame source/uds/deltaIndex.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/deltaIndex.c#7 $
Packit Service 310c69
 */
Packit Service 310c69
#include "deltaIndex.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 "cpu.h"
Packit Service 310c69
#include "errors.h"
Packit Service 310c69
#include "logger.h"
Packit Service 310c69
#include "memoryAlloc.h"
Packit Service 310c69
#include "permassert.h"
Packit Service 310c69
#include "stringUtils.h"
Packit Service 310c69
#include "typeDefs.h"
Packit Service 310c69
#include "uds.h"
Packit Service 310c69
#include "zone.h"
Packit Service 310c69
Packit Service 310c69
/*
Packit Service 310c69
 * A delta index is a key-value store, where each entry maps an address
Packit Service 310c69
 * (the key) to a payload (the value).  The entries are sorted by address,
Packit Service 310c69
 * and only the delta between successive addresses is stored in the entry.
Packit Service 310c69
 * The addresses are assumed to be uniformly distributed,and the deltas are
Packit Service 310c69
 * therefore exponentially distributed.
Packit Service 310c69
 *
Packit Service 310c69
 * The entries could be stored in a single DeltaList, but for efficiency we
Packit Service 310c69
 * use multiple DeltaLists.  These lists are stored in a single chunk of
Packit Service 310c69
 * memory managed by the DeltaMemory module.  The DeltaMemory module can
Packit Service 310c69
 * move the data around in memory, so we never keep any byte pointers into
Packit Service 310c69
 * DeltaList memory.  We only keep offsets into the memory.
Packit Service 310c69
 *
Packit Service 310c69
 * The delta lists are stored as bit streams.  These bit streams are stored
Packit Service 310c69
 * in little endian order, and all offsets into DeltaMemory are bit
Packit Service 310c69
 * offsets.
Packit Service 310c69
 *
Packit Service 310c69
 * All entries are stored as a fixed length payload (the value) followed by a
Packit Service 310c69
 * variable length key (the delta). Always strictly in little endian order.
Packit Service 310c69
 *
Packit Service 310c69
 * A collision entry is used when two block names have the same delta list
Packit Service 310c69
 * address.  A collision entry is encoded with DELTA==0, and has 256
Packit Service 310c69
 * extension bits containing the full block name.
Packit Service 310c69
 *
Packit Service 310c69
 * There is a special exception to be noted.  The DELTA==0 encoding usually
Packit Service 310c69
 * indicates a collision with the preceding entry.  But for the first entry
Packit Service 310c69
 * in any delta list there is no preceding entry, so the DELTA==0 encoding
Packit Service 310c69
 * at the beginning of a delta list indicates a normal entry.
Packit Service 310c69
 *
Packit Service 310c69
 * The Huffman code is driven by 3 parameters:
Packit Service 310c69
 *
Packit Service 310c69
 *  MINBITS   This is the number of bits in the smallest code
Packit Service 310c69
 *
Packit Service 310c69
 *  BASE      This is the number of values coded using a code of length MINBITS
Packit Service 310c69
 *
Packit Service 310c69
 *  INCR      This is the number of values coded by using one additional bit.
Packit Service 310c69
 *
Packit Service 310c69
 * These parameters are related by:
Packit Service 310c69
 *
Packit Service 310c69
 *       BASE + INCR == 1 << MINBITS
Packit Service 310c69
 *
Packit Service 310c69
 * When we create an index, we need to know the mean delta.  From the mean
Packit Service 310c69
 * delta, we compute these three parameters.  The math for the Huffman code
Packit Service 310c69
 * of an exponential distribution says that we compute:
Packit Service 310c69
 *
Packit Service 310c69
 *      INCR = log(2) * MEAN_DELTA
Packit Service 310c69
 *
Packit Service 310c69
 * Then we find the smallest MINBITS so that
Packit Service 310c69
 *
Packit Service 310c69
 *      1 << MINBITS  >  INCR
Packit Service 310c69
 *
Packit Service 310c69
 * And then:
Packit Service 310c69
 *
Packit Service 310c69
 *       BASE = (1 << MINBITS) - INCR
Packit Service 310c69
 *
Packit Service 310c69
 * Now we need a code such that
Packit Service 310c69
 *
Packit Service 310c69
 * - The first BASE values code using MINBITS bits
Packit Service 310c69
 * - The next INCR values code using MINBITS+1 bits.
Packit Service 310c69
 * - The next INCR values code using MINBITS+2 bits.
Packit Service 310c69
 * - The next INCR values code using MINBITS+3 bits.
Packit Service 310c69
 * - (and so on).
Packit Service 310c69
 *
Packit Service 310c69
 * ENCODE(DELTA):
Packit Service 310c69
 *
Packit Service 310c69
 *   if (DELTA < BASE) {
Packit Service 310c69
 *       put DELTA in MINBITS bits;
Packit Service 310c69
 *   } else {
Packit Service 310c69
 *       T1 = (DELTA - BASE) % INCR + BASE;
Packit Service 310c69
 *       T2 = (DELTA - BASE) / INCR;
Packit Service 310c69
 *       put T1 in MINBITS bits;
Packit Service 310c69
 *       put 0 in T2 bits;
Packit Service 310c69
 *       put 1 in 1 bit;
Packit Service 310c69
 *   }
Packit Service 310c69
 *
Packit Service 310c69
 * DECODE(BIT_STREAM):
Packit Service 310c69
 *
Packit Service 310c69
 *   T1 = next MINBITS bits of stream;
Packit Service 310c69
 *   if (T1 < BASE) {
Packit Service 310c69
 *       DELTA = T1;
Packit Service 310c69
 *   } else {
Packit Service 310c69
 *       Scan bits in the stream until reading a 1,
Packit Service 310c69
 *         setting T2 to the number of 0 bits read;
Packit Service 310c69
 *       DELTA = T2 * INCR + T1;
Packit Service 310c69
 *   }
Packit Service 310c69
 *
Packit Service 310c69
 * The bit field utilities that we use on the delta lists assume that it is
Packit Service 310c69
 * possible to read a few bytes beyond the end of the bit field.  So we
Packit Service 310c69
 * make sure to allocates some extra bytes at the end of memory containing
Packit Service 310c69
 * the delta lists.  Look for POST_FIELD_GUARD_BYTES to find the code
Packit Service 310c69
 * related to this.
Packit Service 310c69
 *
Packit Service 310c69
 * And note that the decode bit stream code includes a step that skips over
Packit Service 310c69
 * 0 bits until the first 1 bit is found.  A corrupted delta list could
Packit Service 310c69
 * cause this step to run off the end of the delta list memory.  As an
Packit Service 310c69
 * extra protection against this happening, the guard bytes at the end
Packit Service 310c69
 * should be set to all ones.
Packit Service 310c69
 */
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Constants and structures for the saved delta index. "DI" is for
Packit Service 310c69
 * deltaIndex, and -##### is a number to increment when the format of the
Packit Service 310c69
 * data changes.
Packit Service 310c69
 **/
Packit Service 310c69
enum { MAGIC_SIZE = 8 };
Packit Service 310c69
static const char MAGIC_DI_START[] = "DI-00002";
Packit Service 310c69
Packit Service 310c69
struct di_header {
Packit Service 310c69
  char     magic[MAGIC_SIZE];   // MAGIC_DI_START
Packit Service 310c69
  uint32_t zoneNumber;
Packit Service 310c69
  uint32_t numZones;
Packit Service 310c69
  uint32_t firstList;
Packit Service 310c69
  uint32_t numLists;
Packit Service 310c69
  uint64_t recordCount;
Packit Service 310c69
  uint64_t collisionCount;
Packit Service 310c69
};
Packit Service 310c69
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
//  Methods for dealing with mutable delta list headers
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Move the start of the delta list bit stream without moving the end.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaList  The delta list header
Packit Service 310c69
 * @param increment  The change in the start of the delta list
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE void moveDeltaListStart(DeltaList *deltaList, int increment)
Packit Service 310c69
{
Packit Service 310c69
  deltaList->startOffset += increment;
Packit Service 310c69
  deltaList->size        -= increment;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Move the end of the delta list bit stream without moving the start.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaList  The delta list header
Packit Service 310c69
 * @param increment  The change in the end of the delta list
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE void moveDeltaListEnd(DeltaList *deltaList, int increment)
Packit Service 310c69
{
Packit Service 310c69
  deltaList->size += increment;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
//  Methods for dealing with immutable delta list headers packed
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
Packit Service 310c69
// Header data used for immutable delta index pages.  These data are
Packit Service 310c69
// followed by the delta list offset table.
Packit Service 310c69
typedef struct __attribute__((packed)) deltaPageHeader {
Packit Service 310c69
  uint64_t nonce;                 // Externally-defined nonce
Packit Service 310c69
  uint64_t virtualChapterNumber;  // The virtual chapter number
Packit Service 310c69
  uint16_t firstList;             // Index of the first delta list on the page
Packit Service 310c69
  uint16_t numLists;              // Number of delta lists on the page
Packit Service 310c69
} DeltaPageHeader;
Packit Service 310c69
Packit Service 310c69
// Immutable delta lists are packed into pages containing a header that
Packit Service 310c69
// encodes the delta list information into 19 bits per list (64KB bit offset)
Packit Service 310c69
Packit Service 310c69
enum { IMMUTABLE_HEADER_SIZE = 19 };
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the bit offset to the immutable delta list header
Packit Service 310c69
 *
Packit Service 310c69
 * @param listNumber  The delta list number
Packit Service 310c69
 *
Packit Service 310c69
 * @return the offset of immutable delta list header
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE unsigned int getImmutableHeaderOffset(unsigned int listNumber)
Packit Service 310c69
{
Packit Service 310c69
  return (sizeof(DeltaPageHeader) * CHAR_BIT
Packit Service 310c69
          + listNumber * IMMUTABLE_HEADER_SIZE);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the bit offset to the start of the immutable delta list bit stream
Packit Service 310c69
 *
Packit Service 310c69
 * @param memory      The memory page containing the delta lists
Packit Service 310c69
 * @param listNumber  The delta list number
Packit Service 310c69
 *
Packit Service 310c69
 * @return the start of the delta list
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE unsigned int getImmutableStart(const byte *memory,
Packit Service 310c69
                                             unsigned int listNumber)
Packit Service 310c69
{
Packit Service 310c69
  return getField(memory, getImmutableHeaderOffset(listNumber),
Packit Service 310c69
                  IMMUTABLE_HEADER_SIZE);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Set the bit offset to the start of the immutable delta list bit stream
Packit Service 310c69
 *
Packit Service 310c69
 * @param memory       The memory page containing the delta lists
Packit Service 310c69
 * @param listNumber   The delta list number
Packit Service 310c69
 * @param startOffset  The start of the delta list
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE void setImmutableStart(byte *memory, unsigned int listNumber,
Packit Service 310c69
                                     unsigned int startOffset)
Packit Service 310c69
{
Packit Service 310c69
  setField(startOffset, memory, getImmutableHeaderOffset(listNumber),
Packit Service 310c69
           IMMUTABLE_HEADER_SIZE);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
//  Methods for dealing with Delta List Entries
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Decode a delta index entry delta value. The DeltaIndexEntry basically
Packit Service 310c69
 * describes the previous list entry, and has had its offset field changed to
Packit Service 310c69
 * point to the subsequent entry. We decode the bit stream and update the
Packit Service 310c69
 * DeltaListEntry to describe the entry.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE void decodeDelta(DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  const DeltaMemory *deltaZone = deltaEntry->deltaZone;
Packit Service 310c69
  const byte *memory = deltaZone->memory;
Packit Service 310c69
  uint64_t deltaOffset
Packit Service 310c69
    = getDeltaEntryOffset(deltaEntry) + deltaEntry->valueBits;
Packit Service 310c69
  const byte *addr = memory + deltaOffset / CHAR_BIT;
Packit Service 310c69
  int offset = deltaOffset % CHAR_BIT;
Packit Service 310c69
  uint32_t data = getUInt32LE(addr) >> offset;
Packit Service 310c69
  addr += sizeof(uint32_t);
Packit Service 310c69
  int keyBits = deltaZone->minBits;
Packit Service 310c69
  unsigned int delta = data & ((1 << keyBits) - 1);
Packit Service 310c69
  if (delta >= deltaZone->minKeys) {
Packit Service 310c69
    data >>= keyBits;
Packit Service 310c69
    if (data == 0) {
Packit Service 310c69
      keyBits = sizeof(uint32_t) * CHAR_BIT - offset;
Packit Service 310c69
      while ((data = getUInt32LE(addr)) == 0) {
Packit Service 310c69
        addr += sizeof(uint32_t);
Packit Service 310c69
        keyBits += sizeof(uint32_t) * CHAR_BIT;
Packit Service 310c69
      }
Packit Service 310c69
    }
Packit Service 310c69
    keyBits += ffs(data);
Packit Service 310c69
    delta += (keyBits - deltaZone->minBits - 1) * deltaZone->incrKeys;
Packit Service 310c69
  }
Packit Service 310c69
  deltaEntry->delta = delta;
Packit Service 310c69
  deltaEntry->key += delta;
Packit Service 310c69
Packit Service 310c69
  // Check for a collision, a delta of zero not at the start of the list.
Packit Service 310c69
  if (unlikely((delta == 0) && (deltaEntry->offset > 0))) {
Packit Service 310c69
    deltaEntry->isCollision = true;
Packit Service 310c69
    // The small duplication of this math in the two arms of this if statement
Packit Service 310c69
    // makes a tiny but measurable difference in performance.
Packit Service 310c69
    deltaEntry->entryBits = deltaEntry->valueBits + keyBits + COLLISION_BITS;
Packit Service 310c69
  } else {
Packit Service 310c69
    deltaEntry->isCollision = false;
Packit Service 310c69
    deltaEntry->entryBits = deltaEntry->valueBits + keyBits;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Delete bits from a delta list at the offset of the specified delta index
Packit Service 310c69
 * entry.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 * @param size        The number of bits to delete
Packit Service 310c69
 **/
Packit Service 310c69
static void deleteBits(const DeltaIndexEntry *deltaEntry, int size)
Packit Service 310c69
{
Packit Service 310c69
  DeltaList *deltaList = deltaEntry->deltaList;
Packit Service 310c69
  byte *memory = deltaEntry->deltaZone->memory;
Packit Service 310c69
  // Compute how many bits are retained before and after the deleted bits
Packit Service 310c69
  uint32_t totalSize = getDeltaListSize(deltaList);
Packit Service 310c69
  uint32_t beforeSize = deltaEntry->offset;
Packit Service 310c69
  uint32_t afterSize = totalSize - deltaEntry->offset - size;
Packit Service 310c69
Packit Service 310c69
  // Determine whether to add to the available space either before or after
Packit Service 310c69
  // the delta list.  We prefer to move the least amount of data.  If it is
Packit Service 310c69
  // exactly the same, try to add to the smaller amount of free space.
Packit Service 310c69
  bool beforeFlag;
Packit Service 310c69
  if (beforeSize < afterSize) {
Packit Service 310c69
    beforeFlag = true;
Packit Service 310c69
  } else if (afterSize < beforeSize) {
Packit Service 310c69
    beforeFlag = false;
Packit Service 310c69
  } else {
Packit Service 310c69
    uint64_t freeBefore
Packit Service 310c69
      = getDeltaListStart(&deltaList[0]) - getDeltaListEnd(&deltaList[-1]);
Packit Service 310c69
    uint64_t freeAfter
Packit Service 310c69
      = getDeltaListStart(&deltaList[1]) - getDeltaListEnd(&deltaList[ 0]);
Packit Service 310c69
    beforeFlag = freeBefore < freeAfter;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t source, destination;
Packit Service 310c69
  uint32_t count;
Packit Service 310c69
  if (beforeFlag) {
Packit Service 310c69
    source = getDeltaListStart(deltaList);
Packit Service 310c69
    destination = source + size;
Packit Service 310c69
    moveDeltaListStart(deltaList, size);
Packit Service 310c69
    count = beforeSize;
Packit Service 310c69
  } else {
Packit Service 310c69
    moveDeltaListEnd(deltaList, -size);
Packit Service 310c69
    destination = getDeltaListStart(deltaList) + deltaEntry->offset;
Packit Service 310c69
    source = destination + size;
Packit Service 310c69
    count = afterSize;
Packit Service 310c69
  }
Packit Service 310c69
  moveBits(memory, source, memory, destination, count);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the offset of the collision field in a DeltaIndexEntry
Packit Service 310c69
 *
Packit Service 310c69
 * @param entry  The delta index record
Packit Service 310c69
 *
Packit Service 310c69
 * @return the offset of the start of the collision name
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE uint64_t getCollisionOffset(const DeltaIndexEntry *entry)
Packit Service 310c69
{
Packit Service 310c69
  return (getDeltaEntryOffset(entry) + entry->entryBits - COLLISION_BITS);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Encode a delta index entry delta.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 **/
Packit Service 310c69
static void encodeDelta(const DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  const DeltaMemory *deltaZone = deltaEntry->deltaZone;
Packit Service 310c69
  byte *memory = deltaZone->memory;
Packit Service 310c69
  uint64_t offset = getDeltaEntryOffset(deltaEntry) + deltaEntry->valueBits;
Packit Service 310c69
  if (deltaEntry->delta < deltaZone->minKeys) {
Packit Service 310c69
    setField(deltaEntry->delta, memory, offset, deltaZone->minBits);
Packit Service 310c69
    return;
Packit Service 310c69
  }
Packit Service 310c69
  unsigned int temp = deltaEntry->delta - deltaZone->minKeys;
Packit Service 310c69
  unsigned int t1   = (temp % deltaZone->incrKeys) + deltaZone->minKeys;
Packit Service 310c69
  unsigned int t2   = temp / deltaZone->incrKeys;
Packit Service 310c69
  setField(t1, memory, offset, deltaZone->minBits);
Packit Service 310c69
  setZero(memory, offset + deltaZone->minBits, t2);
Packit Service 310c69
  setOne(memory, offset + deltaZone->minBits + t2, 1);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Encode a delta index entry.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 * @param value       The value associated with the entry
Packit Service 310c69
 * @param name        For collision entries, the 256 bit full name.
Packit Service 310c69
 **/
Packit Service 310c69
static void encodeEntry(const DeltaIndexEntry *deltaEntry, unsigned int value,
Packit Service 310c69
                        const byte *name)
Packit Service 310c69
{
Packit Service 310c69
  byte *memory = deltaEntry->deltaZone->memory;
Packit Service 310c69
  uint64_t offset = getDeltaEntryOffset(deltaEntry);
Packit Service 310c69
  setField(value, memory, offset, deltaEntry->valueBits);
Packit Service 310c69
  encodeDelta(deltaEntry);
Packit Service 310c69
  if (name != NULL) {
Packit Service 310c69
    setBytes(memory, getCollisionOffset(deltaEntry), name, COLLISION_BYTES);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Insert bits into a delta list at the offset of the specified delta index
Packit Service 310c69
 * entry.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 * @param size        The number of bits to insert
Packit Service 310c69
 *
Packit Service 310c69
 * @return UDS_SUCCESS or an error code
Packit Service 310c69
 **/
Packit Service 310c69
static int insertBits(DeltaIndexEntry *deltaEntry, int size)
Packit Service 310c69
{
Packit Service 310c69
  DeltaMemory *deltaZone = deltaEntry->deltaZone;
Packit Service 310c69
  DeltaList  *deltaList  = deltaEntry->deltaList;
Packit Service 310c69
  // Compute how many bits are in use before and after the inserted bits
Packit Service 310c69
  uint32_t totalSize = getDeltaListSize(deltaList);
Packit Service 310c69
  uint32_t beforeSize = deltaEntry->offset;
Packit Service 310c69
  uint32_t afterSize = totalSize - deltaEntry->offset;
Packit Service 310c69
  if ((unsigned int) (totalSize + size) > UINT16_MAX) {
Packit Service 310c69
    deltaEntry->listOverflow = true;
Packit Service 310c69
    deltaZone->overflowCount++;
Packit Service 310c69
    return UDS_OVERFLOW;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Compute how many bits are available before and after the delta list
Packit Service 310c69
  uint64_t freeBefore
Packit Service 310c69
    = getDeltaListStart(&deltaList[0]) - getDeltaListEnd(&deltaList[-1]);
Packit Service 310c69
  uint64_t freeAfter
Packit Service 310c69
    = getDeltaListStart(&deltaList[1]) - getDeltaListEnd(&deltaList[ 0]);
Packit Service 310c69
Packit Service 310c69
  bool beforeFlag;
Packit Service 310c69
  if (((unsigned int) size <= freeBefore)
Packit Service 310c69
      && ((unsigned int) size <= freeAfter)) {
Packit Service 310c69
    // We have enough space to use either before or after the list.  Prefer
Packit Service 310c69
    // to move the least amount of data.  If it is exactly the same, try to
Packit Service 310c69
    // take from the larger amount of free space.
Packit Service 310c69
    if (beforeSize < afterSize) {
Packit Service 310c69
      beforeFlag = true;
Packit Service 310c69
    } else if (afterSize < beforeSize) {
Packit Service 310c69
      beforeFlag = false;
Packit Service 310c69
    } else {
Packit Service 310c69
      beforeFlag = freeBefore > freeAfter;
Packit Service 310c69
    }
Packit Service 310c69
  } else if ((unsigned int) size <= freeBefore) {
Packit Service 310c69
    // There is space before but not after
Packit Service 310c69
    beforeFlag = true;
Packit Service 310c69
  } else if ((unsigned int) size <= freeAfter) {
Packit Service 310c69
    // There is space after but not before
Packit Service 310c69
    beforeFlag = false;
Packit Service 310c69
  } else {
Packit Service 310c69
    // Neither of the surrounding spaces is large enough for this request,
Packit Service 310c69
    // Extend and/or rebalance the delta list memory choosing to move the
Packit Service 310c69
    // least amount of data.
Packit Service 310c69
    unsigned int growingIndex = deltaEntry->listNumber + 1;
Packit Service 310c69
    beforeFlag = beforeSize < afterSize;
Packit Service 310c69
    if (!beforeFlag) {
Packit Service 310c69
      growingIndex++;
Packit Service 310c69
    }
Packit Service 310c69
    int result = extendDeltaMemory(deltaZone, growingIndex,
Packit Service 310c69
                                   (size + CHAR_BIT - 1) / CHAR_BIT, true);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  uint64_t source, destination;
Packit Service 310c69
  uint32_t count;
Packit Service 310c69
  if (beforeFlag) {
Packit Service 310c69
    source = getDeltaListStart(deltaList);
Packit Service 310c69
    destination = source -  size;
Packit Service 310c69
    moveDeltaListStart(deltaList, -size);
Packit Service 310c69
    count = beforeSize;
Packit Service 310c69
  } else {
Packit Service 310c69
    moveDeltaListEnd(deltaList, size);
Packit Service 310c69
    source = getDeltaListStart(deltaList) + deltaEntry->offset;
Packit Service 310c69
    destination = source + size;
Packit Service 310c69
    count = afterSize;
Packit Service 310c69
  }
Packit Service 310c69
  byte *memory = deltaZone->memory;
Packit Service 310c69
  moveBits(memory, source, memory, destination, count);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Get the amount of memory to allocate for each zone
Packit Service 310c69
 *
Packit Service 310c69
 * @param numZones    The number of zones in the index
Packit Service 310c69
 * @param memorySize  The number of bytes in memory for the index
Packit Service 310c69
 *
Packit Service 310c69
 * @return the number of bytes to allocate for a single zone
Packit Service 310c69
 **/
Packit Service 310c69
static INLINE size_t getZoneMemorySize(unsigned int numZones,
Packit Service 310c69
                                       size_t memorySize)
Packit Service 310c69
{
Packit Service 310c69
  size_t zoneSize = memorySize / numZones;
Packit Service 310c69
  // Round the size up so that each zone is a multiple of 64K in size.
Packit Service 310c69
  enum { ALLOC_BOUNDARY = 64 * KILOBYTE };
Packit Service 310c69
  return (zoneSize + ALLOC_BOUNDARY - 1) & -ALLOC_BOUNDARY;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Validate delta index parameters
Packit Service 310c69
 *
Packit Service 310c69
 * @param meanDelta       The mean delta value
Packit Service 310c69
 * @param numPayloadBits  The number of bits in the payload or value
Packit Service 310c69
 **/
Packit Service 310c69
static bool invalidParameters(unsigned int meanDelta,
Packit Service 310c69
                              unsigned int numPayloadBits)
Packit Service 310c69
{
Packit Service 310c69
  const unsigned int minDelta = 10;
Packit Service 310c69
  const unsigned int maxDelta = 1 << MAX_FIELD_BITS;
Packit Service 310c69
  if ((meanDelta < minDelta) || (meanDelta > maxDelta)) {
Packit Service 310c69
    logWarning("error initializing delta index: "
Packit Service 310c69
               "meanDelta (%u) is not in the range %u to %u",
Packit Service 310c69
               meanDelta, minDelta, maxDelta);
Packit Service 310c69
    return true;
Packit Service 310c69
  }
Packit Service 310c69
  if (numPayloadBits > MAX_FIELD_BITS) {
Packit Service 310c69
    logWarning("error initializing delta index: Too many payload bits (%u)",
Packit Service 310c69
               numPayloadBits);
Packit Service 310c69
    return true;
Packit Service 310c69
  }
Packit Service 310c69
  return false;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Set a delta index entry to be a collision
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 **/
Packit Service 310c69
static void setCollision(DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  deltaEntry->isCollision = true;
Packit Service 310c69
  deltaEntry->entryBits += COLLISION_BITS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**
Packit Service 310c69
 * Set the delta in a delta index entry.
Packit Service 310c69
 *
Packit Service 310c69
 * @param deltaEntry  The delta index entry
Packit Service 310c69
 * @param delta       The new delta
Packit Service 310c69
 **/
Packit Service 310c69
static void setDelta(DeltaIndexEntry *deltaEntry, unsigned int delta)
Packit Service 310c69
{
Packit Service 310c69
  const DeltaMemory *deltaZone = deltaEntry->deltaZone;
Packit Service 310c69
  deltaEntry->delta = delta;
Packit Service 310c69
  int keyBits = (deltaZone->minBits
Packit Service 310c69
                 + ((deltaZone->incrKeys - deltaZone->minKeys + delta)
Packit Service 310c69
                    / deltaZone->incrKeys));
Packit Service 310c69
  deltaEntry->entryBits = deltaEntry->valueBits + keyBits;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
//  External functions declared in deltaIndex.h
Packit Service 310c69
//**********************************************************************
Packit Service 310c69
Packit Service 310c69
int initializeDeltaIndex(DeltaIndex *deltaIndex, unsigned int numZones,
Packit Service 310c69
                         unsigned int numLists, unsigned int meanDelta,
Packit Service 310c69
                         unsigned int numPayloadBits, size_t memorySize)
Packit Service 310c69
{
Packit Service 310c69
  size_t memSize = getZoneMemorySize(numZones, memorySize);
Packit Service 310c69
  if (invalidParameters(meanDelta, numPayloadBits)) {
Packit Service 310c69
    return UDS_INVALID_ARGUMENT;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  int result = ALLOCATE(numZones, DeltaMemory, "Delta Index Zones",
Packit Service 310c69
                        &deltaIndex->deltaZones);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  deltaIndex->numZones     = numZones;
Packit Service 310c69
  deltaIndex->numLists     = numLists;
Packit Service 310c69
  deltaIndex->listsPerZone = (numLists + numZones - 1) / numZones;
Packit Service 310c69
  deltaIndex->isMutable    = true;
Packit Service 310c69
  deltaIndex->tag          = 'm';
Packit Service 310c69
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < numZones; z++) {
Packit Service 310c69
    unsigned int firstListInZone = z * deltaIndex->listsPerZone;
Packit Service 310c69
    unsigned int numListsInZone = deltaIndex->listsPerZone;
Packit Service 310c69
    if (z == numZones - 1) {
Packit Service 310c69
      /*
Packit Service 310c69
       * The last zone gets fewer lists if numZones doesn't evenly divide
Packit Service 310c69
       * numLists. We'll have an underflow if the assertion below doesn't
Packit Service 310c69
       * hold. (And it turns out that the assertion is equivalent to
Packit Service 310c69
       *   numZones <= 1 + (numLists / numZones) + (numLists % numZones)
Packit Service 310c69
       * in the case that numZones doesn't evenly divide numlists.
Packit Service 310c69
       * If numLists >= numZones * numZones, then the above inequality
Packit Service 310c69
       * will always hold.)
Packit Service 310c69
       */
Packit Service 310c69
      if (deltaIndex->numLists <= firstListInZone) {
Packit Service 310c69
        uninitializeDeltaIndex(deltaIndex);
Packit Service 310c69
        return logErrorWithStringError(UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                       "%u delta-lists not enough for %u zones",
Packit Service 310c69
                                       numLists, numZones);
Packit Service 310c69
      }
Packit Service 310c69
      numListsInZone = deltaIndex->numLists - firstListInZone;
Packit Service 310c69
    }
Packit Service 310c69
    int result = initializeDeltaMemory(&deltaIndex->deltaZones[z], memSize,
Packit Service 310c69
                                       firstListInZone, numListsInZone,
Packit Service 310c69
                                       meanDelta, numPayloadBits);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      uninitializeDeltaIndex(deltaIndex);
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static bool verifyDeltaIndexPage(uint64_t  nonce,
Packit Service 310c69
                                 uint16_t  numLists,
Packit Service 310c69
                                 uint64_t  expectedNonce,
Packit Service 310c69
                                 byte     *memory,
Packit Service 310c69
                                 size_t    memSize)
Packit Service 310c69
{
Packit Service 310c69
  // Verify the nonce.  A mismatch here happens in normal operation when we are
Packit Service 310c69
  // doing a rebuild but haven't written the entire volume once.
Packit Service 310c69
  if (nonce != expectedNonce) {
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Verify that the number of delta lists can fit in the page.
Packit Service 310c69
  if (numLists >
Packit Service 310c69
      (memSize - sizeof(DeltaPageHeader)) * CHAR_BIT / IMMUTABLE_HEADER_SIZE) {
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Verify that the first delta list is immediately after the last delta list
Packit Service 310c69
  // header.
Packit Service 310c69
  if (getImmutableStart(memory, 0) != getImmutableHeaderOffset(numLists + 1)) {
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Verify that the lists are in the correct order.
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < numLists; i++) {
Packit Service 310c69
    if (getImmutableStart(memory, i) > getImmutableStart(memory, i + 1)) {
Packit Service 310c69
      return false;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Verify that the last list ends on the page, and that there is room for the
Packit Service 310c69
  // post-field guard bits.
Packit Service 310c69
  if (getImmutableStart(memory, numLists)
Packit Service 310c69
      > (memSize - POST_FIELD_GUARD_BYTES) * CHAR_BIT) {
Packit Service 310c69
    return false;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Verify that the guard bytes are correctly set to all ones.
Packit Service 310c69
  for (i = 0; i < POST_FIELD_GUARD_BYTES; i++) {
Packit Service 310c69
    byte guardByte = memory[memSize - POST_FIELD_GUARD_BYTES + i];
Packit Service 310c69
    if (guardByte != (byte) ~0) {
Packit Service 310c69
      return false;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // All verifications passed.
Packit Service 310c69
  return true;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int initializeDeltaIndexPage(DeltaIndexPage *deltaIndexPage,
Packit Service 310c69
                             uint64_t        expectedNonce,
Packit Service 310c69
                             unsigned int    meanDelta,
Packit Service 310c69
                             unsigned int    numPayloadBits,
Packit Service 310c69
                             byte           *memory,
Packit Service 310c69
                             size_t          memSize)
Packit Service 310c69
{
Packit Service 310c69
  const DeltaPageHeader *header = (const DeltaPageHeader *) memory;
Packit Service 310c69
Packit Service 310c69
  if (invalidParameters(meanDelta, numPayloadBits)) {
Packit Service 310c69
    return UDS_INVALID_ARGUMENT;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // First assume that the header is little endian
Packit Service 310c69
  uint64_t nonce = getUInt64LE((const byte *) &header->nonce);
Packit Service 310c69
  uint64_t vcn   = getUInt64LE((const byte *) &header->virtualChapterNumber);
Packit Service 310c69
  uint16_t firstList = getUInt16LE((const byte *) &header->firstList);
Packit Service 310c69
  uint16_t numLists  = getUInt16LE((const byte *) &header->numLists);
Packit Service 310c69
  if (!verifyDeltaIndexPage(nonce, numLists, expectedNonce, memory, memSize)) {
Packit Service 310c69
    // That failed, so try big endian
Packit Service 310c69
    nonce     = getUInt64BE((const byte *) &header->nonce);
Packit Service 310c69
    vcn       = getUInt64BE((const byte *) &header->virtualChapterNumber);
Packit Service 310c69
    firstList = getUInt16BE((const byte *) &header->firstList);
Packit Service 310c69
    numLists  = getUInt16BE((const byte *) &header->numLists);
Packit Service 310c69
    if (!verifyDeltaIndexPage(nonce, numLists, expectedNonce, memory,
Packit Service 310c69
                              memSize)) {
Packit Service 310c69
      // Also failed.  Do not log this as an error.  It happens in normal
Packit Service 310c69
      // operation when we are doing a rebuild but haven't written the entire
Packit Service 310c69
      // volume once.
Packit Service 310c69
      return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  deltaIndexPage->deltaIndex.deltaZones   = &deltaIndexPage->deltaMemory;
Packit Service 310c69
  deltaIndexPage->deltaIndex.numZones     = 1;
Packit Service 310c69
  deltaIndexPage->deltaIndex.numLists     = numLists;
Packit Service 310c69
  deltaIndexPage->deltaIndex.listsPerZone = numLists;
Packit Service 310c69
  deltaIndexPage->deltaIndex.isMutable    = false;
Packit Service 310c69
  deltaIndexPage->deltaIndex.tag          = 'p';
Packit Service 310c69
  deltaIndexPage->virtualChapterNumber = vcn;
Packit Service 310c69
  deltaIndexPage->lowestListNumber     = firstList;
Packit Service 310c69
  deltaIndexPage->highestListNumber    = firstList + numLists - 1;
Packit Service 310c69
Packit Service 310c69
  initializeDeltaMemoryPage(&deltaIndexPage->deltaMemory, (byte *) memory,
Packit Service 310c69
                            memSize, numLists, meanDelta, numPayloadBits);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void uninitializeDeltaIndex(DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  if (deltaIndex != NULL) {
Packit Service 310c69
    unsigned int z;
Packit Service 310c69
    for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
      uninitializeDeltaMemory(&deltaIndex->deltaZones[z]);
Packit Service 310c69
    }
Packit Service 310c69
    FREE(deltaIndex->deltaZones);
Packit Service 310c69
    memset(deltaIndex, 0, sizeof(DeltaIndex));
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void emptyDeltaIndex(const DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    emptyDeltaLists(&deltaIndex->deltaZones[z]);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void emptyDeltaIndexZone(const DeltaIndex *deltaIndex, unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  emptyDeltaLists(&deltaIndex->deltaZones[zoneNumber]);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int packDeltaIndexPage(const DeltaIndex *deltaIndex,
Packit Service 310c69
                       uint64_t          headerNonce,
Packit Service 310c69
                       bool              headerNativeEndian,
Packit Service 310c69
                       byte             *memory,
Packit Service 310c69
                       size_t            memSize,
Packit Service 310c69
                       uint64_t          virtualChapterNumber,
Packit Service 310c69
                       unsigned int      firstList,
Packit Service 310c69
                       unsigned int     *numLists)
Packit Service 310c69
{
Packit Service 310c69
  if (!deltaIndex->isMutable) {
Packit Service 310c69
    return logErrorWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                   "Cannot pack an immutable index");
Packit Service 310c69
  }
Packit Service 310c69
  if (deltaIndex->numZones != 1) {
Packit Service 310c69
    return logErrorWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                   "Cannot pack a delta index page when the"
Packit Service 310c69
                                   " index has %u zones",
Packit Service 310c69
                                   deltaIndex->numZones);
Packit Service 310c69
  }
Packit Service 310c69
  if (firstList > deltaIndex->numLists) {
Packit Service 310c69
    return logErrorWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                   "Cannot pack a delta index page when the"
Packit Service 310c69
                                   " first list (%u) is larger than the number"
Packit Service 310c69
                                   " of lists (%u)",
Packit Service 310c69
                                   firstList, deltaIndex->numLists);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  const DeltaMemory *deltaZone = &deltaIndex->deltaZones[0];
Packit Service 310c69
  DeltaList *deltaLists = &deltaZone->deltaLists[firstList + 1];
Packit Service 310c69
  unsigned int maxLists = deltaIndex->numLists - firstList;
Packit Service 310c69
Packit Service 310c69
  // Compute how many lists will fit on the page
Packit Service 310c69
  int numBits = memSize * CHAR_BIT;
Packit Service 310c69
  // Subtract the size of the fixed header and 1 delta list offset
Packit Service 310c69
  numBits -= getImmutableHeaderOffset(1);
Packit Service 310c69
  // Subtract the guard bytes of memory so that allow us to freely read a
Packit Service 310c69
  // short distance past the end of any byte we are interested in.
Packit Service 310c69
  numBits -= POST_FIELD_GUARD_BYTES * CHAR_BIT;
Packit Service 310c69
  if (numBits < IMMUTABLE_HEADER_SIZE) {
Packit Service 310c69
    // This page is too small to contain even one empty delta list
Packit Service 310c69
    return logErrorWithStringError(UDS_OVERFLOW,
Packit Service 310c69
                                   "Chapter Index Page of %zu bytes is too"
Packit Service 310c69
                                   " small",
Packit Service 310c69
                                   memSize);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int nLists = 0;
Packit Service 310c69
  while (nLists < maxLists) {
Packit Service 310c69
    // Each list requires 1 delta list offset and the list data
Packit Service 310c69
    int bits = IMMUTABLE_HEADER_SIZE + getDeltaListSize(&deltaLists[nLists]);
Packit Service 310c69
    if (bits > numBits) {
Packit Service 310c69
      break;
Packit Service 310c69
    }
Packit Service 310c69
    nLists++;
Packit Service 310c69
    numBits -= bits;
Packit Service 310c69
  }
Packit Service 310c69
  *numLists = nLists;
Packit Service 310c69
Packit Service 310c69
  // Construct the page header
Packit Service 310c69
  DeltaPageHeader *header = (DeltaPageHeader *) memory;
Packit Service 310c69
  if (headerNativeEndian) {
Packit Service 310c69
    header->nonce                = headerNonce;
Packit Service 310c69
    header->virtualChapterNumber = virtualChapterNumber;
Packit Service 310c69
    header->firstList            = firstList;
Packit Service 310c69
    header->numLists             = nLists;
Packit Service 310c69
  } else {
Packit Service 310c69
    storeUInt64LE((byte *) &header->nonce,     headerNonce);
Packit Service 310c69
    storeUInt64LE((byte *) &header->virtualChapterNumber,
Packit Service 310c69
                  virtualChapterNumber);
Packit Service 310c69
    storeUInt16LE((byte *) &header->firstList, firstList);
Packit Service 310c69
    storeUInt16LE((byte *) &header->numLists,  nLists);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Construct the delta list offset table, making sure that the memory
Packit Service 310c69
  // page is large enough.
Packit Service 310c69
  unsigned int offset = getImmutableHeaderOffset(nLists + 1);
Packit Service 310c69
  setImmutableStart(memory, 0, offset);
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < nLists; i++) {
Packit Service 310c69
    offset += getDeltaListSize(&deltaLists[i]);
Packit Service 310c69
    setImmutableStart(memory, i + 1, offset);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Copy the delta list data onto the memory page
Packit Service 310c69
  for (i = 0; i < nLists; i++) {
Packit Service 310c69
    DeltaList *deltaList = &deltaLists[i];
Packit Service 310c69
    moveBits(deltaZone->memory, getDeltaListStart(deltaList), memory,
Packit Service 310c69
             getImmutableStart(memory, i), getDeltaListSize(deltaList));
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Set all the bits in the guard bytes.  Do not use the bit field
Packit Service 310c69
  // utilities.
Packit Service 310c69
  memset(memory + memSize - POST_FIELD_GUARD_BYTES, ~0,
Packit Service 310c69
         POST_FIELD_GUARD_BYTES);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void setDeltaIndexTag(DeltaIndex *deltaIndex, byte tag)
Packit Service 310c69
{
Packit Service 310c69
  deltaIndex->tag = tag;
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    deltaIndex->deltaZones[z].tag = tag;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int decodeDeltaIndexHeader(Buffer *buffer, struct di_header *header)
Packit Service 310c69
{
Packit Service 310c69
  int result = getBytesFromBuffer(buffer, MAGIC_SIZE, &header->magic);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &header->zoneNumber);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &header->numZones);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &header->firstList);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt32LEFromBuffer(buffer, &header->numLists);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &header->recordCount);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = getUInt64LEFromBuffer(buffer, &header->collisionCount);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == 0,
Packit Service 310c69
                           "%zu bytes decoded of %zu expected",
Packit Service 310c69
                           bufferLength(buffer) - contentLength(buffer),
Packit Service 310c69
                           bufferLength(buffer));
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int readDeltaIndexHeader(BufferedReader *reader,
Packit Service 310c69
                                struct di_header *header)
Packit Service 310c69
{
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
Packit Service 310c69
  int result = makeBuffer(sizeof(*header), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = readFromBufferedReader(reader, getBufferContents(buffer),
Packit Service 310c69
                                  bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return logWarningWithStringError(result,
Packit Service 310c69
                                     "failed to read delta index header");
Packit Service 310c69
  }
Packit Service 310c69
  result = resetBufferEnd(buffer, bufferLength(buffer));
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = decodeDeltaIndexHeader(buffer, header);
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int startRestoringDeltaIndex(const DeltaIndex  *deltaIndex,
Packit Service 310c69
                             BufferedReader   **bufferedReaders,
Packit Service 310c69
                             int                numReaders)
Packit Service 310c69
{
Packit Service 310c69
  if (!deltaIndex->isMutable) {
Packit Service 310c69
    return logErrorWithStringError(UDS_BAD_STATE,
Packit Service 310c69
                                   "Cannot restore to an immutable index");
Packit Service 310c69
  }
Packit Service 310c69
  if (numReaders <= 0) {
Packit Service 310c69
    return logWarningWithStringError(UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                     "No delta index files");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int numZones = numReaders;
Packit Service 310c69
  if (numZones > MAX_ZONES) {
Packit Service 310c69
    return logErrorWithStringError(UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                   "zone count %u must not exceed MAX_ZONES",
Packit Service 310c69
                                   numZones);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned long recordCount = 0;
Packit Service 310c69
  unsigned long collisionCount = 0;
Packit Service 310c69
  unsigned int firstList[MAX_ZONES];
Packit Service 310c69
  unsigned int numLists[MAX_ZONES];
Packit Service 310c69
  BufferedReader *reader[MAX_ZONES];
Packit Service 310c69
  bool zoneFlags[MAX_ZONES] = { false, };
Packit Service 310c69
Packit Service 310c69
  // Read the header from each file, and make sure we have a matching set
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < numZones; z++) {
Packit Service 310c69
    struct di_header header;
Packit Service 310c69
    int result = readDeltaIndexHeader(bufferedReaders[z], &header);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return logWarningWithStringError(result,
Packit Service 310c69
                                       "failed to read delta index header");
Packit Service 310c69
    }
Packit Service 310c69
    if (memcmp(header.magic, MAGIC_DI_START, MAGIC_SIZE) != 0) {
Packit Service 310c69
      return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                       "delta index file has bad magic"
Packit Service 310c69
                                       " number");
Packit Service 310c69
    }
Packit Service 310c69
    if (numZones != header.numZones) {
Packit Service 310c69
      return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                       "delta index files contain mismatched"
Packit Service 310c69
                                       " zone counts (%u,%u)",
Packit Service 310c69
                                       numZones, header.numZones);
Packit Service 310c69
    }
Packit Service 310c69
    if (header.zoneNumber >= numZones) {
Packit Service 310c69
      return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                       "delta index files contains zone %u of"
Packit Service 310c69
                                       " %u zones",
Packit Service 310c69
                                       header.zoneNumber, numZones);
Packit Service 310c69
    }
Packit Service 310c69
    if (zoneFlags[header.zoneNumber]) {
Packit Service 310c69
      return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                       "delta index files contain two of zone"
Packit Service 310c69
                                       " %u",
Packit Service 310c69
                                       header.zoneNumber);
Packit Service 310c69
    }
Packit Service 310c69
    reader[header.zoneNumber] = bufferedReaders[z];
Packit Service 310c69
    firstList[header.zoneNumber] = header.firstList;
Packit Service 310c69
    numLists[header.zoneNumber] = header.numLists;
Packit Service 310c69
    zoneFlags[header.zoneNumber] = true;
Packit Service 310c69
    recordCount += header.recordCount;
Packit Service 310c69
    collisionCount += header.collisionCount;
Packit Service 310c69
  }
Packit Service 310c69
  unsigned int listNext = 0;
Packit Service 310c69
  for (z = 0; z < numZones; z++) {
Packit Service 310c69
    if (firstList[z] != listNext) {
Packit Service 310c69
      return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                       "delta index file for zone %u starts"
Packit Service 310c69
                                       " with list %u instead of list %u",
Packit Service 310c69
                                       z, firstList[z], listNext);
Packit Service 310c69
    }
Packit Service 310c69
    listNext += numLists[z];
Packit Service 310c69
  }
Packit Service 310c69
  if (listNext != deltaIndex->numLists) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "delta index files contain %u delta lists"
Packit Service 310c69
                                     " instead of %u delta lists",
Packit Service 310c69
                                     listNext, deltaIndex->numLists);
Packit Service 310c69
  }
Packit Service 310c69
  if (collisionCount > recordCount) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "delta index files contain %ld collisions"
Packit Service 310c69
                                     " and %ld records",
Packit Service 310c69
                                     collisionCount, recordCount);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  emptyDeltaIndex(deltaIndex);
Packit Service 310c69
  deltaIndex->deltaZones[0].recordCount    = recordCount;
Packit Service 310c69
  deltaIndex->deltaZones[0].collisionCount = collisionCount;
Packit Service 310c69
Packit Service 310c69
  // Read the delta list sizes from the files, and distribute each of them
Packit Service 310c69
  // to proper zone
Packit Service 310c69
  for (z = 0; z < numZones; z++) {
Packit Service 310c69
    unsigned int i;
Packit Service 310c69
    for (i = 0; i < numLists[z]; i++) {
Packit Service 310c69
      byte deltaListSizeData[sizeof(uint16_t)];
Packit Service 310c69
      int result = readFromBufferedReader(reader[z], deltaListSizeData,
Packit Service 310c69
                                          sizeof(deltaListSizeData));
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return logWarningWithStringError(result,
Packit Service 310c69
                                         "failed to read delta index size");
Packit Service 310c69
      }
Packit Service 310c69
      uint16_t deltaListSize = getUInt16LE(deltaListSizeData);
Packit Service 310c69
      unsigned int listNumber = firstList[z] + i;
Packit Service 310c69
      unsigned int zoneNumber = getDeltaIndexZone(deltaIndex, listNumber);
Packit Service 310c69
      const DeltaMemory *deltaZone = &deltaIndex->deltaZones[zoneNumber];
Packit Service 310c69
      listNumber -= deltaZone->firstList;
Packit Service 310c69
      deltaZone->deltaLists[listNumber + 1].size = deltaListSize;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  // Prepare each zone to start receiving the delta list data
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    int result = startRestoringDeltaMemory(&deltaIndex->deltaZones[z]);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool isRestoringDeltaIndexDone(const DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    if (!areDeltaMemoryTransfersDone(&deltaIndex->deltaZones[z])) {
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
int restoreDeltaListToDeltaIndex(const DeltaIndex *deltaIndex,
Packit Service 310c69
                                 const DeltaListSaveInfo *dlsi,
Packit Service 310c69
                                 const byte data[DELTA_LIST_MAX_BYTE_COUNT])
Packit Service 310c69
{
Packit Service 310c69
  // Make sure the data are intended for this delta list.  Do not
Packit Service 310c69
  // log an error, as this may be valid data for another delta index.
Packit Service 310c69
  if (dlsi->tag != deltaIndex->tag) {
Packit Service 310c69
    return UDS_CORRUPT_COMPONENT;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (dlsi->index >= deltaIndex->numLists) {
Packit Service 310c69
    return logWarningWithStringError(UDS_CORRUPT_COMPONENT,
Packit Service 310c69
                                     "invalid delta list number %u of %u",
Packit Service 310c69
                                     dlsi->index, deltaIndex->numLists);
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int zoneNumber = getDeltaIndexZone(deltaIndex, dlsi->index);
Packit Service 310c69
  return restoreDeltaList(&deltaIndex->deltaZones[zoneNumber], dlsi, data);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void abortRestoringDeltaIndex(const DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    abortRestoringDeltaMemory(&deltaIndex->deltaZones[z]);
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((warn_unused_result))
Packit Service 310c69
static int encodeDeltaIndexHeader(Buffer *buffer, struct di_header *header)
Packit Service 310c69
{
Packit Service 310c69
  int result = putBytes(buffer, MAGIC_SIZE, MAGIC_DI_START);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, header->zoneNumber);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, header->numZones);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, header->firstList);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt32LEIntoBuffer(buffer, header->numLists);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, header->recordCount);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = putUInt64LEIntoBuffer(buffer, header->collisionCount);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_LOG_ONLY(contentLength(buffer) == sizeof(*header),
Packit Service 310c69
                           "%zu bytes encoded of %zu expected",
Packit Service 310c69
                           contentLength(buffer), sizeof(*header));
Packit Service 310c69
Packit Service 310c69
  return result;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int startSavingDeltaIndex(const DeltaIndex *deltaIndex,
Packit Service 310c69
                          unsigned int zoneNumber,
Packit Service 310c69
                          BufferedWriter *bufferedWriter)
Packit Service 310c69
{
Packit Service 310c69
  DeltaMemory *deltaZone = &deltaIndex->deltaZones[zoneNumber];
Packit Service 310c69
  struct di_header header;
Packit Service 310c69
  memcpy(header.magic, MAGIC_DI_START, MAGIC_SIZE);
Packit Service 310c69
  header.zoneNumber     = zoneNumber;
Packit Service 310c69
  header.numZones       = deltaIndex->numZones;
Packit Service 310c69
  header.firstList      = deltaZone->firstList;
Packit Service 310c69
  header.numLists       = deltaZone->numLists;
Packit Service 310c69
  header.recordCount    = deltaZone->recordCount;
Packit Service 310c69
  header.collisionCount = deltaZone->collisionCount;
Packit Service 310c69
Packit Service 310c69
  Buffer *buffer;
Packit Service 310c69
  int result = makeBuffer(sizeof(struct di_header), &buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = encodeDeltaIndexHeader(buffer, &header);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    freeBuffer(&buffer);
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = writeToBufferedWriter(bufferedWriter, getBufferContents(buffer),
Packit Service 310c69
                                 contentLength(buffer));
Packit Service 310c69
  freeBuffer(&buffer);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return logWarningWithStringError(result,
Packit Service 310c69
                                     "failed to write delta index header");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < deltaZone->numLists; i++) {
Packit Service 310c69
    uint16_t deltaListSize = getDeltaListSize(&deltaZone->deltaLists[i + 1]);
Packit Service 310c69
    byte data[2];
Packit Service 310c69
    storeUInt16LE(data, deltaListSize);
Packit Service 310c69
    result = writeToBufferedWriter(bufferedWriter, data, sizeof(data));
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return logWarningWithStringError(result,
Packit Service 310c69
                                       "failed to write delta list size");
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  startSavingDeltaMemory(deltaZone, bufferedWriter);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
bool isSavingDeltaIndexDone(const DeltaIndex *deltaIndex,
Packit Service 310c69
                            unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  return areDeltaMemoryTransfersDone(&deltaIndex->deltaZones[zoneNumber]);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int finishSavingDeltaIndex(const DeltaIndex *deltaIndex,
Packit Service 310c69
                           unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  return finishSavingDeltaMemory(&deltaIndex->deltaZones[zoneNumber]);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int abortSavingDeltaIndex(const DeltaIndex *deltaIndex,
Packit Service 310c69
                          unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  abortSavingDeltaMemory(&deltaIndex->deltaZones[zoneNumber]);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
size_t computeDeltaIndexSaveBytes(unsigned int numLists, size_t memorySize)
Packit Service 310c69
{
Packit Service 310c69
  // The exact amount of memory used depends upon the number of zones.
Packit Service 310c69
  // Compute the maximum potential memory size.
Packit Service 310c69
  size_t maxMemSize = memorySize;
Packit Service 310c69
  unsigned int numZones;
Packit Service 310c69
  for (numZones = 1; numZones <= MAX_ZONES; numZones++) {
Packit Service 310c69
    size_t memSize = getZoneMemorySize(numZones, memorySize);
Packit Service 310c69
    if (memSize > maxMemSize) {
Packit Service 310c69
      maxMemSize = memSize;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  // Saving a delta index requires a header ...
Packit Service 310c69
  return (sizeof(struct di_header)
Packit Service 310c69
          // ... plus a DeltaListSaveInfo per delta list
Packit Service 310c69
          // plus an extra byte per delta list ...
Packit Service 310c69
          + numLists * (sizeof(DeltaListSaveInfo) + 1)
Packit Service 310c69
          // ... plus the delta list memory
Packit Service 310c69
          + maxMemSize);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int validateDeltaIndex(const DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    int result = validateDeltaLists(&deltaIndex->deltaZones[z]);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int assertNotAtEnd(const DeltaIndexEntry *deltaEntry, int errorCode)
Packit Service 310c69
{
Packit Service 310c69
  return ASSERT_WITH_ERROR_CODE(!deltaEntry->atEnd, errorCode,
Packit Service 310c69
                                "operation is invalid because the list entry "
Packit Service 310c69
                                "is at the end of the delta list");
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static void prefetchDeltaList(const DeltaMemory *deltaZone,
Packit Service 310c69
                              const DeltaList *deltaList)
Packit Service 310c69
{
Packit Service 310c69
  const byte *memory = deltaZone->memory;
Packit Service 310c69
  const byte *addr = &memory[getDeltaListStart(deltaList) / CHAR_BIT];
Packit Service 310c69
  unsigned int size = getDeltaListSize(deltaList) / CHAR_BIT;
Packit Service 310c69
  prefetchRange(addr, size, false);
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int startDeltaIndexSearch(const DeltaIndex *deltaIndex,
Packit Service 310c69
                          unsigned int listNumber, unsigned int key,
Packit Service 310c69
                          bool readOnly, DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  int result
Packit Service 310c69
    = ASSERT_WITH_ERROR_CODE((listNumber < deltaIndex->numLists),
Packit Service 310c69
                             UDS_CORRUPT_DATA,
Packit Service 310c69
                             "Delta list number (%u) is out of range (%u)",
Packit Service 310c69
                             listNumber, deltaIndex->numLists);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  unsigned int zoneNumber = getDeltaIndexZone(deltaIndex, listNumber);
Packit Service 310c69
  DeltaMemory *deltaZone = &deltaIndex->deltaZones[zoneNumber];
Packit Service 310c69
  listNumber -= deltaZone->firstList;
Packit Service 310c69
  result = ASSERT_WITH_ERROR_CODE((listNumber < deltaZone->numLists),
Packit Service 310c69
                                  UDS_CORRUPT_DATA,
Packit Service 310c69
                                  "Delta list number (%u)"
Packit Service 310c69
                                  " is out of range (%u) for zone (%u)",
Packit Service 310c69
                                  listNumber, deltaZone->numLists, zoneNumber);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DeltaList *deltaList;
Packit Service 310c69
  if (deltaIndex->isMutable) {
Packit Service 310c69
    deltaList = &deltaZone->deltaLists[listNumber + 1];
Packit Service 310c69
    if (!readOnly) {
Packit Service 310c69
      // Here is the lazy writing of the index for a checkpoint
Packit Service 310c69
      lazyFlushDeltaList(deltaZone, listNumber);
Packit Service 310c69
    }
Packit Service 310c69
  } else {
Packit Service 310c69
    // Translate the immutable delta list header into a temporary full
Packit Service 310c69
    // delta list header
Packit Service 310c69
    deltaList = &deltaEntry->tempDeltaList;
Packit Service 310c69
    deltaList->startOffset = getImmutableStart(deltaZone->memory, listNumber);
Packit Service 310c69
    unsigned int endOffset = getImmutableStart(deltaZone->memory,
Packit Service 310c69
                                               listNumber + 1);
Packit Service 310c69
    deltaList->size = endOffset - deltaList->startOffset;
Packit Service 310c69
    deltaList->saveKey = 0;
Packit Service 310c69
    deltaList->saveOffset = 0;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (key > deltaList->saveKey) {
Packit Service 310c69
    deltaEntry->key    = deltaList->saveKey;
Packit Service 310c69
    deltaEntry->offset = deltaList->saveOffset;
Packit Service 310c69
  } else {
Packit Service 310c69
    deltaEntry->key    = 0;
Packit Service 310c69
    deltaEntry->offset = 0;
Packit Service 310c69
    if (key == 0) {
Packit Service 310c69
      // This usually means we're about to walk the entire delta list, so get
Packit Service 310c69
      // all of it into the CPU cache.
Packit Service 310c69
      prefetchDeltaList(deltaZone, deltaList);
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  deltaEntry->atEnd        = false;
Packit Service 310c69
  deltaEntry->deltaZone    = deltaZone;
Packit Service 310c69
  deltaEntry->deltaList    = deltaList;
Packit Service 310c69
  deltaEntry->entryBits    = 0;
Packit Service 310c69
  deltaEntry->isCollision  = false;
Packit Service 310c69
  deltaEntry->listNumber   = listNumber;
Packit Service 310c69
  deltaEntry->listOverflow = false;
Packit Service 310c69
  deltaEntry->valueBits    = deltaZone->valueBits;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
__attribute__((__noinline__))
Packit Service 310c69
int nextDeltaIndexEntry(DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  int result = assertNotAtEnd(deltaEntry, UDS_BAD_STATE);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  const DeltaList *deltaList = deltaEntry->deltaList;
Packit Service 310c69
  deltaEntry->offset += deltaEntry->entryBits;
Packit Service 310c69
  unsigned int size = getDeltaListSize(deltaList);
Packit Service 310c69
  if (unlikely(deltaEntry->offset >= size)) {
Packit Service 310c69
    deltaEntry->atEnd       = true;
Packit Service 310c69
    deltaEntry->delta       = 0;
Packit Service 310c69
    deltaEntry->isCollision = false;
Packit Service 310c69
    return ASSERT_WITH_ERROR_CODE((deltaEntry->offset == size),
Packit Service 310c69
                                  UDS_CORRUPT_DATA,
Packit Service 310c69
                                  "next offset past end of delta list");
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  decodeDelta(deltaEntry);
Packit Service 310c69
Packit Service 310c69
  unsigned int nextOffset = deltaEntry->offset + deltaEntry->entryBits;
Packit Service 310c69
  if (nextOffset > size) {
Packit Service 310c69
    // This is not an assertion because validateChapterIndexPage() wants to
Packit Service 310c69
    // handle this error.
Packit Service 310c69
    logWarning("Decoded past the end of the delta list");
Packit Service 310c69
    return UDS_CORRUPT_DATA;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int rememberDeltaIndexOffset(const DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  int result = ASSERT(!deltaEntry->isCollision, "entry is not a collision");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DeltaList *deltaList = deltaEntry->deltaList;
Packit Service 310c69
  deltaList->saveKey = deltaEntry->key - deltaEntry->delta;
Packit Service 310c69
  deltaList->saveOffset = deltaEntry->offset;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int getDeltaIndexEntry(const DeltaIndex *deltaIndex, unsigned int listNumber,
Packit Service 310c69
                       unsigned int key, const byte *name, bool readOnly,
Packit Service 310c69
                       DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  int result = startDeltaIndexSearch(deltaIndex, listNumber, key, readOnly,
Packit Service 310c69
                                     deltaEntry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  do {
Packit Service 310c69
    result = nextDeltaIndexEntry(deltaEntry);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  } while (!deltaEntry->atEnd && (key > deltaEntry->key));
Packit Service 310c69
Packit Service 310c69
  result = rememberDeltaIndexOffset(deltaEntry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (!deltaEntry->atEnd && (key == deltaEntry->key)) {
Packit Service 310c69
    DeltaIndexEntry collisionEntry;
Packit Service 310c69
    collisionEntry = *deltaEntry;
Packit Service 310c69
    for (;;) {
Packit Service 310c69
      result = nextDeltaIndexEntry(&collisionEntry);
Packit Service 310c69
      if (result != UDS_SUCCESS) {
Packit Service 310c69
        return result;
Packit Service 310c69
      }
Packit Service 310c69
      if (collisionEntry.atEnd || !collisionEntry.isCollision) {
Packit Service 310c69
        break;
Packit Service 310c69
      }
Packit Service 310c69
      byte collisionName[COLLISION_BYTES];
Packit Service 310c69
      getBytes(deltaEntry->deltaZone->memory,
Packit Service 310c69
               getCollisionOffset(&collisionEntry), collisionName,
Packit Service 310c69
               COLLISION_BYTES);
Packit Service 310c69
      if (memcmp(collisionName, name, COLLISION_BYTES) == 0) {
Packit Service 310c69
        *deltaEntry = collisionEntry;
Packit Service 310c69
        break;
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
int getDeltaEntryCollision(const DeltaIndexEntry *deltaEntry, byte *name)
Packit Service 310c69
{
Packit Service 310c69
  int result = assertNotAtEnd(deltaEntry, UDS_BAD_STATE);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = ASSERT_WITH_ERROR_CODE(deltaEntry->isCollision, UDS_BAD_STATE,
Packit Service 310c69
                                  "Cannot get full block name from a"
Packit Service 310c69
                                  " non-collision delta index entry");
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  getBytes(deltaEntry->deltaZone->memory, getCollisionOffset(deltaEntry),
Packit Service 310c69
           name, COLLISION_BYTES);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
static int assertMutableEntry(const DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  return ASSERT_WITH_ERROR_CODE(deltaEntry->deltaList
Packit Service 310c69
                                != &deltaEntry->tempDeltaList,
Packit Service 310c69
                                UDS_BAD_STATE,
Packit Service 310c69
                                "delta index is mutable");
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int setDeltaEntryValue(const DeltaIndexEntry *deltaEntry, unsigned int value)
Packit Service 310c69
{
Packit Service 310c69
  int result = assertMutableEntry(deltaEntry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  result = assertNotAtEnd(deltaEntry, UDS_BAD_STATE);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  result = ASSERT_WITH_ERROR_CODE(((value & ((1 << deltaEntry->valueBits) - 1))
Packit Service 310c69
                                   == value), UDS_INVALID_ARGUMENT,
Packit Service 310c69
                                  "Value (%u) being set in a delta index is "
Packit Service 310c69
                                  "too large (must fit in %u bits)",
Packit Service 310c69
                                  value, deltaEntry->valueBits);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  setField(value, deltaEntry->deltaZone->memory,
Packit Service 310c69
           getDeltaEntryOffset(deltaEntry), deltaEntry->valueBits);
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int putDeltaIndexEntry(DeltaIndexEntry *deltaEntry, unsigned int key,
Packit Service 310c69
                       unsigned int value, const byte *name)
Packit Service 310c69
{
Packit Service 310c69
  int result = assertMutableEntry(deltaEntry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  if (deltaEntry->isCollision) {
Packit Service 310c69
    /*
Packit Service 310c69
     * The caller wants us to insert a collision entry onto a collision
Packit Service 310c69
     * entry.  This happens when we find a collision and attempt to add the
Packit Service 310c69
     * name again to the index.  This is normally a fatal error unless we
Packit Service 310c69
     * are replaying a closed chapter while we are rebuilding a master
Packit Service 310c69
     * index.
Packit Service 310c69
     */
Packit Service 310c69
    return UDS_DUPLICATE_NAME;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (deltaEntry->offset < deltaEntry->deltaList->saveOffset) {
Packit Service 310c69
    // The saved entry offset is after the new entry and will no longer be
Packit Service 310c69
    // valid, so replace it with the insertion point.
Packit Service 310c69
    result = rememberDeltaIndexOffset(deltaEntry);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  if (name != NULL) {
Packit Service 310c69
    // We are inserting a collision entry which is placed after this entry
Packit Service 310c69
    result = assertNotAtEnd(deltaEntry, UDS_BAD_STATE);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    result = ASSERT((key == deltaEntry->key),
Packit Service 310c69
                    "incorrect key for collision entry");
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    deltaEntry->offset += deltaEntry->entryBits;
Packit Service 310c69
    setDelta(deltaEntry, 0);
Packit Service 310c69
    setCollision(deltaEntry);
Packit Service 310c69
    result = insertBits(deltaEntry, deltaEntry->entryBits);
Packit Service 310c69
  } else if (deltaEntry->atEnd) {
Packit Service 310c69
    // We are inserting a new entry at the end of the delta list
Packit Service 310c69
    result = ASSERT((key >= deltaEntry->key), "key past end of list");
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    setDelta(deltaEntry, key - deltaEntry->key);
Packit Service 310c69
    deltaEntry->key   = key;
Packit Service 310c69
    deltaEntry->atEnd = false;
Packit Service 310c69
    result = insertBits(deltaEntry, deltaEntry->entryBits);
Packit Service 310c69
  } else {
Packit Service 310c69
    // We are inserting a new entry which requires the delta in the
Packit Service 310c69
    // following entry to be updated.
Packit Service 310c69
    result = ASSERT((key < deltaEntry->key), "key precedes following entry");
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    result = ASSERT((key >= deltaEntry->key - deltaEntry->delta),
Packit Service 310c69
                    "key effects following entry's delta");
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
Packit Service 310c69
    int oldEntrySize = deltaEntry->entryBits;
Packit Service 310c69
    DeltaIndexEntry nextEntry = *deltaEntry;
Packit Service 310c69
    unsigned int nextValue = getDeltaEntryValue(&nextEntry);
Packit Service 310c69
    setDelta(deltaEntry, key - (deltaEntry->key - deltaEntry->delta));
Packit Service 310c69
    deltaEntry->key = key;
Packit Service 310c69
    setDelta(&nextEntry, nextEntry.key - key);
Packit Service 310c69
    nextEntry.offset += deltaEntry->entryBits;
Packit Service 310c69
    // The 2 new entries are always bigger than the 1 entry we are replacing
Packit Service 310c69
    int additionalSize
Packit Service 310c69
      = deltaEntry->entryBits + nextEntry.entryBits - oldEntrySize;
Packit Service 310c69
    result = insertBits(deltaEntry, additionalSize);
Packit Service 310c69
    if (result != UDS_SUCCESS) {
Packit Service 310c69
      return result;
Packit Service 310c69
    }
Packit Service 310c69
    encodeEntry(&nextEntry, nextValue, NULL);
Packit Service 310c69
  }
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
  encodeEntry(deltaEntry, value, name);
Packit Service 310c69
Packit Service 310c69
  DeltaMemory *deltaZone = deltaEntry->deltaZone;
Packit Service 310c69
  deltaZone->recordCount++;
Packit Service 310c69
  deltaZone->collisionCount += deltaEntry->isCollision ? 1 : 0;
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
int removeDeltaIndexEntry(DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  int result = assertMutableEntry(deltaEntry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DeltaIndexEntry nextEntry = *deltaEntry;
Packit Service 310c69
  result = nextDeltaIndexEntry(&nextEntry);
Packit Service 310c69
  if (result != UDS_SUCCESS) {
Packit Service 310c69
    return result;
Packit Service 310c69
  }
Packit Service 310c69
Packit Service 310c69
  DeltaMemory *deltaZone = deltaEntry->deltaZone;
Packit Service 310c69
Packit Service 310c69
  if (deltaEntry->isCollision) {
Packit Service 310c69
    // This is a collision entry, so just remove it
Packit Service 310c69
    deleteBits(deltaEntry, deltaEntry->entryBits);
Packit Service 310c69
    nextEntry.offset = deltaEntry->offset;
Packit Service 310c69
    deltaZone->collisionCount -= 1;
Packit Service 310c69
  } else if (nextEntry.atEnd) {
Packit Service 310c69
    // This entry is at the end of the list, so just remove it
Packit Service 310c69
    deleteBits(deltaEntry, deltaEntry->entryBits);
Packit Service 310c69
    nextEntry.key -= deltaEntry->delta;
Packit Service 310c69
    nextEntry.offset = deltaEntry->offset;
Packit Service 310c69
  } else {
Packit Service 310c69
    // The delta in the next entry needs to be updated.
Packit Service 310c69
    unsigned int nextValue = getDeltaEntryValue(&nextEntry);
Packit Service 310c69
    int oldSize = deltaEntry->entryBits + nextEntry.entryBits;
Packit Service 310c69
    if (nextEntry.isCollision) {
Packit Service 310c69
      // The next record is a collision. It needs to be rewritten as a
Packit Service 310c69
      // non-collision with a larger delta.
Packit Service 310c69
      nextEntry.isCollision = false;
Packit Service 310c69
      deltaZone->collisionCount -= 1;
Packit Service 310c69
    }
Packit Service 310c69
    setDelta(&nextEntry, deltaEntry->delta + nextEntry.delta);
Packit Service 310c69
    nextEntry.offset = deltaEntry->offset;
Packit Service 310c69
    // The 1 new entry is always smaller than the 2 entries we are replacing
Packit Service 310c69
    deleteBits(deltaEntry, oldSize - nextEntry.entryBits);
Packit Service 310c69
    encodeEntry(&nextEntry, nextValue, NULL);
Packit Service 310c69
  }
Packit Service 310c69
  deltaZone->recordCount--;
Packit Service 310c69
  deltaZone->discardCount++;
Packit Service 310c69
  *deltaEntry = nextEntry;
Packit Service 310c69
Packit Service 310c69
  DeltaList *deltaList = deltaEntry->deltaList;
Packit Service 310c69
  if (deltaEntry->offset < deltaList->saveOffset) {
Packit Service 310c69
    // The saved entry offset is after the entry we just removed and it
Packit Service 310c69
    // will no longer be valid.  We must force the next search to start at
Packit Service 310c69
    // the beginning.
Packit Service 310c69
    deltaList->saveKey = 0;
Packit Service 310c69
    deltaList->saveOffset = 0;
Packit Service 310c69
  }
Packit Service 310c69
  return UDS_SUCCESS;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
unsigned int getDeltaIndexZoneFirstList(const DeltaIndex *deltaIndex,
Packit Service 310c69
                                        unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  return deltaIndex->deltaZones[zoneNumber].firstList;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
unsigned int getDeltaIndexZoneNumLists(const DeltaIndex *deltaIndex,
Packit Service 310c69
                                       unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  return deltaIndex->deltaZones[zoneNumber].numLists;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
uint64_t getDeltaIndexZoneDlistBitsUsed(const DeltaIndex *deltaIndex,
Packit Service 310c69
                                        unsigned int zoneNumber)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t bitCount = 0;
Packit Service 310c69
  const DeltaMemory *deltaZone = &deltaIndex->deltaZones[zoneNumber];
Packit Service 310c69
  unsigned int i;
Packit Service 310c69
  for (i = 0; i < deltaZone->numLists; i++) {
Packit Service 310c69
    bitCount += getDeltaListSize(&deltaZone->deltaLists[i + 1]);
Packit Service 310c69
  }
Packit Service 310c69
  return bitCount;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
uint64_t getDeltaIndexDlistBitsUsed(const DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t bitCount = 0;
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    bitCount += getDeltaIndexZoneDlistBitsUsed(deltaIndex, z);
Packit Service 310c69
  }
Packit Service 310c69
  return bitCount;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
uint64_t getDeltaIndexDlistBitsAllocated(const DeltaIndex *deltaIndex)
Packit Service 310c69
{
Packit Service 310c69
  uint64_t byteCount = 0;
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    const DeltaMemory *deltaZone = &deltaIndex->deltaZones[z];
Packit Service 310c69
    byteCount += deltaZone->size;
Packit Service 310c69
  }
Packit Service 310c69
  return byteCount * CHAR_BIT;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void getDeltaIndexStats(const DeltaIndex *deltaIndex, DeltaIndexStats *stats)
Packit Service 310c69
{
Packit Service 310c69
  memset(stats, 0, sizeof(DeltaIndexStats));
Packit Service 310c69
  stats->memoryAllocated = deltaIndex->numZones * sizeof(DeltaMemory);
Packit Service 310c69
  unsigned int z;
Packit Service 310c69
  for (z = 0; z < deltaIndex->numZones; z++) {
Packit Service 310c69
    const DeltaMemory *deltaZone = &deltaIndex->deltaZones[z];
Packit Service 310c69
    stats->memoryAllocated += getDeltaMemoryAllocated(deltaZone);
Packit Service 310c69
    stats->rebalanceTime   += deltaZone->rebalanceTime;
Packit Service 310c69
    stats->rebalanceCount  += deltaZone->rebalanceCount;
Packit Service 310c69
    stats->recordCount     += deltaZone->recordCount;
Packit Service 310c69
    stats->collisionCount  += deltaZone->collisionCount;
Packit Service 310c69
    stats->discardCount    += deltaZone->discardCount;
Packit Service 310c69
    stats->overflowCount   += deltaZone->overflowCount;
Packit Service 310c69
    stats->numLists        += deltaZone->numLists;
Packit Service 310c69
  }
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
unsigned int getDeltaIndexPageCount(unsigned int numEntries,
Packit Service 310c69
                                    unsigned int numLists,
Packit Service 310c69
                                    unsigned int meanDelta,
Packit Service 310c69
                                    unsigned int numPayloadBits,
Packit Service 310c69
                                    size_t bytesPerPage)
Packit Service 310c69
{
Packit Service 310c69
  // Compute the number of bits needed for all the entries
Packit Service 310c69
  size_t bitsPerIndex
Packit Service 310c69
    = getDeltaMemorySize(numEntries, meanDelta, numPayloadBits);
Packit Service 310c69
  // Compute the number of bits needed for a single delta list
Packit Service 310c69
  unsigned int bitsPerDeltaList = bitsPerIndex / numLists;
Packit Service 310c69
  // Adjust the bits per index, adding the immutable delta list headers
Packit Service 310c69
  bitsPerIndex += numLists * IMMUTABLE_HEADER_SIZE;
Packit Service 310c69
  // Compute the number of usable bits on an immutable index page
Packit Service 310c69
  unsigned int bitsPerPage
Packit Service 310c69
    = (bytesPerPage - sizeof(DeltaPageHeader)) * CHAR_BIT;
Packit Service 310c69
  // Adjust the bits per page, taking away one immutable delta list header
Packit Service 310c69
  // and one delta list representing internal fragmentation
Packit Service 310c69
  bitsPerPage -= IMMUTABLE_HEADER_SIZE + bitsPerDeltaList;
Packit Service 310c69
  // Now compute the number of pages needed
Packit Service 310c69
  return (bitsPerIndex + bitsPerPage - 1) / bitsPerPage;
Packit Service 310c69
}
Packit Service 310c69
Packit Service 310c69
/**********************************************************************/
Packit Service 310c69
void logDeltaIndexEntry(DeltaIndexEntry *deltaEntry)
Packit Service 310c69
{
Packit Service 310c69
  logRatelimit(logInfo, "List 0x%X Key 0x%X Offset 0x%X%s%s ListSize 0x%X%s",
Packit Service 310c69
               deltaEntry->listNumber, deltaEntry->key, deltaEntry->offset,
Packit Service 310c69
               deltaEntry->atEnd ? " end" : "",
Packit Service 310c69
               deltaEntry->isCollision ? " collision" : "",
Packit Service 310c69
               getDeltaListSize(deltaEntry->deltaList),
Packit Service 310c69
               deltaEntry->listOverflow ? " overflow" : "");
Packit Service 310c69
  deltaEntry->listOverflow = false;
Packit Service 310c69
}