2nd_lvl_cache.diff
text/x-patch
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| .gitignore | 1 | 0 |
| src/backend/access/nbtree/nbtpage.c | 2 | 2 |
| src/backend/storage/buffer/buf_init.c | 28 | 5 |
| src/backend/storage/buffer/bufmgr.c | 101 | 13 |
| src/backend/storage/buffer/freelist.c | 137 | 28 |
| src/include/catalog/pg_proc.h | 2 | 1 |
| src/include/storage/buf.h | 11 | 0 |
| src/include/storage/buf_internals.h | 41 | 2 |
| src/include/storage/bufmgr.h | 12 | 0 |
diff --git a/.gitignore b/.gitignore
index 3f11f2e..6542e35 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@ lcov.info
/GNUmakefile
/config.log
/config.status
+/nbproject/private/
\ No newline at end of file
diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index 2796445..0229f5a 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -508,7 +508,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
if (blkno != P_NEW)
{
/* Read an existing block of the relation */
- buf = ReadBuffer(rel, blkno);
+ buf = ReadBufferLevel(rel, blkno, BUFFER_LEVEL_2ND);
LockBuffer(buf, access);
_bt_checkpage(rel, buf);
}
@@ -548,7 +548,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
blkno = GetFreeIndexPage(rel);
if (blkno == InvalidBlockNumber)
break;
- buf = ReadBuffer(rel, blkno);
+ buf = ReadBufferLevel(rel, blkno, BUFFER_LEVEL_2ND);
if (ConditionalLockBuffer(buf))
{
page = BufferGetPage(buf);
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index dadb49d..2922711 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -22,6 +22,7 @@ BufferDesc *BufferDescriptors;
char *BufferBlocks;
int32 *PrivateRefCount;
+BufferLevelDesc *bufferLevels;
/*
* Data Structures:
@@ -72,8 +73,7 @@ int32 *PrivateRefCount;
void
InitBufferPool(void)
{
- bool foundBufs,
- foundDescs;
+ bool foundBufs, foundDescs, foundBufferLevels = false;
BufferDescriptors = (BufferDesc *)
ShmemInitStruct("Buffer Descriptors",
@@ -83,19 +83,38 @@ InitBufferPool(void)
ShmemInitStruct("Buffer Blocks",
NBuffers * (Size) BLCKSZ, &foundBufs);
- if (foundDescs || foundBufs)
+ bufferLevels = (BufferLevelDesc*)
+ ShmemInitStruct("Buffer Levels Descriptors Table",
+ sizeof(BufferLevelDesc) * BUFFER_LEVEL_SIZE,
+ &foundBufferLevels);
+ if (foundDescs || foundBufs || foundBufferLevels)
{
/* both should be present or neither */
- Assert(foundDescs && foundBufs);
+ Assert(foundDescs && foundBufs && foundBufferLevels);
/* note: this path is only taken in EXEC_BACKEND case */
}
else
{
BufferDesc *buf;
+ BufferLevelDesc *bufferLevelDesc;
+
int i;
-
+
buf = BufferDescriptors;
+ /* Initialize buffer levels. */
+ //1st Level - Default
+ bufferLevelDesc = bufferLevels;
+ bufferLevelDesc->index = 0;
+ bufferLevelDesc->super = BUFFER_LEVEL_END_OF_LIST;
+ bufferLevelDesc->lower = BUFFER_LEVEL_END_OF_LIST;
+
+ //2nd Level - For indices
+ bufferLevelDesc++;
+ bufferLevelDesc->index = 1;
+ bufferLevelDesc->super = BUFFER_LEVEL_END_OF_LIST;
+ bufferLevelDesc->lower = 0;
+
/*
* Initialize all the buffer headers.
*/
@@ -117,6 +136,10 @@ InitBufferPool(void)
*/
buf->freeNext = i + 1;
+ /* Assign buffer level. */
+ //TODO Currently hardcoded -
+ buf->buf_level = ( 0.3 * NBuffers > i ) ? BUFFER_LEVEL_DEFAULT : BUFFER_LEVEL_2ND;
+
buf->io_in_progress_lock = LWLockAssign();
buf->content_lock = LWLockAssign();
}
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 1f89e52..867bae0 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -47,7 +47,8 @@
#include "storage/standby.h"
#include "utils/rel.h"
#include "utils/resowner.h"
-
+#include "catalog/pg_type.h"
+#include "funcapi.h"
/* Note: these two macros only work on shared buffers, not local ones! */
#define BufHdrGetBlock(bufHdr) ((Block) (BufferBlocks + ((Size) (bufHdr)->buf_id) * BLCKSZ))
@@ -85,7 +86,7 @@ static volatile BufferDesc *PinCountWaitBuf = NULL;
static Buffer ReadBuffer_common(SMgrRelation reln, char relpersistence,
ForkNumber forkNum, BlockNumber blockNum,
ReadBufferMode mode, BufferAccessStrategy strategy,
- bool *hit);
+ bool *hit, BufferLevel bufferLevel);
static bool PinBuffer(volatile BufferDesc *buf, BufferAccessStrategy strategy);
static void PinBuffer_Locked(volatile BufferDesc *buf);
static void UnpinBuffer(volatile BufferDesc *buf, bool fixOwner);
@@ -102,7 +103,8 @@ static volatile BufferDesc *BufferAlloc(SMgrRelation smgr,
ForkNumber forkNum,
BlockNumber blockNum,
BufferAccessStrategy strategy,
- bool *foundPtr);
+ bool *foundPtr,
+ BufferLevel bufferLevel);
static void FlushBuffer(volatile BufferDesc *buf, SMgrRelation reln);
static void AtProcExit_Buffers(int code, Datum arg);
@@ -186,6 +188,18 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
return ReadBufferExtended(reln, MAIN_FORKNUM, blockNum, RBM_NORMAL, NULL);
}
+Buffer
+ReadBufferLevel(Relation reln, BlockNumber blockNum, BufferLevel bufferLevel) {
+ return ReadBufferExtendedLevel(reln, MAIN_FORKNUM, blockNum, RBM_NORMAL, NULL, bufferLevel);
+}
+
+/** See {@link } for more details. */
+Buffer
+ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
+ ReadBufferMode mode, BufferAccessStrategy strategy) {
+ return ReadBufferExtendedLevel(reln, forkNum, blockNum, mode, strategy, BUFFER_LEVEL_DEFAULT);
+}
+
/*
* ReadBufferExtended -- returns a buffer containing the requested
* block of the requested relation. If the blknum
@@ -219,8 +233,8 @@ ReadBuffer(Relation reln, BlockNumber blockNum)
* See buffer/README for details.
*/
Buffer
-ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
- ReadBufferMode mode, BufferAccessStrategy strategy)
+ReadBufferExtendedLevel(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
+ ReadBufferMode mode, BufferAccessStrategy strategy, BufferLevel bufferLevel)
{
bool hit;
Buffer buf;
@@ -244,12 +258,19 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
*/
pgstat_count_buffer_read(reln);
buf = ReadBuffer_common(reln->rd_smgr, reln->rd_rel->relpersistence,
- forkNum, blockNum, mode, strategy, &hit);
+ forkNum, blockNum, mode, strategy, &hit, bufferLevel);
if (hit)
pgstat_count_buffer_hit(reln);
return buf;
}
+/** See {@link ReadBufferWithoutRelcacheLevel} for more details. */
+Buffer
+ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
+ BlockNumber blockNum, ReadBufferMode mode,
+ BufferAccessStrategy strategy) {
+ return ReadBufferWithoutRelcacheLevel(rnode, forkNum, blockNum, mode, strategy, BUFFER_LEVEL_DEFAULT);
+}
/*
* ReadBufferWithoutRelcache -- like ReadBufferExtended, but doesn't require
@@ -261,16 +282,16 @@ ReadBufferExtended(Relation reln, ForkNumber forkNum, BlockNumber blockNum,
* parameters.
*/
Buffer
-ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
+ReadBufferWithoutRelcacheLevel(RelFileNode rnode, ForkNumber forkNum,
BlockNumber blockNum, ReadBufferMode mode,
- BufferAccessStrategy strategy)
+ BufferAccessStrategy strategy, BufferLevel bufferLevel)
{
bool hit;
SMgrRelation smgr = smgropen(rnode, InvalidBackendId);
return ReadBuffer_common(smgr, RELPERSISTENCE_PERMANENT, forkNum, blockNum,
- mode, strategy, &hit);
+ mode, strategy, &hit, bufferLevel);
}
@@ -282,7 +303,7 @@ ReadBufferWithoutRelcache(RelFileNode rnode, ForkNumber forkNum,
static Buffer
ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
BlockNumber blockNum, ReadBufferMode mode,
- BufferAccessStrategy strategy, bool *hit)
+ BufferAccessStrategy strategy, bool *hit, BufferLevel bufferLevel)
{
volatile BufferDesc *bufHdr;
Block bufBlock;
@@ -323,7 +344,7 @@ ReadBuffer_common(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
* not currently in memory.
*/
bufHdr = BufferAlloc(smgr, relpersistence, forkNum, blockNum,
- strategy, &found);
+ strategy, &found, bufferLevel);
if (found)
pgBufferUsage.shared_blks_hit++;
else
@@ -507,7 +528,8 @@ static volatile BufferDesc *
BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
BlockNumber blockNum,
BufferAccessStrategy strategy,
- bool *foundPtr)
+ bool *foundPtr,
+ BufferLevel bufferLevel)
{
BufferTag newTag; /* identity of requested block */
uint32 newHash; /* hash value for newTag */
@@ -585,7 +607,7 @@ BufferAlloc(SMgrRelation smgr, char relpersistence, ForkNumber forkNum,
* still held, since it would be bad to hold the spinlock while
* possibly waking up other processes.
*/
- buf = StrategyGetBuffer(strategy, &lock_held);
+ buf = StrategyGetBufferLevel(strategy, &lock_held, bufferLevel);
Assert(buf->refcount == 0);
@@ -2772,3 +2794,69 @@ local_buffer_write_error_callback(void *arg)
pfree(path);
}
}
+
+Datum
+dump_shared_buffers_info(PG_FUNCTION_ARGS)
+{
+ FuncCallContext *funcctx;
+ int idx = 2;
+
+ //fprintf(stderr, "Executing dump_shared_buffers_info\n");
+ if (SRF_IS_FIRSTCALL())
+ {
+ TupleDesc tupdesc;
+ MemoryContext oldcontext;
+ int val = 1;
+
+ funcctx = SRF_FIRSTCALL_INIT();
+ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+ /*
+ * build tupdesc for result tuples (matches out parameters in pg_proc
+ * entry)
+ */
+ tupdesc = CreateTemplateTupleDesc(3, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) val++, "buf_idx",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) val++, "buf_level",
+ INT4OID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) val++, "buf_free_next",
+ INT4OID, -1, 0);
+
+ funcctx->tuple_desc = BlessTupleDesc(tupdesc);
+
+ /* allocate memory for user context */
+ funcctx->user_fctx = (void*) palloc(sizeof(int));
+ *((int *) funcctx->user_fctx) = 0;
+ MemoryContextSwitchTo(oldcontext);
+ }
+
+ funcctx = SRF_PERCALL_SETUP();
+ idx = *((int *) funcctx->user_fctx);
+ if (idx < NBuffers) {
+ BufferDesc *bufferDesc;
+ Datum result;
+ Datum values[4];
+ bool nulls[4];
+ HeapTuple tuple;
+ int val = 0;
+
+ bufferDesc = BufferDescriptors + idx;
+
+ values[val++] = Int32GetDatum(idx);
+ values[val++] = Int32GetDatum(bufferDesc->buf_level);
+ values[val++] = Int32GetDatum(bufferDesc->freeNext);
+ MemSet(nulls, 0, sizeof(nulls));
+
+ idx++;
+ *((int *) funcctx->user_fctx) = idx;
+ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+ result = HeapTupleGetDatum(tuple);
+
+ SRF_RETURN_NEXT(funcctx, result);
+ }else {
+ SRF_RETURN_DONE(funcctx);
+ }
+
+ SRF_RETURN_DONE(funcctx);
+}
\ No newline at end of file
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index 72968db..fc27609 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -25,10 +25,14 @@
typedef struct
{
/* Clock sweep hand: index of next buffer to consider grabbing */
- int nextVictimBuffer;
+ int nextVictimBufferByLevel[BUFFER_LEVEL_SIZE];
- int firstFreeBuffer; /* Head of list of unused buffers */
- int lastFreeBuffer; /* Tail of list of unused buffers */
+ /** Head of list of unused buffers */
+ int firstFreeBufferByLevel[BUFFER_LEVEL_SIZE];
+
+ //Currently unused
+ ///** Tail of list of unused buffers */
+ //int lastFreeBufferByLevel[BUFFER_LEVEL_SIZE];
/*
* NOTE: lastFreeBuffer is undefined when firstFreeBuffer is -1 (that is,
@@ -81,11 +85,16 @@ typedef struct BufferAccessStrategyData
/* Prototypes for internal functions */
-static volatile BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy);
+static volatile BufferDesc *GetBufferFromRing(BufferAccessStrategy strategy, BufferLevel level);
static void AddBufferToRing(BufferAccessStrategy strategy,
volatile BufferDesc *buf);
+static int findFisrtBufferByLevel(BufferLevel level);
+volatile BufferDesc *
+StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held) {
+ return StrategyGetBufferLevel(strategy, lock_held, BUFFER_LEVEL_DEFAULT);
+}
/*
* StrategyGetBuffer
*
@@ -104,18 +113,21 @@ static void AddBufferToRing(BufferAccessStrategy strategy,
* kernel calls while holding the buffer header spinlock.
*/
volatile BufferDesc *
-StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
+StrategyGetBufferLevel(BufferAccessStrategy strategy, bool *lock_held, BufferLevel level)
{
- volatile BufferDesc *buf;
+ volatile BufferDesc *buf = NULL;
int trycounter;
-
+ int bufferToExamine;
+ volatile BufferDesc *prevExaminedBuffer;
+
+ //level = BUFFER_LEVEL_DEFAULT;
/*
* If given a strategy object, see whether it can select a buffer. We
* assume strategy objects don't need the BufFreelistLock.
*/
if (strategy != NULL)
{
- buf = GetBufferFromRing(strategy);
+ buf = GetBufferFromRing(strategy, level);
if (buf != NULL)
{
*lock_held = false;
@@ -139,14 +151,33 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
* are considered to be protected by the BufFreelistLock not the
* individual buffer spinlocks, so it's OK to manipulate them without
* holding the spinlock.
+ *
+ * We do not keep lock on previous buffer, as free list is modified
+ * only by freelist.c and list is locked exclusivly (ensure this).
*/
- while (StrategyControl->firstFreeBuffer >= 0)
+ prevExaminedBuffer = NULL;
+ bufferToExamine = StrategyControl->firstFreeBufferByLevel[level];
+ while (bufferToExamine >= 0)
{
- buf = &BufferDescriptors[StrategyControl->firstFreeBuffer];
+ buf = &BufferDescriptors[bufferToExamine];
Assert(buf->freeNext != FREENEXT_NOT_IN_LIST);
-
+ if (buf->buf_level != level) {
+ prevExaminedBuffer = buf;
+ bufferToExamine = buf->freeNext;
+ //fprintf(stderr, "Skipping buffer %d due to level missmatch %d, next is %d\n", buf->buf_id, buf->buf_level, buf->freeNext);
+ continue;
+ }else {
+ //fprintf(stderr, "Selecting buffer %d with level %d\n", buf->buf_id, buf->buf_level);
+ }
+
/* Unconditionally remove buffer from freelist */
- StrategyControl->firstFreeBuffer = buf->freeNext;
+ if (prevExaminedBuffer != NULL) {
+ /* We are after list head. */
+ prevExaminedBuffer->freeNext = buf->freeNext;
+ }else {
+ /* We modify head of list. */
+ StrategyControl->firstFreeBufferByLevel[level] = buf->freeNext;
+ }
buf->freeNext = FREENEXT_NOT_IN_LIST;
/*
@@ -161,23 +192,50 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
{
if (strategy != NULL)
AddBufferToRing(strategy, buf);
+ if (buf->buf_level != BUFFER_LEVEL_DEFAULT) {
+ //fprintf(stderr, "Returing free buffer %d with level %d\n", buf->buf_id, buf->buf_level);
+ }
+ Assert(buf->buf_level == level);
return buf;
}
UnlockBufHdr(buf);
}
-
+ if (buf != NULL && buf->buf_level != BUFFER_LEVEL_DEFAULT) {
+ //fprintf(stderr, "No free buffers found with level %d\n", buf->buf_level);
+ }
/* Nothing on the freelist, so run the "clock sweep" algorithm */
- trycounter = NBuffers;
+ trycounter = NBuffers; //I know, we should only do NBuffersByLevel, but this is not initialized still
for (;;)
{
- buf = &BufferDescriptors[StrategyControl->nextVictimBuffer];
+ buf = &BufferDescriptors[StrategyControl->nextVictimBufferByLevel[level]];
- if (++StrategyControl->nextVictimBuffer >= NBuffers)
+ if (++StrategyControl->nextVictimBufferByLevel[level] >= NBuffers)
{
- StrategyControl->nextVictimBuffer = 0;
- StrategyControl->completePasses++;
+ /* We need to determine next victim buffer. We assume
+ * for now, that we can sweep buffers by changing
+ * buf_level. I don't know if such feature will be used
+ * or not.
+ */
+ StrategyControl->nextVictimBufferByLevel[level] = findFisrtBufferByLevel(level);
+
+ Assert(StrategyControl->nextVictimBufferByLevel[level] >= 0);
+
+ StrategyControl->completePasses++;
}
+ /* If buffer doesn't have required level move next. It is almost
+ * same as code checking if buffer is pinned, but we don't use
+ * locking here.
+ */
+ if (buf->buf_level != level) {
+ if (--trycounter == 0)
+ elog(ERROR, "no unpinned buffers available with requested level");
+ //fprintf(stderr, "Skipping in clock sweep buffer %d due to buffer level mismatch %d\n", buf->buf_id, buf->buf_level);
+ continue;
+ }
+
+ Assert(buf->buf_level == level);
+
/*
* If the buffer is pinned or has a nonzero usage_count, we cannot use
* it; decrement the usage_count (unless pinned) and keep scanning.
@@ -195,6 +253,10 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
/* Found a usable buffer */
if (strategy != NULL)
AddBufferToRing(strategy, buf);
+ if (buf->buf_level != BUFFER_LEVEL_DEFAULT) {
+ //fprintf(stderr, "Returing free buffer from clock sweep %d with level %d\n", buf->buf_id, buf->buf_level);
+ }
+ Assert(buf->buf_level == level);
return buf;
}
}
@@ -231,10 +293,10 @@ StrategyFreeBuffer(volatile BufferDesc *buf)
*/
if (buf->freeNext == FREENEXT_NOT_IN_LIST)
{
- buf->freeNext = StrategyControl->firstFreeBuffer;
+ buf->freeNext = StrategyControl->firstFreeBufferByLevel[buf->buf_level];
if (buf->freeNext < 0)
- StrategyControl->lastFreeBuffer = buf->buf_id;
- StrategyControl->firstFreeBuffer = buf->buf_id;
+ //StrategyControl->lastFreeBufferByLevel[buf->buf_level] = buf->buf_id;
+ StrategyControl->firstFreeBufferByLevel[buf->buf_level] = buf->buf_id;
}
LWLockRelease(BufFreelistLock);
@@ -257,7 +319,8 @@ StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
int result;
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
- result = StrategyControl->nextVictimBuffer;
+ //TODO We take next vitim buffer from default level, as we have many levels
+ result = StrategyControl->nextVictimBufferByLevel[BUFFER_LEVEL_DEFAULT];
if (complete_passes)
*complete_passes = StrategyControl->completePasses;
if (num_buf_alloc)
@@ -326,6 +389,11 @@ StrategyInitialize(bool init)
if (!found)
{
+ int i;
+ BufferDesc *buf;
+ BufferLevel level;
+ int previousBufferLevel;
+
/*
* Only done once, usually in postmaster
*/
@@ -335,12 +403,38 @@ StrategyInitialize(bool init)
* Grab the whole linked list of free buffers for our strategy. We
* assume it was previously set up by InitBufferPool().
*/
- StrategyControl->firstFreeBuffer = 0;
- StrategyControl->lastFreeBuffer = NBuffers - 1;
-
- /* Initialize the clock sweep pointer */
- StrategyControl->nextVictimBuffer = 0;
+ //StrategyControl->firstFreeBuffer = 0;
+ //StrategyControl->lastFreeBuffer = NBuffers - 1;
+ //Devo mode:
+ // - we don't set lastFreeBuffer is never used
+ for (i=0; i < BUFFER_LEVEL_SIZE; i++) {
+ StrategyControl->firstFreeBufferByLevel[i] = FREENEXT_END_OF_LIST;
+ //StrategyControl->lastFreeBufferByLevel[i] = FREENEXT_END_OF_LIST;
+ }
+ buf = BufferDescriptors;
+ for (i=0; i < NBuffers; i++, buf++) {
+ level = buf->buf_level;
+ if (StrategyControl->firstFreeBufferByLevel[level] == FREENEXT_END_OF_LIST) {
+ StrategyControl->firstFreeBufferByLevel[level] = i;
+ }
+ }
+ previousBufferLevel = NBuffers - 1;
+
+ /* Coerce last free nexts. */
+ for (level = BUFFER_LEVEL_SIZE - 1; level > -1; level--) {
+ if (StrategyControl->firstFreeBufferByLevel[level] != FREENEXT_END_OF_LIST) {
+ BufferDescriptors[previousBufferLevel].freeNext = FREENEXT_END_OF_LIST;
+ previousBufferLevel = StrategyControl->firstFreeBufferByLevel[level] - 1;
+
+ }
+ StrategyControl->nextVictimBufferByLevel[level]
+ = StrategyControl->firstFreeBufferByLevel[level];
+ }
+
+ //Just simple check if everything is ok
+ Assert(previousBufferLevel == -1);
+
/* Clear statistics */
StrategyControl->completePasses = 0;
StrategyControl->numBufferAllocs = 0;
@@ -431,7 +525,7 @@ FreeAccessStrategy(BufferAccessStrategy strategy)
* The bufhdr spin lock is held on the returned buffer.
*/
static volatile BufferDesc *
-GetBufferFromRing(BufferAccessStrategy strategy)
+GetBufferFromRing(BufferAccessStrategy strategy, BufferLevel level)
{
volatile BufferDesc *buf;
Buffer bufnum;
@@ -452,6 +546,8 @@ GetBufferFromRing(BufferAccessStrategy strategy)
return NULL;
}
+ // TODO: If buffer doesn't have requested level tall caller to allocate new buffer. Is it ok?
+
/*
* If the buffer is pinned we cannot use it under any circumstances.
*
@@ -521,3 +617,16 @@ StrategyRejectBuffer(BufferAccessStrategy strategy, volatile BufferDesc *buf)
return true;
}
+
+static int findFisrtBufferByLevel(BufferLevel level) {
+ int i;
+ BufferDesc *buf;
+
+ buf = BufferDescriptors;
+ for (i=0; i < NBuffers; i++, buf++) {
+ if (buf->buf_level == level)
+ return i;
+ }
+
+ return FREENEXT_END_OF_LIST;
+}
\ No newline at end of file
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index cff64ba..d634f84 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4320,7 +4320,8 @@ DATA(insert OID = 3113 ( last_value PGNSP PGUID 12 1 0 0 f t f t f i 1 0 2283 "
DESCR("fetch the last row value");
DATA(insert OID = 3114 ( nth_value PGNSP PGUID 12 1 0 0 f t f t f i 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ window_nth_value _null_ _null_ _null_ ));
DESCR("fetch the Nth row value");
-
+DATA(insert OID = 3833 ( dump_shared_buffers_info PGNSP PGUID 12 1 10 0 f f f t t s 0 0 2249 "" "{23,23,23}" "{o,o,o}" "{buf_idx,buf_level,buf_free_next}" _null_ dump_shared_buffers_info _null_ _null_ _null_ ));
+DESCR("Dump information about usage of shared buffers");
/*
* Symbolic values for provolatile column: these indicate whether the result
diff --git a/src/include/storage/buf.h b/src/include/storage/buf.h
index 5347ab0..01b51d2 100644
--- a/src/include/storage/buf.h
+++ b/src/include/storage/buf.h
@@ -43,4 +43,15 @@ typedef int Buffer;
*/
typedef struct BufferAccessStrategyData *BufferAccessStrategy;
+
+/** Type for buffer level. */
+typedef int BufferLevel;
+
+#define BUFFER_LEVEL_END_OF_LIST -2
+#define BUFFER_LEVEL_DEFAULT 0
+#define BUFFER_LEVEL_2ND 1
+/** I wonder to mark end of list with zeroed struct, not to put all here. */
+#define BUFFER_LEVEL_SIZE 2
+
+extern int NBuffersByLevel[BUFFER_LEVEL_SIZE];
#endif /* BUF_H */
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 0652bdf..1a019ac 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -104,6 +104,23 @@ typedef struct buftag
#define BufMappingPartitionLock(hashcode) \
((LWLockId) (FirstBufMappingLock + BufTableHashPartition(hashcode)))
+/**
+ * Shared descriptor of buffer level. Each level contains index of super
+ * and lower level. {@code BUFFER_LEVEL_END_OF_LIST} in lower level means end of list,
+ * and {@code BUFFER_LEVEL_END_OF_LIST} in super means begin of list. This structure allows
+ * us to define tree-like structure of levels.
+ *
+ * Note: Currently we use only 2 levels; 1st Level is standard level, 2nd
+ * level is designed for use with index pages (when requested).
+ */
+typedef struct sbuflevel {
+ BufferLevel index;
+
+ /** Not used currently. */
+ BufferLevel super;
+ BufferLevel lower;
+} BufferLevelDesc;
+
/*
* BufferDesc -- shared descriptor/state data for a single shared buffer.
*
@@ -142,10 +159,28 @@ typedef struct sbufdesc
int buf_id; /* buffer's index number (from 0) */
int freeNext; /* link in freelist chain */
+ /** Holds level of buffer. */
+ BufferLevel buf_level;
LWLockId io_in_progress_lock; /* to wait for I/O to complete */
LWLockId content_lock; /* to lock access to buffer contents */
} BufferDesc;
+/** Struct for holding parameters for getting buffer. We emulate polymorphic
+ * methods here*/
+typedef struct _StrategyGetBufferOptsV1 {
+ int version;
+ BufferLevel level;
+}StrategyGetBufferOptsV1;
+
+typedef union _StrategyGetBufferUnion {
+ StrategyGetBufferOptsV1 optsV1;
+}StrategyGetBufferUnion;
+
+typedef struct _StrategyGetBufferOpts {
+ int version;
+ StrategyGetBufferOptsV1 opts;
+}StrategyGetBufferOpts;
+
#define BufferDescriptorGetBuffer(bdesc) ((bdesc)->buf_id + 1)
/*
@@ -174,14 +209,18 @@ extern PGDLLIMPORT BufferDesc *BufferDescriptors;
/* in localbuf.c */
extern BufferDesc *LocalBufferDescriptors;
+/** Shared table for buffer levels */
+extern PGDLLIMPORT BufferLevelDesc *bufferLevels;
/*
* Internal routines: only called by bufmgr
*/
/* freelist.c */
-extern volatile BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy,
- bool *lock_held);
+extern volatile BufferDesc *StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held);
+
+extern volatile BufferDesc * StrategyGetBufferLevel(BufferAccessStrategy strategy, bool *lock_held, BufferLevel level);
+
extern void StrategyFreeBuffer(volatile BufferDesc *buf);
extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
volatile BufferDesc *buf);
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index b8fc87e..d8b1b46 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -59,6 +59,9 @@ extern PGDLLIMPORT int NLocBuffer;
extern PGDLLIMPORT Block *LocalBufferBlockPointers;
extern PGDLLIMPORT int32 *LocalRefCount;
+/** Dumps informations about shared buffers. */
+extern Datum dump_shared_buffers_info(PG_FUNCTION_ARGS);
+
/* special block number for ReadBuffer() */
#define P_NEW InvalidBlockNumber /* grow the file to get a new page */
@@ -157,12 +160,21 @@ extern PGDLLIMPORT int32 *LocalRefCount;
extern void PrefetchBuffer(Relation reln, ForkNumber forkNum,
BlockNumber blockNum);
extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
+extern Buffer ReadBufferLevel(Relation reln, BlockNumber blockNum, BufferLevel bufferLevel);
extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
BlockNumber blockNum, ReadBufferMode mode,
BufferAccessStrategy strategy);
+extern Buffer ReadBufferExtendedLevel(Relation reln, ForkNumber forkNum,
+ BlockNumber blockNum, ReadBufferMode mode,
+ BufferAccessStrategy strategy,
+ BufferLevel bufferLevel);
extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode,
ForkNumber forkNum, BlockNumber blockNum,
ReadBufferMode mode, BufferAccessStrategy strategy);
+extern Buffer ReadBufferWithoutRelcacheLevel(RelFileNode rnode,
+ ForkNumber forkNum, BlockNumber blockNum,
+ ReadBufferMode mode, BufferAccessStrategy strategy,
+ BufferLevel bufferLevel);
extern void ReleaseBuffer(Buffer buffer);
extern void UnlockReleaseBuffer(Buffer buffer);
extern void MarkBufferDirty(Buffer buffer);