1d540f44创建于 2021年9月23日历史提交
/* -------------------------------------------------------------------------
 *
 * dynahash
 *	  openGauss dynahash.h file definitions
 *
 *
 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/utils/dynahash.h
 *
 * -------------------------------------------------------------------------
 */
#ifndef DYNAHASH_H
#define DYNAHASH_H

#include "storage/buf/buf_internals.h"
#include "storage/lock/s_lock.h"
#include "utils/hsearch.h"

/* Number of freelists to be used for a partitioned hash table. */
#define NUM_FREELISTS 32

/* A hash bucket is a linked list of HASHELEMENTs */
typedef HASHELEMENT* HASHBUCKET;

/* A hash segment is an array of bucket headers */
typedef HASHBUCKET* HASHSEGMENT;

/*
 * Using array of FreeListData instead of separate arrays of mutexes, nentries
 * and freeLists prevents, at least partially, sharing one cache line between
 * different mutexes (see below).
 */
typedef struct {
    slock_t mutex;         /* spinlock */
    long nentries;         /* number of entries */
    HASHELEMENT* freeList; /* list of free elements */
} FreeListData;

/*
 * Header structure for a hash table --- contains all changeable info
 *
 * In a shared-memory hash table, the HASHHDR is in shared memory, while
 * each backend has a local HTAB struct.  For a non-shared table, there isn't
 * any functional difference between HASHHDR and HTAB, but we separate them
 * anyway to share code between shared and non-shared tables.
 */
struct HASHHDR {
    /*
     * The freelist can become a point of contention on high-concurrency hash
     * tables, so we use an array of freelist, each with its own mutex and
     * nentries count, instead of just a single one.
     *
     * If hash table is not partitioned only freeList[0] is used and spinlocks
     * are not used at all.
     */
    FreeListData freeList[NUM_FREELISTS];

    /* These fields can change, but not in a partitioned table */
    /* Also, dsize can't change in a shared table, even if unpartitioned */
    long dsize;        /* directory size */
    long nsegs;        /* number of allocated segments (<= dsize) */
    uint32 max_bucket; /* ID of maximum bucket in use */
    uint32 high_mask;  /* mask to modulo into entire table */
    uint32 low_mask;   /* mask to modulo into lower half of table */

    /* These fields are fixed at hashtable creation */
    Size keysize;        /* hash key length in bytes */
    Size entrysize;      /* total user element size in bytes */
    long num_partitions; /* # partitions (must be power of 2), or 0 */
    long ffactor;        /* target fill factor */
    long max_dsize;      /* 'dsize' limit if directory is fixed size */
    long ssize;          /* segment size --- must be power of 2 */
    int sshift;          /* segment shift = log2(ssize) */
    int nelem_alloc;     /* number of entries to allocate at once */

#ifdef HASH_STATISTICS

    /*
     * Count statistics here.  NB: stats code doesn't bother with mutex, so
     * counts could be corrupted a bit in a partitioned table.
     */
    long accesses;
    long collisions;
#endif
};

/* the offset of the last padding if exists*/
#define HTAB_PAD_OFFSET 104

/*
 * Top control structure for a hashtable --- in a shared table, each backend
 * has its own copy (OK since no fields change at runtime)
 */
struct HTAB {
    HASHHDR* hctl;           /* => shared control information */
    HASHSEGMENT* dir;        /* directory of segment starts */
    HashValueFunc hash;      /* hash function */
    HashCompareFunc match;   /* key comparison function */
    HashCopyFunc keycopy;    /* key copying function */
    HashAllocFunc alloc;     /* memory allocator */
    HashDeallocFunc dealloc; /* memory deallocator */
    MemoryContext hcxt;      /* memory context if default allocator used */
    char* tabname;           /* table name (for error messages) */
    bool isshared;           /* true if table is in shared memory */
    bool isfixed;            /* if true, don't enlarge */

    /* freezing a shared table isn't allowed, so we can keep state here */
    bool frozen; /* true = no more inserts allowed */

    /* We keep local copies of these fixed values to reduce contention */
    Size keysize; /* hash key length in bytes */
    long ssize;   /* segment size --- must be power of 2 */
    int sshift;   /* segment shift = log2(ssize) */
#ifdef __aarch64__
    char pad[PG_CACHE_LINE_SIZE - HTAB_PAD_OFFSET];
#endif
};

extern int my_log2(long num);
template <HASHACTION action>
void* buf_hash_operate(HTAB* hashp, const BufferTag* keyPtr, uint32 hashvalue, bool* foundPtr);
#endif /* DYNAHASH_H */