gist.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*-------------------------------------------------------------------------
  2. *
  3. * gist.h
  4. * The public API for GiST indexes. This API is exposed to
  5. * individuals implementing GiST indexes, so backward-incompatible
  6. * changes should be made with care.
  7. *
  8. *
  9. * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
  10. * Portions Copyright (c) 1994, Regents of the University of California
  11. *
  12. * src/include/access/gist.h
  13. *
  14. *-------------------------------------------------------------------------
  15. */
  16. #ifndef GIST_H
  17. #define GIST_H
  18. #include "access/itup.h"
  19. #include "access/transam.h"
  20. #include "access/xlog.h"
  21. #include "access/xlogdefs.h"
  22. #include "storage/block.h"
  23. #include "storage/bufpage.h"
  24. #include "utils/relcache.h"
  25. /*
  26. * amproc indexes for GiST indexes.
  27. */
  28. #define GIST_CONSISTENT_PROC 1
  29. #define GIST_UNION_PROC 2
  30. #define GIST_COMPRESS_PROC 3
  31. #define GIST_DECOMPRESS_PROC 4
  32. #define GIST_PENALTY_PROC 5
  33. #define GIST_PICKSPLIT_PROC 6
  34. #define GIST_EQUAL_PROC 7
  35. #define GIST_DISTANCE_PROC 8
  36. #define GIST_FETCH_PROC 9
  37. #define GIST_OPTIONS_PROC 10
  38. #define GIST_SORTSUPPORT_PROC 11
  39. #define GISTNProcs 11
  40. /*
  41. * Page opaque data in a GiST index page.
  42. */
  43. #define F_LEAF (1 << 0) /* leaf page */
  44. #define F_DELETED (1 << 1) /* the page has been deleted */
  45. #define F_TUPLES_DELETED (1 << 2) /* some tuples on the page were
  46. * deleted */
  47. #define F_FOLLOW_RIGHT (1 << 3) /* page to the right has no downlink */
  48. #define F_HAS_GARBAGE (1 << 4) /* some tuples on the page are dead,
  49. * but not deleted yet */
  50. /*
  51. * NSN (node sequence number) is a special-purpose LSN which is stored on each
  52. * index page in GISTPageOpaqueData and updated only during page splits. By
  53. * recording the parent's LSN in GISTSearchItem.parentlsn, it is possible to
  54. * detect concurrent child page splits by checking if parentlsn < child's NSN,
  55. * and handle them properly. The child page's LSN is insufficient for this
  56. * purpose since it is updated for every page change.
  57. */
  58. typedef XLogRecPtr GistNSN;
  59. /*
  60. * A fake LSN / NSN value used during index builds. Must be smaller than any
  61. * real or fake (unlogged) LSN generated after the index build completes so
  62. * that all splits are considered complete.
  63. */
  64. #define GistBuildLSN ((XLogRecPtr) 1)
  65. /*
  66. * For on-disk compatibility with pre-9.3 servers, NSN is stored as two
  67. * 32-bit fields on disk, same as LSNs.
  68. */
  69. typedef PageXLogRecPtr PageGistNSN;
  70. typedef struct GISTPageOpaqueData
  71. {
  72. PageGistNSN nsn; /* this value must change on page split */
  73. BlockNumber rightlink; /* next page if any */
  74. uint16 flags; /* see bit definitions above */
  75. uint16 gist_page_id; /* for identification of GiST indexes */
  76. } GISTPageOpaqueData;
  77. typedef GISTPageOpaqueData *GISTPageOpaque;
  78. /*
  79. * Maximum possible sizes for GiST index tuple and index key. Calculation is
  80. * based on assumption that GiST page should fit at least 4 tuples. In theory,
  81. * GiST index can be functional when page can fit 3 tuples. But that seems
  82. * rather inefficient, so we use a bit conservative estimate.
  83. *
  84. * The maximum size of index key is true for unicolumn index. Therefore, this
  85. * estimation should be used to figure out which maximum size of GiST index key
  86. * makes sense at all. For multicolumn indexes, user might be able to tune
  87. * key size using opclass parameters.
  88. */
  89. #define GISTMaxIndexTupleSize \
  90. MAXALIGN_DOWN((BLCKSZ - SizeOfPageHeaderData - sizeof(GISTPageOpaqueData)) / \
  91. 4 - sizeof(ItemIdData))
  92. #define GISTMaxIndexKeySize \
  93. (GISTMaxIndexTupleSize - MAXALIGN(sizeof(IndexTupleData)))
  94. /*
  95. * The page ID is for the convenience of pg_filedump and similar utilities,
  96. * which otherwise would have a hard time telling pages of different index
  97. * types apart. It should be the last 2 bytes on the page. This is more or
  98. * less "free" due to alignment considerations.
  99. */
  100. #define GIST_PAGE_ID 0xFF81
  101. /*
  102. * This is the Split Vector to be returned by the PickSplit method.
  103. * PickSplit should fill the indexes of tuples to go to the left side into
  104. * spl_left[], and those to go to the right into spl_right[] (note the method
  105. * is responsible for palloc'ing both of these arrays!). The tuple counts
  106. * go into spl_nleft/spl_nright, and spl_ldatum/spl_rdatum must be set to
  107. * the union keys for each side.
  108. *
  109. * If spl_ldatum_exists and spl_rdatum_exists are true, then we are performing
  110. * a "secondary split" using a non-first index column. In this case some
  111. * decisions have already been made about a page split, and the set of tuples
  112. * being passed to PickSplit is just the tuples about which we are undecided.
  113. * spl_ldatum/spl_rdatum then contain the union keys for the tuples already
  114. * chosen to go left or right. Ideally the PickSplit method should take those
  115. * keys into account while deciding what to do with the remaining tuples, ie
  116. * it should try to "build out" from those unions so as to minimally expand
  117. * them. If it does so, it should union the given tuples' keys into the
  118. * existing spl_ldatum/spl_rdatum values rather than just setting those values
  119. * from scratch, and then set spl_ldatum_exists/spl_rdatum_exists to false to
  120. * show it has done this.
  121. *
  122. * If the PickSplit method fails to clear spl_ldatum_exists/spl_rdatum_exists,
  123. * the core GiST code will make its own decision about how to merge the
  124. * secondary-split results with the previously-chosen tuples, and will then
  125. * recompute the union keys from scratch. This is a workable though often not
  126. * optimal approach.
  127. */
  128. typedef struct GIST_SPLITVEC
  129. {
  130. OffsetNumber *spl_left; /* array of entries that go left */
  131. int spl_nleft; /* size of this array */
  132. Datum spl_ldatum; /* Union of keys in spl_left */
  133. bool spl_ldatum_exists; /* true, if spl_ldatum already exists. */
  134. OffsetNumber *spl_right; /* array of entries that go right */
  135. int spl_nright; /* size of the array */
  136. Datum spl_rdatum; /* Union of keys in spl_right */
  137. bool spl_rdatum_exists; /* true, if spl_rdatum already exists. */
  138. } GIST_SPLITVEC;
  139. /*
  140. * An entry on a GiST node. Contains the key, as well as its own
  141. * location (rel,page,offset) which can supply the matching pointer.
  142. * leafkey is a flag to tell us if the entry is in a leaf node.
  143. */
  144. typedef struct GISTENTRY
  145. {
  146. Datum key;
  147. Relation rel;
  148. Page page;
  149. OffsetNumber offset;
  150. bool leafkey;
  151. } GISTENTRY;
  152. #define GistPageGetOpaque(page) ( (GISTPageOpaque) PageGetSpecialPointer(page) )
  153. #define GistPageIsLeaf(page) ( GistPageGetOpaque(page)->flags & F_LEAF)
  154. #define GIST_LEAF(entry) (GistPageIsLeaf((entry)->page))
  155. #define GistPageIsDeleted(page) ( GistPageGetOpaque(page)->flags & F_DELETED)
  156. #define GistTuplesDeleted(page) ( GistPageGetOpaque(page)->flags & F_TUPLES_DELETED)
  157. #define GistMarkTuplesDeleted(page) ( GistPageGetOpaque(page)->flags |= F_TUPLES_DELETED)
  158. #define GistClearTuplesDeleted(page) ( GistPageGetOpaque(page)->flags &= ~F_TUPLES_DELETED)
  159. #define GistPageHasGarbage(page) ( GistPageGetOpaque(page)->flags & F_HAS_GARBAGE)
  160. #define GistMarkPageHasGarbage(page) ( GistPageGetOpaque(page)->flags |= F_HAS_GARBAGE)
  161. #define GistClearPageHasGarbage(page) ( GistPageGetOpaque(page)->flags &= ~F_HAS_GARBAGE)
  162. #define GistFollowRight(page) ( GistPageGetOpaque(page)->flags & F_FOLLOW_RIGHT)
  163. #define GistMarkFollowRight(page) ( GistPageGetOpaque(page)->flags |= F_FOLLOW_RIGHT)
  164. #define GistClearFollowRight(page) ( GistPageGetOpaque(page)->flags &= ~F_FOLLOW_RIGHT)
  165. #define GistPageGetNSN(page) ( PageXLogRecPtrGet(GistPageGetOpaque(page)->nsn))
  166. #define GistPageSetNSN(page, val) ( PageXLogRecPtrSet(GistPageGetOpaque(page)->nsn, val))
  167. /*
  168. * On a deleted page, we store this struct. A deleted page doesn't contain any
  169. * tuples, so we don't use the normal page layout with line pointers. Instead,
  170. * this struct is stored right after the standard page header. pd_lower points
  171. * to the end of this struct. If we add fields to this struct in the future, we
  172. * can distinguish the old and new formats by pd_lower.
  173. */
  174. typedef struct GISTDeletedPageContents
  175. {
  176. /* last xid which could see the page in a scan */
  177. FullTransactionId deleteXid;
  178. } GISTDeletedPageContents;
  179. static inline void
  180. GistPageSetDeleted(Page page, FullTransactionId deletexid)
  181. {
  182. Assert(PageIsEmpty(page));
  183. GistPageGetOpaque(page)->flags |= F_DELETED;
  184. ((PageHeader) page)->pd_lower = MAXALIGN(SizeOfPageHeaderData) + sizeof(GISTDeletedPageContents);
  185. ((GISTDeletedPageContents *) PageGetContents(page))->deleteXid = deletexid;
  186. }
  187. static inline FullTransactionId
  188. GistPageGetDeleteXid(Page page)
  189. {
  190. Assert(GistPageIsDeleted(page));
  191. /* Is the deleteXid field present? */
  192. if (((PageHeader) page)->pd_lower >= MAXALIGN(SizeOfPageHeaderData) +
  193. offsetof(GISTDeletedPageContents, deleteXid) + sizeof(FullTransactionId))
  194. {
  195. return ((GISTDeletedPageContents *) PageGetContents(page))->deleteXid;
  196. }
  197. else
  198. return FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
  199. }
  200. /*
  201. * Vector of GISTENTRY structs; user-defined methods union and picksplit
  202. * take it as one of their arguments
  203. */
  204. typedef struct
  205. {
  206. int32 n; /* number of elements */
  207. GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER];
  208. } GistEntryVector;
  209. #define GEVHDRSZ (offsetof(GistEntryVector, vector))
  210. /*
  211. * macro to initialize a GISTENTRY
  212. */
  213. #define gistentryinit(e, k, r, pg, o, l) \
  214. do { (e).key = (k); (e).rel = (r); (e).page = (pg); \
  215. (e).offset = (o); (e).leafkey = (l); } while (0)
  216. #endif /* GIST_H */