Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Add the framework for the pg_statistic table. (#1416)
Browse files Browse the repository at this point in the history
Co-authored-by: Arvind Sai Krishnan <[email protected]>
Co-authored-by: Wan Shen Lim <[email protected]>
  • Loading branch information
3 people authored Jan 24, 2021
1 parent 3ebdd86 commit d60c55a
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 8 deletions.
18 changes: 17 additions & 1 deletion src/catalog/database_catalog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "catalog/postgres/pg_index.h"
#include "catalog/postgres/pg_namespace.h"
#include "catalog/postgres/pg_proc.h"
#include "catalog/postgres/pg_statistic.h"
#include "catalog/postgres/pg_type.h"
#include "catalog/schema.h"
#include "common/error/error_code.h"
Expand All @@ -38,7 +39,8 @@ DatabaseCatalog::DatabaseCatalog(const db_oid_t oid,
pg_type_(db_oid_),
pg_constraint_(db_oid_),
pg_language_(db_oid_),
pg_proc_(db_oid_) {}
pg_proc_(db_oid_),
pg_stat_(db_oid_) {}

void DatabaseCatalog::TearDown(const common::ManagedPointer<transaction::TransactionContext> txn) {
auto teardown_pg_core = pg_core_.GetTearDownFn(txn, common::ManagedPointer(this));
Expand Down Expand Up @@ -66,6 +68,7 @@ void DatabaseCatalog::BootstrapPRIs() {
pg_constraint_.BootstrapPRIs();
pg_language_.BootstrapPRIs();
pg_proc_.BootstrapPRIs();
pg_stat_.BootstrapPRIs();
}

void DatabaseCatalog::Bootstrap(const common::ManagedPointer<transaction::TransactionContext> txn) {
Expand All @@ -82,6 +85,7 @@ void DatabaseCatalog::Bootstrap(const common::ManagedPointer<transaction::Transa
pg_constraint_.Bootstrap(txn, common::ManagedPointer(this));
pg_language_.Bootstrap(txn, common::ManagedPointer(this));
pg_proc_.Bootstrap(txn, common::ManagedPointer(this));
pg_stat_.Bootstrap(txn, common::ManagedPointer(this));
}

namespace_oid_t DatabaseCatalog::CreateNamespace(const common::ManagedPointer<transaction::TransactionContext> txn,
Expand Down Expand Up @@ -112,6 +116,11 @@ table_oid_t DatabaseCatalog::CreateTable(const common::ManagedPointer<transactio
bool DatabaseCatalog::DeleteTable(const common::ManagedPointer<transaction::TransactionContext> txn,
const table_oid_t table) {
if (!TryLock(txn)) return false;
// Delete associated entries in pg_statistic.
{
auto result = pg_stat_.DeleteColumnStatistics(txn, table);
if (!result) return false;
}
return pg_core_.DeleteTable(txn, common::ManagedPointer(this), table);
}

Expand Down Expand Up @@ -325,6 +334,13 @@ void DatabaseCatalog::BootstrapIndex(const common::ManagedPointer<transaction::T
bool DatabaseCatalog::CreateTableEntry(const common::ManagedPointer<transaction::TransactionContext> txn,
const table_oid_t table_oid, const namespace_oid_t ns_oid,
const std::string &name, const Schema &schema) {
// Create associated entries in pg_statistic.
{
col_oid_t col_oid(1);
for (auto &col : schema.GetColumns()) {
pg_stat_.CreateColumnStatistic(txn, table_oid, col_oid++, col);
}
}
return pg_core_.CreateTableEntry(txn, table_oid, ns_oid, name, schema);
}

Expand Down
46 changes: 46 additions & 0 deletions src/catalog/postgres/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "catalog/postgres/pg_language.h"
#include "catalog/postgres/pg_namespace.h"
#include "catalog/postgres/pg_proc.h"
#include "catalog/postgres/pg_statistic.h"
#include "catalog/postgres/pg_type.h"
#include "catalog/schema.h"
#include "parser/expression/abstract_expression.h"
Expand Down Expand Up @@ -82,6 +83,7 @@ DatabaseCatalog *Builder::CreateDatabaseCatalog(
dbc->pg_constraint_.constraints_ = new storage::SqlTable(block_store, Builder::GetConstraintTableSchema());
dbc->pg_language_.languages_ = new storage::SqlTable(block_store, Builder::GetLanguageTableSchema());
dbc->pg_proc_.procs_ = new storage::SqlTable(block_store, Builder::GetProcTableSchema());
dbc->pg_stat_.statistics_ = new storage::SqlTable(block_store, Builder::GetStatisticTableSchema());

// Indexes on pg_namespace
dbc->pg_core_.namespaces_oid_index_ =
Expand Down Expand Up @@ -143,6 +145,10 @@ DatabaseCatalog *Builder::CreateDatabaseCatalog(
dbc->pg_proc_.procs_name_index_ =
Builder::BuildLookupIndex(Builder::GetProcNameIndexSchema(oid), PgProc::PRO_NAME_INDEX_OID);

// Indexes on pg_statistic
dbc->pg_stat_.statistic_oid_index_ =
Builder::BuildUniqueIndex(Builder::GetStatisticOidIndexSchema(oid), PgStatistic::STATISTIC_OID_INDEX_OID);

dbc->next_oid_.store(START_OID);

return dbc;
Expand Down Expand Up @@ -670,6 +676,28 @@ IndexSchema Builder::GetLanguageNameIndexSchema(db_oid_t db) {
return schema;
}

Schema Builder::GetStatisticTableSchema() {
std::vector<Schema::Column> columns;

columns.emplace_back("starelid", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STARELID.oid_);

columns.emplace_back("staattnum", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STAATTNUM.oid_);

columns.emplace_back("stanullrows", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STA_NULLROWS.oid_);

columns.emplace_back("stanumrows", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STA_NUMROWS.oid_);

return Schema(columns);
}

Schema Builder::GetProcTableSchema() {
std::vector<Schema::Column> columns;

Expand Down Expand Up @@ -795,6 +823,24 @@ IndexSchema Builder::GetProcNameIndexSchema(db_oid_t db) {
return schema;
}

IndexSchema Builder::GetStatisticOidIndexSchema(db_oid_t db) {
std::vector<IndexSchema::Column> columns;

columns.emplace_back("starelid", type::TypeId::INTEGER, false,
parser::ColumnValueExpression(db, PgStatistic::STATISTIC_TABLE_OID, PgStatistic::STARELID.oid_));
columns.back().SetOid(indexkeycol_oid_t(1));

columns.emplace_back(
"staattnum", type::TypeId::INTEGER, false,
parser::ColumnValueExpression(db, PgStatistic::STATISTIC_TABLE_OID, PgStatistic::STAATTNUM.oid_));
columns.back().SetOid(indexkeycol_oid_t(2));

// Primary
IndexSchema schema(columns, storage::index::IndexType::BWTREE, true, true, false, true);

return schema;
}

storage::index::Index *Builder::BuildUniqueIndex(const IndexSchema &key_schema, index_oid_t oid) {
NOISEPAGE_ASSERT(key_schema.Unique(), "KeySchema must represent a unique index.");
storage::index::IndexBuilder index_builder;
Expand Down
131 changes: 131 additions & 0 deletions src/catalog/postgres/pg_statistic_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#include "catalog/postgres/pg_statistic_impl.h"

#include "catalog/database_catalog.h"
#include "catalog/index_schema.h"
#include "catalog/postgres/builder.h"
#include "catalog/postgres/pg_namespace.h"
#include "catalog/schema.h"
#include "storage/index/index.h"
#include "storage/sql_table.h"

namespace noisepage::catalog::postgres {

PgStatisticImpl::PgStatisticImpl(db_oid_t db_oid) : db_oid_(db_oid) {}

void PgStatisticImpl::BootstrapPRIs() {
const std::vector<col_oid_t> pg_statistic_all_oids{PgStatistic::PG_STATISTIC_ALL_COL_OIDS.cbegin(),
PgStatistic::PG_STATISTIC_ALL_COL_OIDS.end()};
pg_statistic_all_cols_pri_ = statistics_->InitializerForProjectedRow(pg_statistic_all_oids);
pg_statistic_all_cols_prm_ = statistics_->ProjectionMapForOids(pg_statistic_all_oids);
const std::vector<col_oid_t> statistic_oid_index_oids{PgStatistic::STARELID.oid_, PgStatistic::STAATTNUM.oid_};
statistic_oid_index_pri_ = statistics_->InitializerForProjectedRow(statistic_oid_index_oids);
statistic_oid_index_prm_ = statistics_->ProjectionMapForOids(statistic_oid_index_oids);
}

void PgStatisticImpl::Bootstrap(common::ManagedPointer<transaction::TransactionContext> txn,
common::ManagedPointer<DatabaseCatalog> dbc) {
dbc->BootstrapTable(txn, PgStatistic::STATISTIC_TABLE_OID, PgNamespace::NAMESPACE_CATALOG_NAMESPACE_OID,
"pg_statistic", Builder::GetStatisticTableSchema(), statistics_);
dbc->BootstrapIndex(txn, PgNamespace::NAMESPACE_CATALOG_NAMESPACE_OID, PgStatistic::STATISTIC_TABLE_OID,
PgStatistic::STATISTIC_OID_INDEX_OID, "pg_statistic_index",
Builder::GetStatisticOidIndexSchema(db_oid_), statistic_oid_index_);
}

void PgStatisticImpl::CreateColumnStatistic(const common::ManagedPointer<transaction::TransactionContext> txn,
const table_oid_t table_oid, const col_oid_t col_oid,
const Schema::Column &col) {
auto *const redo = txn->StageWrite(db_oid_, PgStatistic::STATISTIC_TABLE_OID, pg_statistic_all_cols_pri_);
auto delta = common::ManagedPointer(redo->Delta());
auto &pm = pg_statistic_all_cols_prm_;

// Prepare the PR for insertion.
{
PgStatistic::STARELID.Set(delta, pm, table_oid);
PgStatistic::STAATTNUM.Set(delta, pm, col_oid);
PgStatistic::STA_NULLROWS.Set(delta, pm, 0);
PgStatistic::STA_NUMROWS.Set(delta, pm, 0);
}
const auto tuple_slot = statistics_->Insert(txn, redo);

const auto oid_pri = statistic_oid_index_->GetProjectedRowInitializer();
auto oid_prm = statistic_oid_index_->GetKeyOidToOffsetMap();
byte *const buffer = common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize());

// Insert into pg_statistic_index.
{
auto *pr = oid_pri.InitializeRow(buffer);
pr->Set<table_oid_t, false>(oid_prm[indexkeycol_oid_t(1)], table_oid, false);
pr->Set<col_oid_t, false>(oid_prm[indexkeycol_oid_t(2)], col_oid, false);

bool UNUSED_ATTRIBUTE result = statistic_oid_index_->InsertUnique(txn, *pr, tuple_slot);
NOISEPAGE_ASSERT(result, "Assigned pg_statistic OIDs failed to be unique.");
}

delete[] buffer;
}

bool PgStatisticImpl::DeleteColumnStatistics(const common::ManagedPointer<transaction::TransactionContext> txn,
const table_oid_t table_oid) {
const auto &oid_pri = statistic_oid_index_->GetProjectedRowInitializer();
const auto &oid_prm = statistic_oid_index_->GetKeyOidToOffsetMap();

byte *const key_buffer = common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize());
byte *const key_buffer_2 = common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize());

// Look for the column statistic in pg_statistic_index.
std::vector<storage::TupleSlot> index_results;
{
auto *pr_lo = oid_pri.InitializeRow(key_buffer);
auto *pr_hi = oid_pri.InitializeRow(key_buffer_2);

// Low key (class, min col_oid_t)
pr_lo->Set<table_oid_t, false>(oid_prm.at(indexkeycol_oid_t(1)), table_oid, false);
pr_lo->Set<col_oid_t, false>(oid_prm.at(indexkeycol_oid_t(2)), col_oid_t(std::numeric_limits<uint32_t>::min()),
false);

// High key (class + 1, max col_oid_t)
pr_hi->Set<table_oid_t, false>(oid_prm.at(indexkeycol_oid_t(1)), table_oid + 1, false);
pr_hi->Set<col_oid_t, false>(oid_prm.at(indexkeycol_oid_t(2)), col_oid_t(std::numeric_limits<uint32_t>::max()),
false);

statistic_oid_index_->ScanAscending(*txn, storage::index::ScanType::Closed, 2, pr_lo, pr_hi, 0, &index_results);
// TODO(WAN): Is there an assertion that we can make here?
}

// Scan pg_statistic to get the columns.
if (!index_results.empty()) {
auto pr = common::ManagedPointer(statistic_oid_index_pri_.InitializeRow(key_buffer));
for (const auto &slot : index_results) {
auto UNUSED_ATTRIBUTE result = statistics_->Select(txn, slot, pr.Get());
NOISEPAGE_ASSERT(result, "Index scan did a visibility check, so Select shouldn't fail at this point.");

auto &pm = statistic_oid_index_prm_;
auto *col_oid = PgStatistic::STAATTNUM.Get(pr, pm);
NOISEPAGE_ASSERT(col_oid != nullptr, "OID shouldn't be NULL.");

// Delete from pg_statistic.
{
txn->StageDelete(db_oid_, PgStatistic::STATISTIC_TABLE_OID, slot);
if (!statistics_->Delete(txn, slot)) { // Failed to delete some column. Ask to abort.
delete[] key_buffer;
delete[] key_buffer_2;
return false;
}
}

// Delete from pg_statistic_index.
{
auto *key_pr = oid_pri.InitializeRow(key_buffer_2);
key_pr->Set<table_oid_t, false>(oid_prm.at(indexkeycol_oid_t(1)), table_oid, false);
key_pr->Set<col_oid_t, false>(oid_prm.at(indexkeycol_oid_t(2)), *col_oid, false);
statistic_oid_index_->Delete(txn, *key_pr, slot);
}
}
}

delete[] key_buffer;
delete[] key_buffer_2;
return true;
}

} // namespace noisepage::catalog::postgres
3 changes: 3 additions & 0 deletions src/include/catalog/database_catalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "catalog/postgres/pg_core_impl.h"
#include "catalog/postgres/pg_language_impl.h"
#include "catalog/postgres/pg_proc_impl.h"
#include "catalog/postgres/pg_statistic_impl.h"
#include "catalog/postgres/pg_type_impl.h"
#include "common/managed_pointer.h"

Expand Down Expand Up @@ -192,6 +193,7 @@ class DatabaseCatalog {
friend class postgres::PgLanguageImpl;
friend class postgres::PgProcImpl;
friend class postgres::PgTypeImpl;
friend class postgres::PgStatisticImpl;
///@}
friend class Catalog; ///< Accesses write_lock_ (creating accessor) and TearDown (cleanup).
friend class postgres::Builder; ///< Initializes DatabaseCatalog's tables.
Expand All @@ -209,6 +211,7 @@ class DatabaseCatalog {
postgres::PgConstraintImpl pg_constraint_; ///< Constraints: pg_constraint.
postgres::PgLanguageImpl pg_language_; ///< Languages: pg_language.
postgres::PgProcImpl pg_proc_; ///< Procedures: pg_proc.
postgres::PgStatisticImpl pg_stat_; ///< Statistics: pg_statistic.

/** @brief Create a new DatabaseCatalog. Does not create any tables until Bootstrap is called. */
DatabaseCatalog(db_oid_t oid, common::ManagedPointer<storage::GarbageCollector> garbage_collector);
Expand Down
11 changes: 11 additions & 0 deletions src/include/catalog/postgres/builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ class Builder {
*/
static Schema GetProcTableSchema();

/**
* @return schema object for pg_statistic table
*/
static Schema GetStatisticTableSchema();

/**
* @param db oid in which the indexed table exists
* @return schema object for the oid index on pg_namespace
Expand Down Expand Up @@ -225,6 +230,12 @@ class Builder {
*/
static IndexSchema GetProcNameIndexSchema(db_oid_t db);

/**
* @param db oid in which the indexed table exists
* @return schema object for the table/oid index on pg_statistic
*/
static IndexSchema GetStatisticOidIndexSchema(db_oid_t db);

/**
* Instantiate a new unique index with the given schema and oid
* @param key_schema for the index
Expand Down
42 changes: 42 additions & 0 deletions src/include/catalog/postgres/pg_statistic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include <array>

#include "catalog/catalog_column_def.h"
#include "catalog/catalog_defs.h"

namespace noisepage::storage {
class RecoveryManager;
} // namespace noisepage::storage

namespace noisepage::catalog::postgres {
class Builder;
class PgStatisticImpl;

/** The OIDs used by the NoisePage version of pg_statistic. */
class PgStatistic {
private:
friend class storage::RecoveryManager;
friend class Builder;
friend class PgStatisticImpl;

static constexpr table_oid_t STATISTIC_TABLE_OID = table_oid_t(91);
static constexpr index_oid_t STATISTIC_OID_INDEX_OID = index_oid_t(92);

/*
* Column names of the form "STA[name]" are present in the PostgreSQL
* catalog specification and columns of the form "STA_[name]" are
* noisepage-specific additions.
*/
static constexpr CatalogColumnDef<table_oid_t, uint32_t> STARELID{col_oid_t{1}};
static constexpr CatalogColumnDef<col_oid_t, uint32_t> STAATTNUM{col_oid_t{2}};
static constexpr CatalogColumnDef<uint32_t, uint32_t> STA_NULLROWS{col_oid_t{3}};
static constexpr CatalogColumnDef<uint32_t, uint32_t> STA_NUMROWS{col_oid_t{4}};

static constexpr uint8_t NUM_PG_STATISTIC_COLS = 4;

static constexpr std::array<col_oid_t, NUM_PG_STATISTIC_COLS> PG_STATISTIC_ALL_COL_OIDS = {
STARELID.oid_, STAATTNUM.oid_, STA_NULLROWS.oid_, STA_NUMROWS.oid_};
};

} // namespace noisepage::catalog::postgres
Loading

0 comments on commit d60c55a

Please sign in to comment.