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

结束

posted @ 2012-11-06 16:05  健哥的数据花园  阅读(916)  评论(0编辑  收藏  举报