diff --git a/src/backend/access/common/tidstore.c b/src/backend/access/common/tidstore.c index 9360520482..fc20e58a95 100644 --- a/src/backend/access/common/tidstore.c +++ b/src/backend/access/common/tidstore.c @@ -75,6 +75,14 @@ typedef uint64 offsetbm; #define LOWER_OFFSET_NBITS 6 /* log(sizeof(offsetbm), 2) */ #define LOWER_OFFSET_MASK ((1 << LOWER_OFFSET_NBITS) - 1) +/* + * The minimum amount of memory required by TidStore is 2MB, the current minimum + * valid value for the maintenance_work_mem GUC. This is required to allocate the + * DSA initial segment, 1MB, and some meta data. This number is applied also to + * the local TidStore cases for simplicity. + */ +#define TIDSTORE_MIN_MEMORY (2 * 1024 * 1024L) /* 2MB */ + /* A magic value used to identify our TidStore. */ #define TIDSTORE_MAGIC 0x826f6a10 @@ -101,7 +109,7 @@ typedef struct TidStoreControl /* These values are never changed after creation */ size_t max_bytes; /* the maximum bytes a TidStore can use */ - int max_off; /* the maximum offset number */ + OffsetNumber max_off; /* the maximum offset number */ int max_off_nbits; /* the number of bits required for offset * numbers */ int upper_off_nbits; /* the number of bits of offset numbers @@ -174,10 +182,17 @@ static inline tidkey encode_tid(TidStore *ts, ItemPointer tid, offsetbm *off_bit * The radix tree for storage is allocated in DSA area is 'area' is non-NULL. */ TidStore * -TidStoreCreate(size_t max_bytes, int max_off, dsa_area *area) +TidStoreCreate(size_t max_bytes, OffsetNumber max_off, dsa_area *area) { TidStore *ts; + Assert(max_off <= MaxOffsetNumber); + + /* Sanity check for the max_bytes */ + if (max_bytes < TIDSTORE_MIN_MEMORY) + elog(ERROR, "memory for TidStore must be at least %ld, but %zu provided", + TIDSTORE_MIN_MEMORY, max_bytes); + ts = palloc0(sizeof(TidStore)); /* @@ -192,8 +207,8 @@ TidStoreCreate(size_t max_bytes, int max_off, dsa_area *area) * In local TidStore cases, the radix tree uses slab allocators for each kind * of node class. The most memory consuming case while adding Tids associated * with one page (i.e. during TidStoreSetBlockOffsets()) is that we allocate a new - * slab block for a new radix tree node, which is approximately 70kB. Therefore, - * we deduct 70kB from the max_bytes. + * slab block for a new radix tree node, which is approximately 70kB at most. + * Therefore, we deduct 70kB from the max_bytes. * * In shared cases, DSA allocates the memory segments big enough to follow * a geometric series that approximately doubles the total DSA size (see @@ -378,6 +393,7 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, const int nkeys = UINT64CONST(1) << ts->control->upper_off_nbits; Assert(!TidStoreIsShared(ts) || ts->control->magic == TIDSTORE_MAGIC); + Assert(BlockNumberIsValid(blkno)); bitmaps = palloc(sizeof(offsetbm) * nkeys); key = prev_key = key_base; @@ -386,6 +402,8 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, { offsetbm off_bit; + Assert(offsets[i] <= ts->control->max_off); + /* encode the tid to a key and partial offset */ key = encode_blk_off(ts, blkno, offsets[i], &off_bit); @@ -452,6 +470,8 @@ TidStoreIsMember(TidStore *ts, ItemPointer tid) offsetbm off_bit; bool found; + Assert(ItemPointerIsValid(tid)); + key = encode_tid(ts, tid, &off_bit); if (TidStoreIsShared(ts)) @@ -535,6 +555,7 @@ TidStoreIterateNext(TidStoreIter *iter) while (tidstore_iter(iter, &key, &off_bitmap)) { BlockNumber blkno = key_get_blkno(iter->ts, key); + Assert(BlockNumberIsValid(blkno)); if (BlockNumberIsValid(output->blkno) && output->blkno != blkno) { @@ -586,6 +607,7 @@ TidStoreNumTids(TidStore *ts) num_tids = ts->control->num_tids; LWLockRelease(&ts->control->lock); + Assert(num_tids >= 0); return num_tids; } diff --git a/src/include/access/tidstore.h b/src/include/access/tidstore.h index 66f0fdd482..d1cc93cbb6 100644 --- a/src/include/access/tidstore.h +++ b/src/include/access/tidstore.h @@ -30,7 +30,7 @@ typedef struct TidStoreIterResult OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]; } TidStoreIterResult; -extern TidStore *TidStoreCreate(size_t max_bytes, int max_off, dsa_area *dsa); +extern TidStore *TidStoreCreate(size_t max_bytes, OffsetNumber max_off, dsa_area *dsa); extern TidStore *TidStoreAttach(dsa_area *dsa, dsa_pointer handle); extern void TidStoreDetach(TidStore *ts); extern void TidStoreDestroy(TidStore *ts);