PostgreSQL 后台进程对共享内存的指针

开始

/*                    

 *    InitShmemIndex() --- set up or attach to shmem index table.                

 */                    

void                    

InitShmemIndex(void)                    

{                    

    HASHCTL        info;        

    int        hash_flags;        

                    

    /*                

     * Create the shared memory shmem index.                

     *                

     * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex                

     * hashtable to exist already, we have a bit of a circularity problem in                

     * initializing the ShmemIndex itself.                The special "ShmemIndex" hash

     * table name will tell ShmemInitStruct to fake it.                

     */                

    info.keysize = SHMEM_INDEX_KEYSIZE;                

    info.entrysize = sizeof(ShmemIndexEnt);                

    hash_flags = HASH_ELEM;                

                    

    ShmemIndex = ShmemInitHash("ShmemIndex",                

                       SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,

                       &info, hash_flags);

}                    

其实 ShmemIndex 就是对共享内存的指针:

/*                            

 * ShmemInitHash -- Create and initialize, or attach to, a                            

 *        shared memory hash table.                    

 *                            

 * We assume caller is doing some kind of synchronization                            

 * so that two processes don't try to create/initialize the same                            

 * table at once.  (In practice, all creations are done in the postmaster                            

 * process; child processes should always be attaching to existing tables.)                            

 *                            

 * max_size is the estimated maximum number of hashtable entries.  This is                            

 * not a hard limit, but the access efficiency will degrade if it is                            

 * exceeded substantially (since it's used to compute directory size and                            

 * the hash table buckets will get overfull).                            

 *                            

 * init_size is the number of hashtable entries to preallocate.  For a table                            

 * whose maximum size is certain, this should be equal to max_size; that                            

 * ensures that no run-time out-of-shared-memory failures can occur.                            

 *                            

 * Note: before Postgres 9.0, this function returned NULL for some failure                            

 * cases.  Now, it always throws error instead, so callers need not check                            

 * for NULL.                            

 */                            

HTAB *                            

ShmemInitHash(const char *name, /* table string name for shmem index */                            

              long init_size,    /* initial table size */            

              long max_size,    /* max size of the table */            

              HASHCTL *infoP,    /* info about key and bucket size */            

              int hash_flags)    /* info about infoP */            

{                            

    bool       found;                    

    void       *location;                    

                            

    /*                        

     * Hash tables allocated in shared memory have a fixed directory; it can't                        

     * grow or other backends wouldn't be able to find it. So, make sure we                        

     * make it big enough to start with.                        

     *                        

     * The shared memory allocator must be specified too.                        

     */                        

    infoP->dsize = infoP->max_dsize = hash_select_dirsize(max_size);                        

    infoP->alloc = ShmemAlloc;                        

    hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;                        

                            

    /* look it up in the shmem index */                        

    location = ShmemInitStruct(name,                        

                   hash_get_shared_size(infoP, hash_flags),            

                   &found);            

                            

    /*                        

     * if it already exists, attach to it rather than allocate and initialize                        

     * new space                        

     */                        

    if (found)                        

        hash_flags |= HASH_ATTACH;                    

                            

    /* Pass location of hashtable header to hash_create */                        

    infoP->hctl = (HASHHDR *) location;                        

                            

    return hash_create(name, init_size, infoP, hash_flags);                        

}                            

看hash_create 的相关代码:

/*                                

 * hash_create -- create a new dynamic hash table                                

 *                                

 *    tabname: a name for the table (for debugging purposes)                            

 *    nelem: maximum number of elements expected                            

 *    *info: additional table parameters, as indicated by flags                            

 *    flags: bitmask indicating which parameters to take from *info                            

 *                                

 * Note: for a shared-memory hashtable, nelem needs to be a pretty good                                

 * estimate, since we can't expand the table on the fly.  But an unshared                                

 * hashtable can be expanded on-the-fly, so it's better for nelem to be                                

 * on the small side and let the table grow if it's exceeded.  An overly                                

 * large nelem will penalize hash_seq_search speed without buying much.                                

 */                                

