From bef98460128bdaed155017b54f1b89cde2a16c2b Mon Sep 17 00:00:00 2001 From: Hari Babu Date: Wed, 30 Aug 2017 12:41:15 +1000 Subject: [PATCH 2/8] Storage AM API hooks and related functions --- src/backend/access/heap/Makefile | 3 +- src/backend/access/heap/heapam_storage.c | 58 ++++++++ src/backend/access/heap/storageamapi.c | 103 ++++++++++++++ src/include/access/htup.h | 21 +++ src/include/access/storageamapi.h | 237 +++++++++++++++++++++++++++++++ src/include/catalog/pg_proc.h | 5 + src/include/nodes/nodes.h | 1 + src/include/utils/tqual.h | 9 -- 8 files changed, 427 insertions(+), 10 deletions(-) create mode 100644 src/backend/access/heap/heapam_storage.c create mode 100644 src/backend/access/heap/storageamapi.c create mode 100644 src/include/access/storageamapi.h diff --git a/src/backend/access/heap/Makefile b/src/backend/access/heap/Makefile index b83d496..02a3909 100644 --- a/src/backend/access/heap/Makefile +++ b/src/backend/access/heap/Makefile @@ -12,6 +12,7 @@ subdir = src/backend/access/heap top_builddir = ../../../.. include $(top_builddir)/src/Makefile.global -OBJS = heapam.o hio.o pruneheap.o rewriteheap.o syncscan.o tuptoaster.o visibilitymap.o +OBJS = heapam.o hio.o heapam_storage.o pruneheap.o rewriteheap.o storageamapi.o \ + syncscan.o tuptoaster.o visibilitymap.o include $(top_srcdir)/src/backend/common.mk diff --git a/src/backend/access/heap/heapam_storage.c b/src/backend/access/heap/heapam_storage.c new file mode 100644 index 0000000..88827e7 --- /dev/null +++ b/src/backend/access/heap/heapam_storage.c @@ -0,0 +1,58 @@ +/*------------------------------------------------------------------------- + * + * heapam_storage.c + * heap storage access method code + * + * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/access/heap/heapam_storage.c + * + * + * NOTES + * This file contains the heap_ routines which implement + * the POSTGRES heap access method used for all POSTGRES + * relations. + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/heapam.h" +#include "access/heapam_xlog.h" +#include "access/hio.h" +#include "access/htup_details.h" +#include "access/multixact.h" +#include "access/relscan.h" +#include "access/storageamapi.h" +#include "access/subtrans.h" +#include "access/tuptoaster.h" +#include "access/valid.h" +#include "access/visibilitymap.h" +#include "access/xloginsert.h" +#include "access/xact.h" +#include "catalog/catalog.h" +#include "miscadmin.h" +#include "pgstat.h" +#include "storage/bufmgr.h" +#include "storage/lmgr.h" +#include "storage/predicate.h" +#include "storage/procarray.h" +#include "storage/smgr.h" +#include "storage/spin.h" +#include "utils/builtins.h" +#include "utils/inval.h" +#include "utils/rel.h" +#include "utils/tqual.h" + + +Datum +heapam_storage_handler(PG_FUNCTION_ARGS) +{ + StorageAmRoutine *amroutine = makeNode(StorageAmRoutine); + + + PG_RETURN_POINTER(amroutine); +} diff --git a/src/backend/access/heap/storageamapi.c b/src/backend/access/heap/storageamapi.c new file mode 100644 index 0000000..def2029 --- /dev/null +++ b/src/backend/access/heap/storageamapi.c @@ -0,0 +1,103 @@ +/*---------------------------------------------------------------------- + * + * storageamapi.c + * Support routines for API for Postgres storage access methods + * + * FIXME: looks like this should be in amapi.c. + * + * Copyright (c) 2016, PostgreSQL Global Development Group + * + * src/backend/access/heap/storageamapi.c + *---------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/htup_details.h" +#include "access/storageamapi.h" +#include "catalog/pg_am.h" +#include "catalog/pg_proc.h" +#include "utils/syscache.h" +#include "utils/memutils.h" + + +/* + * GetStorageAmRoutine + * Call the specified access method handler routine to get its + * StorageAmRoutine struct, which will be palloc'd in the caller's + * memory context. + */ +StorageAmRoutine * +GetStorageAmRoutine(Oid amhandler) +{ + Datum datum; + StorageAmRoutine *routine; + + datum = OidFunctionCall0(amhandler); + routine = (StorageAmRoutine *) DatumGetPointer(datum); + + if (routine == NULL || !IsA(routine, StorageAmRoutine)) + elog(ERROR, "storage access method handler %u did not return a StorageAmRoutine struct", + amhandler); + + return routine; +} + +/* A crock */ +StorageAmRoutine * +GetHeapamStorageAmRoutine(void) +{ + Datum datum; + static StorageAmRoutine *HeapamStorageAmRoutine = NULL; + + if (HeapamStorageAmRoutine == NULL) + { + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + datum = OidFunctionCall0(HEAPAM_STORAGE_AM_HANDLER_OID); + HeapamStorageAmRoutine = (StorageAmRoutine *) DatumGetPointer(datum); + MemoryContextSwitchTo(oldcxt); + } + + return HeapamStorageAmRoutine; +} + +/* + * GetStorageAmRoutineByAmId - look up the handler of the storage access + * method with the given OID, and get its StorageAmRoutine struct. + */ +StorageAmRoutine * +GetStorageAmRoutineByAmId(Oid amoid) +{ + regproc amhandler; + HeapTuple tuple; + Form_pg_am amform; + + /* Get handler function OID for the access method */ + tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(amoid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for access method %u", + amoid); + amform = (Form_pg_am) GETSTRUCT(tuple); + + /* Check that it is a storage access method */ + if (amform->amtype != AMTYPE_STORAGE) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("access method \"%s\" is not of type %s", + NameStr(amform->amname), "STORAGE"))); + + amhandler = amform->amhandler; + + /* Complain if handler OID is invalid */ + if (!RegProcedureIsValid(amhandler)) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("storage access method \"%s\" does not have a handler", + NameStr(amform->amname)))); + + ReleaseSysCache(tuple); + + /* And finally, call the handler function to get the API struct. */ + return GetStorageAmRoutine(amhandler); +} diff --git a/src/include/access/htup.h b/src/include/access/htup.h index 61b3e68..6459435 100644 --- a/src/include/access/htup.h +++ b/src/include/access/htup.h @@ -26,6 +26,27 @@ typedef struct MinimalTupleData MinimalTupleData; typedef MinimalTupleData *MinimalTuple; +typedef enum tuple_visibility_type +{ + MVCC_VISIBILITY = 0, /* HeapTupleSatisfiesMVCC */ + SELF_VISIBILITY, /* HeapTupleSatisfiesSelf */ + ANY_VISIBILITY, /* HeapTupleSatisfiesAny */ + TOAST_VISIBILITY, /* HeapTupleSatisfiesToast */ + DIRTY_VISIBILITY, /* HeapTupleSatisfiesDirty */ + HISTORIC_MVCC_VISIBILITY, /* HeapTupleSatisfiesHistoricMVCC */ + + END_OF_VISIBILITY +} tuple_visibility_type; + +/* Result codes for HeapTupleSatisfiesVacuum */ +typedef enum +{ + HEAPTUPLE_DEAD, /* tuple is dead and deletable */ + HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */ + HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */ + HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ + HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */ +} HTSV_Result; /* * HeapTupleData is an in-memory data structure that points to a tuple. diff --git a/src/include/access/storageamapi.h b/src/include/access/storageamapi.h new file mode 100644 index 0000000..95fe028 --- /dev/null +++ b/src/include/access/storageamapi.h @@ -0,0 +1,237 @@ +/*--------------------------------------------------------------------- + * + * storageamapi.h + * API for Postgres storage access methods + * + * Copyright (c) 2016, PostgreSQL Global Development Group + * + * src/include/access/storageamapi.h + *--------------------------------------------------------------------- + */ +#ifndef STORAGEAMAPI_H +#define STORAGEAMAPI_H + +#include "access/htup.h" +#include "access/heapam.h" +#include "access/sdir.h" +#include "access/skey.h" +#include "executor/tuptable.h" +#include "utils/relcache.h" +#include "utils/snapshot.h" + +/* A physical tuple coming from a storage AM scan */ +typedef void *StorageTuple; + +typedef union tuple_data +{ + TransactionId xid; + CommandId cid; + ItemPointerData tid; +} tuple_data; + +typedef enum tuple_data_flags +{ + XMIN = 0, + UPDATED_XID, + CMIN, + TID, + CTID +} tuple_data_flags; + + +typedef HeapScanDesc (*scan_begin_hook) (Relation relation, + Snapshot snapshot, + int nkeys, ScanKey key, + ParallelHeapScanDesc parallel_scan, + bool allow_strat, + bool allow_sync, + bool allow_pagemode, + bool is_bitmapscan, + bool is_samplescan, + bool temp_snap); +typedef void (*scan_setlimits_hook) (HeapScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks); + +/* must return a TupleTableSlot? */ +typedef StorageTuple (*scan_getnext_hook) (HeapScanDesc scan, + ScanDirection direction); + +typedef TupleTableSlot* (*scan_getnext_slot_hook) (HeapScanDesc scan, + ScanDirection direction, TupleTableSlot *slot); + +typedef void (*scan_end_hook) (HeapScanDesc scan); + + +typedef void (*scan_getpage_hook) (HeapScanDesc scan, BlockNumber page); +typedef void (*scan_rescan_hook) (HeapScanDesc scan, ScanKey key, bool set_params, + bool allow_strat, bool allow_sync, bool allow_pagemode); +typedef void (*scan_update_snapshot_hook) (HeapScanDesc scan, Snapshot snapshot); + +typedef bool (*hot_search_buffer_hook) (ItemPointer tid, Relation relation, + Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, + bool *all_dead, bool first_call); + +typedef Oid (*tuple_insert_hook) (Relation relation, + TupleTableSlot *tupslot, + CommandId cid, + int options, + BulkInsertState bistate); + +typedef HTSU_Result (*tuple_delete_hook) (Relation relation, + ItemPointer tid, + CommandId cid, + Snapshot crosscheck, + bool wait, + HeapUpdateFailureData *hufd); + +typedef HTSU_Result (*tuple_update_hook) (Relation relation, + ItemPointer otid, + TupleTableSlot *slot, + CommandId cid, + Snapshot crosscheck, + bool wait, + HeapUpdateFailureData *hufd, + LockTupleMode *lockmode); + +typedef bool (*tuple_fetch_hook) (Relation relation, + ItemPointer tid, + Snapshot snapshot, + StorageTuple *tuple, + Buffer *userbuf, + bool keep_buf, + Relation stats_relation); + +typedef HTSU_Result (*tuple_lock_hook) (Relation relation, + ItemPointer tid, + StorageTuple *tuple, + CommandId cid, + LockTupleMode mode, + LockWaitPolicy wait_policy, + bool follow_update, + Buffer *buffer, + HeapUpdateFailureData *hufd); + +typedef void (*multi_insert_hook) (Relation relation, HeapTuple *tuples, int ntuples, + CommandId cid, int options, BulkInsertState bistate); + +typedef bool (*tuple_freeze_hook) (HeapTupleHeader tuple, TransactionId cutoff_xid, + TransactionId cutoff_multi); + +typedef void (*tuple_get_latest_tid_hook) (Relation relation, + Snapshot snapshot, + ItemPointer tid); + +typedef tuple_data (*get_tuple_data_hook) (StorageTuple tuple, tuple_data_flags flags); + +typedef StorageTuple (*tuple_from_datum_hook) (Datum data, Oid tableoid); + +typedef bool (*tuple_is_heaponly_hook) (StorageTuple tuple); + +typedef void (*slot_store_tuple_hook) (TupleTableSlot *slot, + StorageTuple tuple, + bool shouldFree, + bool minumumtuple); +typedef void (*slot_clear_tuple_hook) (TupleTableSlot *slot); +typedef Datum (*slot_getattr_hook) (TupleTableSlot *slot, + int attnum, bool *isnull); +typedef void (*slot_virtualize_tuple_hook) (TupleTableSlot *slot, int16 upto); + +typedef HeapTuple (*slot_tuple_hook) (TupleTableSlot *slot, bool palloc_copy); +typedef MinimalTuple (*slot_min_tuple_hook) (TupleTableSlot *slot, bool palloc_copy); + +typedef void (*slot_update_tableoid_hook) (TupleTableSlot *slot, Oid tableoid); + +typedef void (*speculative_finish_hook) (Relation rel, + TupleTableSlot *slot); +typedef void (*speculative_abort_hook) (Relation rel, + TupleTableSlot *slot); + +typedef void (*relation_sync_hook) (Relation relation); + +typedef bool (*snapshot_satisfies_hook) (StorageTuple htup, Snapshot snapshot, Buffer buffer); +typedef HTSU_Result (*snapshot_satisfies_update_hook) (StorageTuple htup, CommandId curcid, Buffer buffer); +typedef HTSV_Result (*snapshot_satisfies_vacuum_hook) (StorageTuple htup, TransactionId OldestXmin, Buffer buffer); + +typedef struct StorageSlotAmRoutine +{ + /* Operations on TupleTableSlot */ + slot_store_tuple_hook slot_store_tuple; + slot_virtualize_tuple_hook slot_virtualize_tuple; + slot_clear_tuple_hook slot_clear_tuple; + slot_getattr_hook slot_getattr; + slot_tuple_hook slot_tuple; + slot_min_tuple_hook slot_min_tuple; + slot_update_tableoid_hook slot_update_tableoid; +} StorageSlotAmRoutine; + +typedef StorageSlotAmRoutine* (*slot_storageam_hook) (void); + +/* + * API struct for a storage AM. Note this must be stored in a single palloc'd + * chunk of memory. + * + * XXX currently all functions are together in a single struct. Would it be + * worthwhile to split the slot-accessor functions to a different struct? + * That way, MinimalTuple could be handled without a complete StorageAmRoutine + * for them -- it'd only have a few functions in TupleTableSlotAmRoutine or so. + */ +typedef struct StorageAmRoutine +{ + NodeTag type; + + /* Operations on relation scans */ + scan_begin_hook scan_begin; + scan_setlimits_hook scansetlimits; + scan_getnext_hook scan_getnext; + scan_getnext_slot_hook scan_getnextslot; + scan_end_hook scan_end; + scan_getpage_hook scan_getpage; + scan_rescan_hook scan_rescan; + scan_update_snapshot_hook scan_update_snapshot; + hot_search_buffer_hook hot_search_buffer; /* heap_hot_search_buffer */ + + // heap_sync_function heap_sync; /* heap_sync */ + /* not implemented */ + // parallelscan_estimate_function parallelscan_estimate; /* heap_parallelscan_estimate */ + // parallelscan_initialize_function parallelscan_initialize; /* heap_parallelscan_initialize */ + // parallelscan_begin_function parallelscan_begin; /* heap_beginscan_parallel */ + + /* Operations on physical tuples */ + tuple_insert_hook tuple_insert; /* heap_insert */ + tuple_update_hook tuple_update; /* heap_update */ + tuple_delete_hook tuple_delete; /* heap_delete */ + tuple_fetch_hook tuple_fetch; /* heap_fetch */ + tuple_lock_hook tuple_lock; /* heap_lock_tuple */ + multi_insert_hook multi_insert; /* heap_multi_insert */ + tuple_freeze_hook tuple_freeze; /* heap_freeze_tuple */ + tuple_get_latest_tid_hook tuple_get_latest_tid; /* heap_get_latest_tid */ + + get_tuple_data_hook get_tuple_data; + tuple_is_heaponly_hook tuple_is_heaponly; + tuple_from_datum_hook tuple_from_datum; + + + slot_storageam_hook slot_storageam; + + /* + * Speculative insertion support operations + * + * Setting a tuple's speculative token is a slot-only operation, so no need + * for a storage AM method, but after inserting a tuple containing a + * speculative token, the insertion must be completed by these routines: + */ + speculative_finish_hook speculative_finish; + speculative_abort_hook speculative_abort; + + + relation_sync_hook relation_sync; /* heap_sync */ + + snapshot_satisfies_hook snapshot_satisfies[END_OF_VISIBILITY]; + snapshot_satisfies_update_hook snapshot_satisfiesUpdate; /* HeapTupleSatisfiesUpdate */ + snapshot_satisfies_vacuum_hook snapshot_satisfiesVacuum; /* HeapTupleSatisfiesVacuum */ +} StorageAmRoutine; + +extern StorageAmRoutine *GetStorageAmRoutine(Oid amhandler); +extern StorageAmRoutine *GetStorageAmRoutineByAmId(Oid amoid); +extern StorageAmRoutine *GetHeapamStorageAmRoutine(void); + +#endif /* STORAGEAMAPI_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 6b675b0..1dfb711 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -558,6 +558,11 @@ DESCR("convert int4 to float4"); DATA(insert OID = 319 ( int4 PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 23 "700" _null_ _null_ _null_ _null_ _null_ ftoi4 _null_ _null_ _null_ )); DESCR("convert float4 to int4"); +/* Storage access method handlers */ +DATA(insert OID = 4002 ( heapam_storage_handler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 3998 "2281" _null_ _null_ _null_ _null_ _null_ heapam_storage_handler _null_ _null_ _null_ )); +DESCR("row-oriented storage access method handler"); +#define HEAPAM_STORAGE_AM_HANDLER_OID 4002 + /* Index access method handlers */ DATA(insert OID = 330 ( bthandler PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 325 "2281" _null_ _null_ _null_ _null_ _null_ bthandler _null_ _null_ _null_ )); DESCR("btree index access method handler"); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 27bd4f3..108df9b 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -496,6 +496,7 @@ typedef enum NodeTag T_InlineCodeBlock, /* in nodes/parsenodes.h */ T_FdwRoutine, /* in foreign/fdwapi.h */ T_IndexAmRoutine, /* in access/amapi.h */ + T_StorageAmRoutine, /* in access/storageamapi.h */ T_TsmRoutine, /* in access/tsmapi.h */ T_ForeignKeyCacheInfo /* in utils/rel.h */ } NodeTag; diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 9a3b56e..de75e01 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -45,15 +45,6 @@ extern PGDLLIMPORT SnapshotData CatalogSnapshotData; #define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer) \ ((*(snapshot)->satisfies) (tuple, snapshot, buffer)) -/* Result codes for HeapTupleSatisfiesVacuum */ -typedef enum -{ - HEAPTUPLE_DEAD, /* tuple is dead and deletable */ - HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */ - HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */ - HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ - HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */ -} HTSV_Result; /* These are the "satisfies" test routines for the various snapshot types */ extern bool HeapTupleSatisfiesMVCC(HeapTuple htup, -- 2.7.4.windows.1