📄 mm.c
字号:
/*------------------------------------------------------------------------- * * mm.c * main memory storage manager * * This code manages relations that reside in (presumably stable) * main memory. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/storage/smgr/mm.c,v 1.16 1999/05/25 16:11:32 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#ifdef STABLE_MEMORY_STORAGE#include <math.h>#include "storage/ipc.h"#include "storage/smgr.h" /* where the declarations go */#include "storage/block.h"#include "storage/shmem.h"#include "storage/spin.h"#include "utils/hsearch.h"#include "utils/rel.h"#include "utils/memutils.h"/* * MMCacheTag -- Unique triplet for blocks stored by the main memory * storage manager. */typedef struct MMCacheTag{ Oid mmct_dbid; Oid mmct_relid; BlockNumber mmct_blkno;} MMCacheTag;/* * Shared-memory hash table for main memory relations contains * entries of this form. */typedef struct MMHashEntry{ MMCacheTag mmhe_tag; int mmhe_bufno;} MMHashEntry;/* * MMRelTag -- Unique identifier for each relation that is stored in the * main-memory storage manager. */typedef struct MMRelTag{ Oid mmrt_dbid; Oid mmrt_relid;} MMRelTag;/* * Shared-memory hash table for # blocks in main memory relations contains * entries of this form. */typedef struct MMRelHashEntry{ MMRelTag mmrhe_tag; int mmrhe_nblocks;} MMRelHashEntry;#define MMNBUFFERS 10#define MMNRELATIONS 2SPINLOCK MMCacheLock;extern Oid MyDatabaseId;static int *MMCurTop;static int *MMCurRelno;static MMCacheTag *MMBlockTags;static char *MMBlockCache;static HTAB *MMCacheHT;static HTAB *MMRelCacheHT;intmminit(){ char *mmcacheblk; int mmsize = 0; bool found; HASHCTL info; SpinAcquire(MMCacheLock); mmsize += MAXALIGN(BLCKSZ * MMNBUFFERS); mmsize += MAXALIGN(sizeof(*MMCurTop)); mmsize += MAXALIGN(sizeof(*MMCurRelno)); mmsize += MAXALIGN((MMNBUFFERS * sizeof(MMCacheTag))); mmcacheblk = (char *) ShmemInitStruct("Main memory smgr", mmsize, &found); if (mmcacheblk == (char *) NULL) { SpinRelease(MMCacheLock); return SM_FAIL; } info.keysize = sizeof(MMCacheTag); info.datasize = sizeof(MMHashEntry) - sizeof(MMCacheTag); info.hash = tag_hash; MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT", MMNBUFFERS, MMNBUFFERS, &info, (HASH_ELEM | HASH_FUNCTION)); if (MMCacheHT == (HTAB *) NULL) { SpinRelease(MMCacheLock); return SM_FAIL; } info.keysize = sizeof(MMRelTag); info.datasize = sizeof(MMRelHashEntry) - sizeof(MMRelTag); info.hash = tag_hash; MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT", MMNRELATIONS, MMNRELATIONS, &info, (HASH_ELEM | HASH_FUNCTION)); if (MMRelCacheHT == (HTAB *) NULL) { SpinRelease(MMCacheLock); return SM_FAIL; } if (IsUnderPostmaster) /* was IsPostmaster bjm */ { MemSet(mmcacheblk, 0, mmsize); SpinRelease(MMCacheLock); return SM_SUCCESS; } SpinRelease(MMCacheLock); MMCurTop = (int *) mmcacheblk; mmcacheblk += sizeof(int); MMCurRelno = (int *) mmcacheblk; mmcacheblk += sizeof(int); MMBlockTags = (MMCacheTag *) mmcacheblk; mmcacheblk += (MMNBUFFERS * sizeof(MMCacheTag)); MMBlockCache = mmcacheblk; return SM_SUCCESS;}intmmshutdown(){ return SM_SUCCESS;}intmmcreate(Relation reln){ MMRelHashEntry *entry; bool found; MMRelTag tag; SpinAcquire(MMCacheLock); if (*MMCurRelno == MMNRELATIONS) { SpinRelease(MMCacheLock); return SM_FAIL; } (*MMCurRelno)++; tag.mmrt_relid = RelationGetRelid(reln); if (reln->rd_rel->relisshared) tag.mmrt_dbid = (Oid) 0; else tag.mmrt_dbid = MyDatabaseId; entry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &tag, HASH_ENTER, &found); if (entry == (MMRelHashEntry *) NULL) { SpinRelease(MMCacheLock); elog(FATAL, "main memory storage mgr rel cache hash table corrupt"); } if (found) { /* already exists */ SpinRelease(MMCacheLock); return SM_FAIL; } entry->mmrhe_nblocks = 0; SpinRelease(MMCacheLock); return SM_SUCCESS;}/* * mmunlink() -- Unlink a relation. */intmmunlink(Relation reln){ int i; Oid reldbid; MMHashEntry *entry; MMRelHashEntry *rentry; bool found; MMRelTag rtag; if (reln->rd_rel->relisshared) reldbid = (Oid) 0; else reldbid = MyDatabaseId; SpinAcquire(MMCacheLock); for (i = 0; i < MMNBUFFERS; i++) { if (MMBlockTags[i].mmct_dbid == reldbid && MMBlockTags[i].mmct_relid == RelationGetRelid(reln)) { entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &MMBlockTags[i], HASH_REMOVE, &found); if (entry == (MMHashEntry *) NULL || !found) { SpinRelease(MMCacheLock); elog(FATAL, "mmunlink: cache hash table corrupted"); } MMBlockTags[i].mmct_dbid = (Oid) 0; MMBlockTags[i].mmct_relid = (Oid) 0; MMBlockTags[i].mmct_blkno = (BlockNumber) 0; } } rtag.mmrt_dbid = reldbid; rtag.mmrt_relid = RelationGetRelid(reln); rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag, HASH_REMOVE, &found); if (rentry == (MMRelHashEntry *) NULL || !found) { SpinRelease(MMCacheLock); elog(FATAL, "mmunlink: rel cache hash table corrupted"); } (*MMCurRelno)--; SpinRelease(MMCacheLock); return 1;}/* * mmextend() -- Add a block to the specified relation. * * This routine returns SM_FAIL or SM_SUCCESS, with errno set as * appropriate. */intmmextend(Relation reln, char *buffer){ MMRelHashEntry *rentry; MMHashEntry *entry; int i; Oid reldbid; int offset; bool found; MMRelTag rtag; MMCacheTag tag; if (reln->rd_rel->relisshared) reldbid = (Oid) 0; else reldbid = MyDatabaseId; tag.mmct_dbid = rtag.mmrt_dbid = reldbid; tag.mmct_relid = rtag.mmrt_relid = RelationGetRelid(reln); SpinAcquire(MMCacheLock); if (*MMCurTop == MMNBUFFERS) { for (i = 0; i < MMNBUFFERS; i++) { if (MMBlockTags[i].mmct_dbid == 0 && MMBlockTags[i].mmct_relid == 0) break; } if (i == MMNBUFFERS) { SpinRelease(MMCacheLock); return SM_FAIL; } } else { i = *MMCurTop; (*MMCurTop)++; } rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag, HASH_FIND, &found); if (rentry == (MMRelHashEntry *) NULL || !found) { SpinRelease(MMCacheLock); elog(FATAL, "mmextend: rel cache hash table corrupt"); } tag.mmct_blkno = rentry->mmrhe_nblocks; entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag, HASH_ENTER, &found); if (entry == (MMHashEntry *) NULL || found) { SpinRelease(MMCacheLock); elog(FATAL, "mmextend: cache hash table corrupt"); } entry->mmhe_bufno = i; MMBlockTags[i].mmct_dbid = reldbid; MMBlockTags[i].mmct_relid = RelationGetRelid(reln); MMBlockTags[i].mmct_blkno = rentry->mmrhe_nblocks; /* page numbers are zero-based, so we increment this at the end */ (rentry->mmrhe_nblocks)++; /* write the extended page */ offset = (i * BLCKSZ); memmove(&(MMBlockCache[offset]), buffer, BLCKSZ); SpinRelease(MMCacheLock); return SM_SUCCESS;}/* * mmopen() -- Open the specified relation. */intmmopen(Relation reln){ /* automatically successful */ return 0;}/* * mmclose() -- Close the specified relation. * * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate. */intmmclose(Relation reln){ /* automatically successful */ return SM_SUCCESS;}/* * mmread() -- Read the specified block from a relation. * * Returns SM_SUCCESS or SM_FAIL. */intmmread(Relation reln, BlockNumber blocknum, char *buffer){ MMHashEntry *entry; bool found; int offset; MMCacheTag tag; if (reln->rd_rel->relisshared) tag.mmct_dbid = (Oid) 0; else tag.mmct_dbid = MyDatabaseId; tag.mmct_relid = RelationGetRelid(reln); tag.mmct_blkno = blocknum; SpinAcquire(MMCacheLock); entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag, HASH_FIND, &found); if (entry == (MMHashEntry *) NULL) { SpinRelease(MMCacheLock); elog(FATAL, "mmread: hash table corrupt"); } if (!found) { /* reading nonexistent pages is defined to fill them with zeroes */ SpinRelease(MMCacheLock); MemSet(buffer, 0, BLCKSZ); return SM_SUCCESS; } offset = (entry->mmhe_bufno * BLCKSZ); memmove(buffer, &MMBlockCache[offset], BLCKSZ); SpinRelease(MMCacheLock); return SM_SUCCESS;}/* * mmwrite() -- Write the supplied block at the appropriate location. * * Returns SM_SUCCESS or SM_FAIL. */intmmwrite(Relation reln, BlockNumber blocknum, char *buffer){ MMHashEntry *entry; bool found; int offset; MMCacheTag tag; if (reln->rd_rel->relisshared) tag.mmct_dbid = (Oid) 0; else tag.mmct_dbid = MyDatabaseId; tag.mmct_relid = RelationGetRelid(reln); tag.mmct_blkno = blocknum; SpinAcquire(MMCacheLock); entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag, HASH_FIND, &found); if (entry == (MMHashEntry *) NULL) { SpinRelease(MMCacheLock); elog(FATAL, "mmread: hash table corrupt"); } if (!found) { SpinRelease(MMCacheLock); elog(FATAL, "mmwrite: hash table missing requested page"); } offset = (entry->mmhe_bufno * BLCKSZ); memmove(&MMBlockCache[offset], buffer, BLCKSZ); SpinRelease(MMCacheLock); return SM_SUCCESS;}/* * mmflush() -- Synchronously write a block to stable storage. * * For main-memory relations, this is exactly equivalent to mmwrite(). */intmmflush(Relation reln, BlockNumber blocknum, char *buffer){ return mmwrite(reln, blocknum, buffer);}/* * mmblindwrt() -- Write a block to stable storage blind. * * We have to be able to do this using only the name and OID of * the database and relation in which the block belongs. */intmmblindwrt(char *dbstr, char *relstr, Oid dbid, Oid relid, BlockNumber blkno, char *buffer){ return SM_FAIL;}/* * mmnblocks() -- Get the number of blocks stored in a relation. * * Returns # of blocks or -1 on error. */intmmnblocks(Relation reln){ MMRelTag rtag; MMRelHashEntry *rentry; bool found; int nblocks; if (reln->rd_rel->relisshared) rtag.mmrt_dbid = (Oid) 0; else rtag.mmrt_dbid = MyDatabaseId; rtag.mmrt_relid = RelationGetRelid(reln); SpinAcquire(MMCacheLock); rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag, HASH_FIND, &found); if (rentry == (MMRelHashEntry *) NULL) { SpinRelease(MMCacheLock); elog(FATAL, "mmnblocks: rel cache hash table corrupt"); } if (found) nblocks = rentry->mmrhe_nblocks; else nblocks = -1; SpinRelease(MMCacheLock); return nblocks;}/* * mmcommit() -- Commit a transaction. * * Returns SM_SUCCESS or SM_FAIL with errno set as appropriate. */intmmcommit(){ return SM_SUCCESS;}/* * mmabort() -- Abort a transaction. */intmmabort(){ return SM_SUCCESS;}/* * MMShmemSize() -- Declare amount of shared memory we require. * * The shared memory initialization code creates a block of shared * memory exactly big enough to hold all the structures it needs to. * This routine declares how much space the main memory storage * manager will use. */intMMShmemSize(){ int size = 0; /* * first compute space occupied by the (dbid,relid,blkno) hash table */ size += hash_estimate_size(MMNBUFFERS, 0, /* MMHashEntry includes key */ sizeof(MMHashEntry)); /* * now do the same for the rel hash table */ size += hash_estimate_size(MMNRELATIONS, 0, /* MMRelHashEntry includes key */ sizeof(MMRelHashEntry)); /* * finally, add in the memory block we use directly */ size += MAXALIGN(BLCKSZ * MMNBUFFERS); size += MAXALIGN(sizeof(*MMCurTop)); size += MAXALIGN(sizeof(*MMCurRelno)); size += MAXALIGN(MMNBUFFERS * sizeof(MMCacheTag)); return size;}#endif /* STABLE_MEMORY_STORAGE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -