对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: luckyjackgao@gmail.com ]

结束

原文地址:https://www.cnblogs.com/gaojian/p/2757116.html