对PostgreSQL中后台进程内存挂载的初步学习

开始

从 CreateSharedMemoryAndSemaphores 开始:

对于 Postmaster 的各个子进程而言,内存结构在 Postmaster 中已经建立,只是需要挂到各子进程自己的本地变量上。

/*                            

 * CreateSharedMemoryAndSemaphores                            

 *        Creates and initializes shared memory and semaphores.                    

 *                            

 * This is called by the postmaster or by a standalone backend.                            

 * It is also called by a backend forked from the postmaster in the                            

 * EXEC_BACKEND case.  In the latter case, the shared memory segment                            

 * already exists and has been physically attached to, but we have to                            

 * initialize pointers in local memory that reference the shared structures,                            

 * because we didn't inherit the correct pointer values from the postmaster                            

 * as we do in the fork() scenario.  The easiest way to do that is to run                            

 * through the same code as before.  (Note that the called routines mostly                            

 * check IsUnderPostmaster, rather than EXEC_BACKEND, to detect this case.                            

 * This is a bit code-wasteful and could be cleaned up.)                            

 *                            

 * If "makePrivate" is true then we only need private memory, not shared                            

 * memory.    This is true for a standalone backend, false for a postmaster.                        

 */                            

void                            

CreateSharedMemoryAndSemaphores(bool makePrivate, int port)                            

{                            

    ……                        

    /*                        

     * Set up shmem.c index hashtable                        

     */ InitShmemIndex();                        

                            

    /*                        

     * Set up xlog, clog, and buffers                        

     */                        

    XLOGShmemInit();                        

    CLOGShmemInit();                        

    SUBTRANSShmemInit();                        

    MultiXactShmemInit();                        

    InitBufferPool();                        

                            

    /*                        

     * Set up lock manager                        

     */                        

    InitLocks();                        

                            

    /*                        

     * Set up predicate lock manager                        

     */                        

    InitPredicateLocks();                        

                            

    /*                        

     * Set up process table                        

     */                        

    if (!IsUnderPostmaster)                        

        InitProcGlobal();                    

    CreateSharedProcArray();                        

    CreateSharedBackendStatus();                        

    TwoPhaseShmemInit();                        

                            

    /*                        

     * Set up shared-inval messaging                        

     */                        

    CreateSharedInvalidationState();                        

                            

    /*                        

     * Set up interprocess signaling mechanisms                        

     */                        

    PMSignalShmemInit();                        

    ProcSignalShmemInit();                        

    CheckpointerShmemInit();                        

    AutoVacuumShmemInit();                        

    WalSndShmemInit();                        

    WalRcvShmemInit();                        

                            

    /*                        

     * Set up other modules that need some shared memory space                        

     */                        

    BTreeShmemInit();                        

    SyncScanShmemInit();                        

    AsyncShmemInit();                        

                            

    #ifdef EXEC_BACKEND                        

                            

        /*                    

         * Alloc the win32 shared backend array                    

         */                    

        if (!IsUnderPostmaster)                    

            ShmemBackendArrayAllocation();                

    #endif                        

                            

    /*                        

     * Now give loadable modules a chance to set up their shmem allocations                        

     */                        

    if (shmem_startup_hook)                        

        shmem_startup_hook();                    

}                            

接着看 InitShmemIndex

/*                    

 *    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);

}                    

然后是 ShmemInitHash,重点要关注 hash_flag 的设置

/*                                

 * 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 -- 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)                            

{                            

    ……                        

    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                        

    {                        

        ……                    

    }                        

    ……                        

    return hashp;                        

}                            

                            

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

结束

你可能感兴趣的:(PostgreSQL)