Use block_id as index into registered_buffers array
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 10 Nov 2014 14:25:10 +0000 (16:25 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 10 Nov 2014 19:24:36 +0000 (21:24 +0200)
src/backend/access/transam/xloginsert.c

index f5e1c4fa3d82fb33b49afee7fe6572907a27a490..8d84f27d3dfae8c4869021b54055d12c63a01692 100644 (file)
  */
 typedef struct
 {
+       bool            in_use;
+       uint8           flags;                  /* REGBUF_* flags */
        RelFileNode rnode;                      /* identifies the relation and block */
        ForkNumber      forkno;
        BlockNumber block;
        Page            page;                   /* page content */
-       uint8           block_id;               /* ID the buffer was registered with */
-       uint8           flags;                  /* REGBUF_* flags */
-       uint32          rdata_sz;               /* total length of data in rdata chain */
+       uint32          rdata_len;              /* total length of data in rdata chain */
        XLogRecData *rdata_head;        /* head of the chain of data registered with
                                                                 * this block */
        XLogRecData *rdata_tail;        /* last entry in the chain, or &rdata_head if
@@ -55,8 +55,9 @@ typedef struct
 }      registered_buffer;
 
 static registered_buffer *registered_buffers;
-static int     num_registered_buffers = 0; /* # of structs in use */
 static int     max_registered_buffers;         /* allocated size */
+static int     max_registered_block_id = 0;    /* highest block_id + 1 currently
+                                                                                        * registered */
 
 /*
  * A chain of XLogRecDatas to hold the "main data" of a WAL record, registered
@@ -110,7 +111,7 @@ static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info,
 void
 XLogBeginInsert(void)
 {
-       Assert(num_registered_buffers == 0);
+       Assert(max_registered_block_id == 0);
        Assert(mainrdata_last == (XLogRecData *) &mainrdata_head);
        Assert(mainrdata_len == 0);
        Assert(!begininsert_called);
@@ -184,8 +185,13 @@ XLogEnsureRecordSpace(int nbuffers, int ndatas)
 void
 XLogResetInsertion(void)
 {
+       int                     i;
+
+       for (i = 0; i < max_registered_block_id; i++)
+               registered_buffers[i].in_use = false;
+
        num_rdatas = 0;
-       num_registered_buffers = 0;
+       max_registered_block_id = 0;
        mainrdata_len = 0;
        mainrdata_last = (XLogRecData *) &mainrdata_head;
        begininsert_called = false;
@@ -204,31 +210,36 @@ XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
        Assert(!((flags & REGBUF_FORCE_IMAGE) && (flags & (REGBUF_NO_IMAGE))));
        Assert(begininsert_called);
 
-       if (num_registered_buffers > max_registered_buffers)
-               elog(ERROR, "too many registered buffers");
+       if (block_id >= max_registered_block_id)
+       {
+               if (block_id >= max_registered_buffers)
+                       elog(ERROR, "too many registered buffers");
+               max_registered_block_id = block_id + 1;
+       }
 
-       regbuf = &registered_buffers[num_registered_buffers];
+       regbuf = &registered_buffers[block_id];
 
-       regbuf->block_id = block_id;
        BufferGetTag(buffer, &regbuf->rnode, &regbuf->forkno, &regbuf->block);
        regbuf->page = BufferGetPage(buffer);
        regbuf->flags = flags;
        regbuf->rdata_tail = (XLogRecData *) &regbuf->rdata_head;
-       regbuf->rdata_sz = 0;
+       regbuf->rdata_len = 0;
 
        /*
-        * Check that this page, or some other page with the same block_id,
-        * hasn't already been registered.
+        * Check that this page hasn't already been registered with some other
+        * block_id.
         */
 #ifdef USE_ASSERT_CHECKING
        {
                int                     i;
 
-               for (i = 0; i < num_registered_buffers; i++)
+               for (i = 0; i < max_registered_block_id; i++)
                {
                        registered_buffer *regbuf_old = &registered_buffers[i];
 
-                       Assert (regbuf_old->block_id != block_id);
+                       if (i == block_id || !regbuf_old->in_use)
+                               continue;
+
                        Assert (!RelFileNodeEquals(regbuf_old->rnode, regbuf->rnode) ||
                                        regbuf_old->forkno != regbuf->forkno ||
                                        regbuf_old->block != regbuf->block);
@@ -236,7 +247,7 @@ XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
        }
 #endif
 
-       num_registered_buffers++;
+       regbuf->in_use = true;
 }
 
 /*
@@ -248,38 +259,41 @@ XLogRegisterBlock(uint8 block_id, RelFileNode *rnode, ForkNumber forknum,
 {
        registered_buffer *regbuf;
 
-       if (num_registered_buffers > max_registered_buffers)
-               elog(ERROR, "too many registered buffers");
-
        /* This is currently only used to WAL-log a full-page image of a page */
        Assert(flags & REGBUF_FORCE_IMAGE);
+       Assert(begininsert_called);
 
-       regbuf = &registered_buffers[num_registered_buffers];
+       if (block_id >= max_registered_block_id)
+               max_registered_block_id = block_id + 1;
 
-       Assert(begininsert_called);
+       if (block_id >= max_registered_buffers)
+               elog(ERROR, "too many registered buffers");
+
+       regbuf = &registered_buffers[block_id];
 
-       regbuf->block_id = block_id;
        regbuf->rnode = *rnode;
        regbuf->forkno = forknum;
        regbuf->block = blknum;
        regbuf->page = page;
        regbuf->flags = flags;
        regbuf->rdata_tail = (XLogRecData *) &regbuf->rdata_head;
-       regbuf->rdata_sz = 0;
+       regbuf->rdata_len = 0;
 
        /*
-        * Check that this page, or some other page with the same block_id,
-        * hasn't already been registered.
+        * Check that this page hasn't already been registered with some other
+        * block_id.
         */
 #ifdef USE_ASSERT_CHECKING
        {
                int                     i;
 
-               for (i = 0; i < num_registered_buffers; i++)
+               for (i = 0; i < max_registered_block_id; i++)
                {
                        registered_buffer *regbuf_old = &registered_buffers[i];
 
-                       Assert (regbuf_old->block_id != block_id);
+                       if (i == block_id || !regbuf_old->in_use)
+                               continue;
+
                        Assert (!RelFileNodeEquals(regbuf_old->rnode, regbuf->rnode) ||
                                        regbuf_old->forkno != regbuf->forkno ||
                                        regbuf_old->block != regbuf->block);
@@ -287,7 +301,7 @@ XLogRegisterBlock(uint8 block_id, RelFileNode *rnode, ForkNumber forknum,
        }
 #endif
 
-       num_registered_buffers++;
+       regbuf->in_use = true;
 }
 
 /*
@@ -332,20 +346,14 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
 {
        registered_buffer *regbuf;
        XLogRecData *rdata;
-       int                     i;
 
        Assert(begininsert_called);
 
        /* find the registered buffer struct */
-       for (i = 0; i < num_registered_buffers; i++)
-       {
-               if (registered_buffers[i].block_id == block_id)
-                       break;
-       }
-       if (i >= num_registered_buffers)
+       regbuf = &registered_buffers[block_id];
+       if (!regbuf->in_use)
                elog(ERROR, "no block with id %d registered with WAL insertion",
                         block_id);
-       regbuf = &registered_buffers[i];
 
        if (num_rdatas >= max_rdatas)
                elog(ERROR, "too much WAL data");
@@ -356,7 +364,7 @@ XLogRegisterBufData(uint8 block_id, char *data, int len)
 
        regbuf->rdata_tail->next = rdata;
        regbuf->rdata_tail = rdata;
-       regbuf->rdata_sz += len;
+       regbuf->rdata_len += len;
 }
 
 /*
@@ -443,9 +451,10 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
 {
        XLogRecData *rdt;
        uint32          total_len;
-       int                     i;
+       int                     block_id;
        int                     used_rdatas = num_rdatas;
        pg_crc32        rdata_crc;
+       registered_buffer *prev_regbuf = NULL;
 
        /*
         * Note: this function can be called multiple times for the same record.
@@ -478,14 +487,17 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
         * Make additional rdata chain entries for the backup blocks.
         */
        *fpw_lsn = InvalidXLogRecPtr;
-       for (i = 0; i < num_registered_buffers; i++)
+       for (block_id = 0; block_id < max_registered_block_id; block_id++)
        {
-               registered_buffer *regbuf = &registered_buffers[i];
+               registered_buffer *regbuf = &registered_buffers[block_id];
                XLogRecordBlockData *bkpb = &regbuf->dtbuf_xlg;
                bool            needs_backup;
                bool            needs_data;
                int                     padlen;
 
+               if (!regbuf->in_use)
+                       continue;
+
                /* Determine if this block needs to be backed up */
                if (regbuf->flags & REGBUF_FORCE_IMAGE)
                        needs_backup = true;
@@ -511,7 +523,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
                }
 
                /* Determine if the buffer data needs to included */
-               if (regbuf->rdata_sz == 0)
+               if (regbuf->rdata_len == 0)
                        needs_data = false;
                else if ((regbuf->flags & REGBUF_KEEP_DATA) != 0)
                        needs_data = true;
@@ -525,11 +537,11 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
                rdt->next = &rdatas[used_rdatas++];
                rdt = rdt->next;
 
-               bkpb->id = regbuf->block_id;
+               bkpb->id = block_id;
                bkpb->fork_flags = (uint8) regbuf->forkno;
                bkpb->block = regbuf->block;
 
-               if (i > 0 && RelFileNodeEquals(bkpb->node, registered_buffers[i - 1].rnode))
+               if (prev_regbuf && RelFileNodeEquals(regbuf->rnode, prev_regbuf->rnode))
                {
                        bkpb->fork_flags |= BKPBLOCK_SAME_REL;
 
@@ -548,6 +560,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
                        bkpb->node = regbuf->rnode;
 
                        rdt->len = SizeOfXLogRecordBlockData;
+                       prev_regbuf = regbuf;
                }
 
                if ((regbuf->flags & REGBUF_WILL_INIT) == REGBUF_WILL_INIT)
@@ -666,7 +679,7 @@ XLogRecordAssemble(RmgrId rmid, uint8 info,
                         * overall list.
                         */
                        bkpb->fork_flags |= BKPBLOCK_HAS_DATA;
-                       bkpb->data_length += regbuf->rdata_sz;
+                       bkpb->data_length += regbuf->rdata_len;
 
                        rdt->next = regbuf->rdata_head;
                        rdt = regbuf->rdata_tail;