HTAB *                                

hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)                                

{                                

    HTAB       *hashp;                        

    HASHHDR    *hctl;                            

                                

    /*                            

     * For shared hash tables, we have a local hash header (HTAB struct) that                            

     * we allocate in TopMemoryContext; all else is in shared memory.                            

     *                            

     * For non-shared hash tables, everything including the hash header is in                            

     * a memory context created specially for the hash table --- this makes                            

     * hash_destroy very simple.  The memory context is made a child of either                            

     * a context specified by the caller, or TopMemoryContext if nothing is                            

     * specified.                            

     */                            

    if (flags & HASH_SHARED_MEM)                            

    {                            

        /* Set up to allocate the hash header */                        

        CurrentDynaHashCxt = TopMemoryContext;                        

    }                            

    else                            

    {                            

        /* Create the hash table's private memory context */                        

        if (flags & HASH_CONTEXT)                        

            CurrentDynaHashCxt = info->hcxt;                    

        else                        

            CurrentDynaHashCxt = TopMemoryContext;                    

        CurrentDynaHashCxt = AllocSetContextCreate(CurrentDynaHashCxt,                        

                                   tabname,

                                   ALLOCSET_DEFAULT_MINSIZE,

                                   ALLOCSET_DEFAULT_INITSIZE,

                                   ALLOCSET_DEFAULT_MAXSIZE);

    }                            

                                

    /* Initialize the hash header, plus a copy of the table name */                            

    hashp = (HTAB *) DynaHashAlloc(sizeof(HTAB) + strlen(tabname) +1);                            

    MemSet(hashp, 0, sizeof(HTAB));                            

                                

    hashp->tabname = (char *) (hashp + 1);                            

    strcpy(hashp->tabname, tabname);                            

                                

    ……                            

    if (flags & HASH_SHARED_MEM)                            

    {                            

        /*                        

         * ctl structure and directory are preallocated for shared memory                        

         * tables.    Note that HASH_DIRSIZE and HASH_ALLOC had better be set as                    

         * well.                        

         */                        

        hashp->hctl = info->hctl;                        

        hashp->dir = (HASHSEGMENT *) (((char *) info->hctl) + sizeof(HASHHDR));                        

        hashp->hcxt = NULL;                        

        hashp->isshared = true;                        

                                

        /* hash table already exists, we're just attaching to it */                        

        if (flags & HASH_ATTACH)                        

        {                        

            /* make local copies of some heavily-used values */                    

            hctl = hashp->hctl;                    

            hashp->keysize = hctl->keysize;                    

            hashp->ssize = hctl->ssize;                    

            hashp->sshift = hctl->sshift;                    

                                

            return hashp;                    

        }                        

    }                            

    else                            

    {                            

        ……                        

    }                            

                                

    if (!hashp->hctl)                            

    {                            

        hashp->hctl = (HASHHDR *) hashp->alloc(sizeof(HASHHDR));                        

        if (!hashp->hctl)                        

            ereport(ERROR,                    

                    (errcode(ERRCODE_OUT_OF_MEMORY),            

                     errmsg("out of memory")));            

    }                            

                                

    ……                            

    if (flags & HASH_FIXED_SIZE)                            

        hashp->isfixed = true;                        

    return hashp;                            

}                                

在 src/backend/storage/ipc/shmem.c 的注释中也是这么说的:

/*
* POSTGRES processes share one or more regions of shared memory.
* The shared memory is created by a postmaster and is inherited
* by each backend via fork() (or, in some ports, via other OS-specific
* methods). The routines in this file are used for allocating and
* binding to shared memory data structures.

......

/

......

static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */

[作者:技术者高健@博客园  mail: [email protected] ]

结束

你可能感兴趣的:(PostgreSQL)