/* * Copyright (c) 2020 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * $Id: //eng/uds-releases/jasper/src/uds/geometry.h#3 $ */ #ifndef GEOMETRY_H #define GEOMETRY_H 1 #include "compiler.h" #include "typeDefs.h" #include "uds.h" #include "uds-block.h" /** * Geometry defines constants and a record that parameterize the layout of an * Albireo index volume. * *
An index volume is divided into a fixed number of fixed-size * chapters, each consisting of a fixed number of fixed-size * pages. The volume layout is defined by two assumptions and four * parameters. The assumptions (constants) are that index records are * 64 bytes (32-byte block name plus 32-byte metadata) and that open * chapter index hash slots are one byte long. The four parameters are * the number of bytes in a page, the number of chapters in a volume, * the number of record pages in a chapter, and the number of chapters * that are sparse. From these parameters, we derive the rest of the * layout and derived properties, ranging from the number of pages in * a chapter to the number of records in the volume. * *
The default geometry is 64 KByte pages, 1024 chapters, 256
* record pages in a chapter, and zero sparse chapters. This will
* allow us to store 2^28 entries (indexing 1TB of 4K blocks) in an
* approximately 16.5 MByte volume using fourteen index pages in each
* chapter.
**/
typedef struct geometry {
/** Length of a page in a chapter, in bytes */
size_t bytesPerPage;
/** Number of record pages in a chapter */
unsigned int recordPagesPerChapter;
/** Number of (total) chapters in a volume */
unsigned int chaptersPerVolume;
/** Number of sparsely-indexed chapters in a volume */
unsigned int sparseChaptersPerVolume;
/** Number of bits used to determine delta list numbers */
unsigned int chapterDeltaListBits;
// These are derived properties, expressed as fields for convenience.
/** Total number of pages in a volume, excluding header */
unsigned int pagesPerVolume;
/** Total number of header pages per volume */
unsigned int headerPagesPerVolume;
/** Total number of bytes in a volume, including header */
size_t bytesPerVolume;
/** Total number of bytes in a chapter */
size_t bytesPerChapter;
/** Number of pages in a chapter */
unsigned int pagesPerChapter;
/** Number of index pages in a chapter index */
unsigned int indexPagesPerChapter;
/** The minimum ratio of hash slots to records in an open chapter */
unsigned int openChapterLoadRatio;
/** Number of records that fit on a page */
unsigned int recordsPerPage;
/** Number of records that fit in a chapter */
unsigned int recordsPerChapter;
/** Number of records that fit in a volume */
uint64_t recordsPerVolume;
/** Number of deltaLists per chapter index */
unsigned int deltaListsPerChapter;
/** Mean delta in chapter indexes */
unsigned int chapterMeanDelta;
/** Number of bits needed for record page numbers */
unsigned int chapterPayloadBits;
/** Number of bits used to compute addresses for chapter delta lists */
unsigned int chapterAddressBits;
/** Number of densely-indexed chapters in a volume */
unsigned int denseChaptersPerVolume;
} Geometry;
enum {
/* The number of bytes in a record (name + metadata) */
BYTES_PER_RECORD = (UDS_CHUNK_NAME_SIZE + UDS_MAX_BLOCK_DATA_SIZE),
/* The default length of a page in a chapter, in bytes */
DEFAULT_BYTES_PER_PAGE = 1024 * BYTES_PER_RECORD,
/* The default maximum number of records per page */
DEFAULT_RECORDS_PER_PAGE = DEFAULT_BYTES_PER_PAGE / BYTES_PER_RECORD,
/** The default number of record pages in a chapter */
DEFAULT_RECORD_PAGES_PER_CHAPTER = 256,
/** The default number of record pages in a chapter for a small index */
SMALL_RECORD_PAGES_PER_CHAPTER = 64,
/** The default number of chapters in a volume */
DEFAULT_CHAPTERS_PER_VOLUME = 1024,
/** The default number of sparsely-indexed chapters in a volume */
DEFAULT_SPARSE_CHAPTERS_PER_VOLUME = 0,
/** The log2 of the default mean delta */
DEFAULT_CHAPTER_MEAN_DELTA_BITS = 16,
/** The log2 of the number of delta lists in a large chapter */
DEFAULT_CHAPTER_DELTA_LIST_BITS = 12,
/** The log2 of the number of delta lists in a small chapter */
SMALL_CHAPTER_DELTA_LIST_BITS = 10,
/** The default min ratio of slots to records in an open chapter */
DEFAULT_OPEN_CHAPTER_LOAD_RATIO = 2,
/** Checkpoint every n chapters written. Default is to not checkpoint */
DEFAULT_CHECKPOINT_FREQUENCY = 0
};
/**
* Allocate and initialize all fields of a volume geometry using the
* specified layout parameters.
*
* @param bytesPerPage The length of a page in a chapter, in bytes
* @param recordPagesPerChapter The number of pages in a chapter
* @param chaptersPerVolume The number of chapters in a volume
* @param sparseChaptersPerVolume The number of sparse chapters in a volume
* @param geometryPtr A pointer to hold the new geometry
*
* @return UDS_SUCCESS or an error code
**/
int makeGeometry(size_t bytesPerPage,
unsigned int recordPagesPerChapter,
unsigned int chaptersPerVolume,
unsigned int sparseChaptersPerVolume,
Geometry **geometryPtr)
__attribute__((warn_unused_result));
/**
* Allocate a new geometry and initialize it with the same parameters as an
* existing geometry.
*
* @param source The geometry record to copy
* @param geometryPtr A pointer to hold the new geometry
*
* @return UDS_SUCCESS or an error code
**/
int copyGeometry(Geometry *source,
Geometry **geometryPtr)
__attribute__((warn_unused_result));
/**
* Clean up a geometry and its memory.
*
* @param geometry The geometry record to free
**/
void freeGeometry(Geometry *geometry);
/**
* Map a virtual chapter number to a physical chapter number
*
* @param geometry The geometry
* @param virtualChapter The virtual chapter number
*
* @return the corresponding physical chapter number
**/
__attribute__((warn_unused_result))
static INLINE unsigned int mapToPhysicalChapter(const Geometry *geometry,
uint64_t virtualChapter)
{
return (virtualChapter % geometry->chaptersPerVolume);
}
/**
* Convert a physical chapter number to its current virtual chapter number.
*
* @param geometry The geometry
* @param newestVirtualChapter The number of the newest virtual chapter
* @param physicalChapter The physical chapter number to convert
*
* @return The current virtual chapter number of the physical chapter
* in question
**/
uint64_t mapToVirtualChapterNumber(Geometry *geometry,
uint64_t newestVirtualChapter,
unsigned int physicalChapter);
/**
* Check whether this geometry is for a sparse index.
*
* @param geometry The geometry to check
*
* @return true if this geometry has sparse chapters
**/
__attribute__((warn_unused_result))
static INLINE bool isSparse(const Geometry *geometry)
{
return (geometry->sparseChaptersPerVolume > 0);
}
/**
* Check whether any sparse chapters have been filled.
*
* @param geometry The geometry of the index
* @param oldestVirtualChapter The number of the oldest chapter in the
* index
* @param newestVirtualChapter The number of the newest chapter in the
* index
*
* @return true if the index has filled at least one sparse chapter
**/
bool hasSparseChapters(const Geometry *geometry,
uint64_t oldestVirtualChapter,
uint64_t newestVirtualChapter)
__attribute__((warn_unused_result));
/**
* Check whether a chapter is sparse or dense.
*
* @param geometry The geometry of the index containing the chapter
* @param oldestVirtualChapter The number of the oldest chapter in the index
* @param newestVirtualChapter The number of the newest chapter in the index
* @param virtualChapterNumber The number of the chapter to check
*
* @return true if the chapter is sparse
**/
bool isChapterSparse(const Geometry *geometry,
uint64_t oldestVirtualChapter,
uint64_t newestVirtualChapter,
uint64_t virtualChapterNumber)
__attribute__((warn_unused_result));
/**
* Check whether two virtual chapter numbers correspond to the same
* physical chapter.
*
* @param geometry The geometry of the index
* @param chapter1 The first chapter to compare
* @param chapter2 The second chapter to compare
*
* @return true
if both chapters correspond to the same
* physical chapter
**/
bool areSamePhysicalChapter(const Geometry *geometry,
uint64_t chapter1,
uint64_t chapter2)
__attribute__((warn_unused_result));
#endif /* GEOMETRY_H */