对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 ]
结束