Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* This file is part of VoltDB.
* Copyright (C) 2008-2018 VoltDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with VoltDB. If not, see .
*/
package org.voltdb.utils;
import java.util.ArrayList;
import java.util.List;
import org.voltdb.VoltType;
import org.voltdb.catalog.CatalogMap;
import org.voltdb.catalog.Column;
import org.voltdb.catalog.ColumnRef;
import org.voltdb.catalog.Database;
import org.voltdb.catalog.Index;
import org.voltdb.catalog.Table;
import org.voltdb.types.IndexType;
/**
* A collection of classes used for estimating the bytewise size of a database,
* given a catalog.
*
* Currently used by the Compiler Report.
*
*/
public abstract class CatalogSizing {
public final static int MAX_BYTES_PER_UTF8_CHARACTER = 4;
/**
* Base class for raw catalog sizes.
*/
public static class CatalogItemSizeBase {
public long widthMin;
public long widthMax;
public CatalogItemSizeBase() {
this(0, 0);
}
public CatalogItemSizeBase(long widthMin, long widthMax) {
this.widthMin = widthMin;
this.widthMax = widthMax;
}
}
/**
* Catalog sizes and cardinality estimate.
*/
public static class CatalogItemSize extends CatalogItemSizeBase {
public final long cardinality;
public CatalogItemSize(long cardinality) {
super();
this.cardinality = cardinality;
}
public CatalogItemSize(long widthMin, long widthMax, long cardinality) {
super(widthMin, widthMax);
this.cardinality = cardinality;
}
public long getItemCount() {
return 1;
}
}
public static class CatalogItemSizeRollup extends CatalogItemSize {
public long itemCount;
public CatalogItemSizeRollup(long cardinality, long itemCount) {
super(cardinality);
this.itemCount = itemCount;
}
@Override
public long getItemCount() {
return itemCount;
}
}
/**
* Raw index sizes.
*/
public static class IndexSize extends CatalogItemSize {
public final Index index;
public final String name;
public IndexSize(Index index, long widthMin, long widthMax, long cardinality) {
super(widthMin, widthMax, cardinality);
this.index = index;
this.name = index.getTypeName().toLowerCase();
}
}
/**
* List of catalog item sizes with roll-up support.
*
* @param
*/
public static class CatalogItemSizeList extends ArrayList {
private static final long serialVersionUID = -6846163291201059792L;
public CatalogItemSizeRollup rollup(long cardinality) {
CatalogItemSizeRollup rollupSize = new CatalogItemSizeRollup(cardinality, 0);
for (T size: this) {
rollupSize.widthMin += (size.widthMin * size.cardinality);
rollupSize.widthMax += (size.widthMax * size.cardinality);
rollupSize.itemCount += size.getItemCount();
}
return rollupSize;
}
}
/**
* Raw table sizes.
*/
public static class TableSize extends CatalogItemSize {
public final Table table;
public final String name;
public final boolean isView;
public final CatalogItemSizeList indexSizes;
public TableSize(
Table table,
boolean isView,
long widthMin,
long widthMax,
long cardinality)
{
super(widthMin, widthMax, cardinality);
this.table = table;
this.name = table.getTypeName().toLowerCase();
this.isView = isView;
this.indexSizes = new CatalogItemSizeList();
}
public void addIndex(Index index, long widthMin, long widthMax) {
this.indexSizes.add(new IndexSize(index, widthMin, widthMax, 1));
}
public CatalogItemSizeRollup indexRollup() {
return this.indexSizes.rollup(this.cardinality);
}
}
/**
* Container of raw database size numbers.
*/
public static class DatabaseSizes {
public final CatalogItemSizeList tableSizes = new CatalogItemSizeList();
public final CatalogItemSizeList viewSizes = new CatalogItemSizeList();
public long indexCount = 0;
public void addTable(TableSize tableSize) {
if (tableSize.isView) {
this.viewSizes.add(tableSize);
}
else {
this.tableSizes.add(tableSize);
}
this.indexCount += tableSize.indexSizes.size();
}
public CatalogItemSizeRollup tableRollup() {
return this.tableSizes.rollup(1);
}
public CatalogItemSizeRollup viewRollup() {
return this.viewSizes.rollup(1);
}
public CatalogItemSizeRollup indexRollup() {
CatalogItemSizeList indexSizes = new CatalogItemSizeList();
for (TableSize tsize: this.tableSizes) {
for (IndexSize isize: tsize.indexSizes) {
indexSizes.add(isize);
}
}
for (TableSize vsize: this.viewSizes) {
for (IndexSize isize: vsize.indexSizes) {
indexSizes.add(isize);
}
}
return indexSizes.rollup(1);
}
}
private static int roundedAllocationSize(int min, int contentSize) {
int bufferSize = min;
while (bufferSize < contentSize) {
int increment = bufferSize / 2;
bufferSize += increment;
if (bufferSize >= contentSize) {
break;
}
bufferSize += increment;
}
return bufferSize;
}
private static int getVariableColumnSize(VoltType type, int capacity, int dataSize, boolean forIndex, boolean isNullable) {
assert(capacity >= 0);
assert(dataSize >= 0);
// Smaller capacities get fully consumed (plus 1 byte).
if (capacity < 64) {
return capacity + 1;
}
// Indexes get 8 byte pointers rather than replicate large data.
if (forIndex) {
if (type != VoltType.GEOGRAPHY) {
return 8;
}
else {
// Instances of GEOGRAPHY are not stored in indices.
// Geospatial indexes decompose them into cells, which
// are accounted for separately in the indexes that contain them.
return 0;
}
}
// For Nullable
if (isNullable) {
return 8;
}
// Larger capacities use pooled buffers sized in powers of 2 or values halfway
// between powers of 2.
// The rounded buffer size includes an object length of 4 bytes and
// an 8-byte backpointer used in compaction.
int content = 4 + 8 + dataSize;
int bufferSize = roundedAllocationSize(8, content);
// There is also has an 8-byte pointer in the tuple
// and an 8-byte StringRef indirection pointer.
return bufferSize + 8 + 8;
}
public static int testOnlyAllocationSizeForObject(int dataSize) {
// See the comments in getVariableColumnSize for the significance of
// these adjustments.
int content = 4 + 8 + dataSize;
if (content <= 48) {
// Short-cut calculations for sizes that are not used in the
// catalog sizing.
return roundedAllocationSize(16, content);
}
// Otherwise exercise as much of the catalog sizing code path as
// possible but strip out any adjustments that are not directly a
// result of allocation rounding.
// See the comments in getVariableColumnSize for the significance of
// these adjustments.
return getVariableColumnSize(VoltType.VARBINARY, 64, dataSize, false, false) - 8 - 8;
}
private static CatalogItemSizeBase getColumnsSize(List columns, boolean forIndex, boolean bAdjustForDrAA) {
// See http://voltdb.com/docs/PlanningGuide/ChapMemoryRecs.php
CatalogItemSizeBase csize = new CatalogItemSizeBase();
for (Column column: columns) {
VoltType ctype = VoltType.get((byte)column.getType());
boolean isNullable = column.getNullable();
if (ctype.isVariableLength()) {
int capacity = column.getSize();
if (ctype == VoltType.STRING && !column.getInbytes()) {
capacity *= MAX_BYTES_PER_UTF8_CHARACTER;
}
csize.widthMin += getVariableColumnSize(ctype, capacity, 0, forIndex, isNullable);
csize.widthMax += getVariableColumnSize(ctype, capacity, capacity, forIndex, false);
}
else {
// Fixed type - use the fixed size.
csize.widthMin += ctype.getLengthInBytesForFixedTypes();
csize.widthMax += ctype.getLengthInBytesForFixedTypes();
}
}
//For DR active active enabled account for additional timestamp column for conflict detection.
if (bAdjustForDrAA) {
csize.widthMin += 8;
csize.widthMax += 8;
}
return csize;
}
private static CatalogItemSizeBase getIndexSize(Index index) {
// this is sizeof(CompactingMap::TreeNode), not counting template parameter KeyValuePair.
final long TREE_MAP_ENTRY_OVERHEAD = 32;
final long TUPLE_PTR_SIZE = 8;
// All index types consume the space taken by the column data,
// except that 8 byte pointers references replace large var... data.
// Additional overhead is determined by the index type.
CatalogMap columnRefsMap = index.getColumns();
List indexColumns = new ArrayList(columnRefsMap.size());
for (ColumnRef columnRef: columnRefsMap) {
indexColumns.add(columnRef.getColumn());
}
//For index Size dont count the DR AA conflict column.
CatalogItemSizeBase isize = getColumnsSize(indexColumns, true, false);
if (index.getType() == IndexType.HASH_TABLE.getValue()) {
// Hash index overhead follows this documented formula:
// w=column width, r=row count
// (((2 * r) + 1) * 8) + ((w + 32) * r)
// This can be reduced to the following:
// (w + 48) * r + 8
// For approximation purposes the constant +8 is ignorable.
isize.widthMin += 48;
isize.widthMax += 48;
}
else if (index.getType() == IndexType.COVERING_CELL_INDEX.getValue()) {
// Covering cell indexes are implemented in the EE with two maps:
//
// [1 entry per table row] tuple address -> fixed-size array of 8 cell ids
// [1-8 entries per table row] cell id -> tuple address
//
// The polygon value is not referenced at all in the index, just the tuple address.
// The call to getColumnsSize above purposely omits the size of the pointer to
// the geography value for this reason.
//
// Other columns in the index are included, so if in the future we decide to support
// multi-component geospatial indexes to optimize predicates like
// "WHERE id = 10 and contains(geog, ?)", then this code would not need to change.
final long MIN_CELLS = 1;
final long MAX_CELLS = 8;
final long CELL_SIZE = 8;
final long TUPLE_MAP_ENTRY = TREE_MAP_ENTRY_OVERHEAD + TUPLE_PTR_SIZE + MAX_CELLS * CELL_SIZE;
final long CELL_MAP_ENTRY = TREE_MAP_ENTRY_OVERHEAD + CELL_SIZE + TUPLE_PTR_SIZE;
isize.widthMin += TUPLE_MAP_ENTRY + MIN_CELLS * CELL_MAP_ENTRY;
isize.widthMax += TUPLE_MAP_ENTRY + MAX_CELLS * CELL_MAP_ENTRY;
}
else {
// Tree indexes have a 40 byte overhead per row.
isize.widthMin += TREE_MAP_ENTRY_OVERHEAD + TUPLE_PTR_SIZE;
isize.widthMax += TREE_MAP_ENTRY_OVERHEAD + TUPLE_PTR_SIZE;
}
return isize;
}
private static TableSize getTableSize(Table table, boolean bActiveActiveEnabled) {
// The cardinality is the estimated tuple count or an arbitrary number
// if not estimated.
long cardinality = table.getEstimatedtuplecount();
if (cardinality <= 0) {
cardinality = 1000;
}
//Do we need to adjust for DR-AA?
boolean bAdjustForDrAA = (table.getIsdred() && bActiveActiveEnabled);
// Add up the column widths.
CatalogMap columnsMap = table.getColumns();
List columns = new ArrayList(columnsMap.size());
for (Column column: columnsMap) {
columns.add(column);
}
CatalogItemSizeBase csize = getColumnsSize(columns, false, bAdjustForDrAA);
boolean isView = table.getMaterializer() != null;
TableSize tsize = new TableSize(table, isView, csize.widthMin, csize.widthMax, cardinality);
// Add the table indexes.
CatalogMap indexes = table.getIndexes();
for (Index index: indexes) {
CatalogItemSizeBase isize = getIndexSize(index);
tsize.addIndex(index, isize.widthMin, isize.widthMax);
}
return tsize;
}
/**
* Produce a sizing of all significant database objects.
* @param dbCatalog database catalog
* @param isXDCR Is XDCR enabled
* @return database size result object tree
*/
public static DatabaseSizes getCatalogSizes(Database dbCatalog, boolean isXDCR) {
DatabaseSizes dbSizes = new DatabaseSizes();
for (Table table: dbCatalog.getTables()) {
dbSizes.addTable(getTableSize(table, isXDCR));
}
return dbSizes;
}
}