summaryrefslogtreecommitdiff
path: root/storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp')
-rw-r--r--storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp370
1 files changed, 370 insertions, 0 deletions
diff --git a/storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp b/storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp
new file mode 100644
index 00000000000..9722aa437c0
--- /dev/null
+++ b/storage/ndb/src/kernel/blocks/dbtup/DbtupPagMan.cpp
@@ -0,0 +1,370 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#define DBTUP_C
+#include "Dbtup.hpp"
+#include <RefConvert.hpp>
+#include <ndb_limits.h>
+#include <pc.hpp>
+
+#define ljam() { jamLine(16000 + __LINE__); }
+#define ljamEntry() { jamEntryLine(16000 + __LINE__); }
+
+/* ---------------------------------------------------------------- */
+// 4) Page Memory Manager (buddy algorithm)
+//
+// The following data structures in Dbtup is used by the Page Memory
+// Manager.
+//
+// cfreepageList[16]
+// Pages with a header
+//
+// The cfreepageList is 16 free lists. Free list 0 contains chunks of
+// pages with 2^0 (=1) pages in each chunk. Free list 1 chunks of 2^1
+// (=2) pages in each chunk and so forth upto free list 15 which
+// contains chunks of 2^15 (=32768) pages in each chunk.
+// The cfreepageList array contains the pointer to the first chunk
+// in each of those lists. The lists are doubly linked where the
+// first page in each chunk contains the next and previous references
+// in position ZPAGE_NEXT_CLUST_POS and ZPAGE_PREV_CLUST_POS in the
+// page header.
+// In addition the leading page and the last page in each chunk is marked
+// with a state (=ZFREE_COMMON) in position ZPAGE_STATE_POS in page
+// header. This state indicates that the page is the leading or last page
+// in a chunk of free pages. Furthermore the leading and last page is
+// also marked with a reference to the leading (=ZPAGE_FIRST_CLUST_POS)
+// and the last page (=ZPAGE_LAST_CLUST_POS) in the chunk.
+//
+// The aim of these data structures is to enable a free area handling of
+// free pages based on a buddy algorithm. When allocating pages it is
+// performed in chunks of pages and the algorithm tries to make the
+// chunks as large as possible.
+// This manager is invoked when fragments lack internal page space to
+// accomodate all the data they are requested to store. It is also
+// invoked when fragments deallocate page space back to the free area.
+//
+// The following routines are part of the external interface:
+// void
+// allocConsPages(Uint32 noOfPagesToAllocate, #In
+// Uint32& noOfPagesAllocated, #Out
+// Uint32& retPageRef) #Out
+// void
+// returnCommonArea(Uint32 retPageRef, #In
+// Uint32 retNoPages) #In
+//
+// allocConsPages tries to allocate noOfPagesToAllocate pages in one chunk.
+// If this fails it delivers a chunk as large as possible. It returns the
+// i-value of the first page in the chunk delivered, if zero pages returned
+// this i-value is undefined. It also returns the size of the chunk actually
+// delivered.
+//
+// returnCommonArea is used when somebody is returning pages to the free area.
+// It is used both from internal routines and external routines.
+//
+// The following routines are private routines used to support the
+// above external interface:
+// removeCommonArea()
+// insertCommonArea()
+// findFreeLeftNeighbours()
+// findFreeRightNeighbours()
+// Uint32
+// nextHigherTwoLog(Uint32 input)
+//
+// nextHigherTwoLog is a support routine which is a mathematical function with
+// an integer as input and an integer as output. It calculates the 2-log of
+// (input + 1). If the 2-log of (input + 1) is larger than 15 then the routine
+// will return 15. It is part of the external interface since it is also used
+// by other similar memory management algorithms.
+//
+// External dependencies:
+// None.
+//
+// Side Effects:
+// Apart from the above mentioned data structures there are no more
+// side effects other than through the subroutine parameters in the
+// external interface.
+//
+/* ---------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------- */
+/* CALCULATE THE 2-LOG + 1 OF TMP AND PUT RESULT INTO TBITS */
+/* ---------------------------------------------------------------- */
+Uint32 Dbtup::nextHigherTwoLog(Uint32 input)
+{
+ input = input | (input >> 8);
+ input = input | (input >> 4);
+ input = input | (input >> 2);
+ input = input | (input >> 1);
+ Uint32 output = (input & 0x5555) + ((input >> 1) & 0x5555);
+ output = (output & 0x3333) + ((output >> 2) & 0x3333);
+ output = output + (output >> 4);
+ output = (output & 0xf) + ((output >> 8) & 0xf);
+ return output;
+}//nextHigherTwoLog()
+
+void Dbtup::initializePage()
+{
+ for (Uint32 i = 0; i < 16; i++) {
+ cfreepageList[i] = RNIL;
+ }//for
+ PagePtr pagePtr;
+ for (pagePtr.i = 0; pagePtr.i < cnoOfPage; pagePtr.i++) {
+ ljam();
+ refresh_watch_dog();
+ ptrAss(pagePtr, page);
+ pagePtr.p->pageWord[ZPAGE_PHYSICAL_INDEX] = pagePtr.i;
+ pagePtr.p->pageWord[ZPAGE_NEXT_POS] = pagePtr.i + 1;
+ pagePtr.p->pageWord[ZPAGE_NEXT_CLUST_POS] = RNIL;
+ pagePtr.p->pageWord[ZPAGE_LAST_CLUST_POS] = RNIL;
+ pagePtr.p->pageWord[ZPAGE_PREV_POS] = RNIL;
+ pagePtr.p->pageWord[ZPAGE_STATE_POS] = ZFREE_COMMON;
+ }//for
+ pagePtr.i = cnoOfPage - 1;
+ ptrAss(pagePtr, page);
+ pagePtr.p->pageWord[ZPAGE_NEXT_POS] = RNIL;
+
+ pagePtr.i = 0;
+ ptrAss(pagePtr, page);
+ pagePtr.p->pageWord[ZPAGE_STATE_POS] = ~ZFREE_COMMON;
+
+ for(size_t j = 0; j<MAX_PARALLELL_TUP_SRREQ; j++){
+ pagePtr.i = 1+j;
+ ptrAss(pagePtr, page);
+ pagePtr.p->pageWord[ZPAGE_STATE_POS] = ~ZFREE_COMMON;
+ }
+
+ Uint32 tmp = 1 + MAX_PARALLELL_TUP_SRREQ;
+ returnCommonArea(tmp, cnoOfPage - tmp);
+ cnoOfAllocatedPages = tmp; // Is updated by returnCommonArea
+ c_sr_free_page_0 = ~0;
+}//Dbtup::initializePage()
+
+void Dbtup::allocConsPages(Uint32 noOfPagesToAllocate,
+ Uint32& noOfPagesAllocated,
+ Uint32& allocPageRef)
+{
+ if (noOfPagesToAllocate == 0){
+ ljam();
+ noOfPagesAllocated = 0;
+ return;
+ }//if
+
+ Uint32 firstListToCheck = nextHigherTwoLog(noOfPagesToAllocate - 1);
+ for (Uint32 i = firstListToCheck; i < 16; i++) {
+ ljam();
+ if (cfreepageList[i] != RNIL) {
+ ljam();
+/* ---------------------------------------------------------------- */
+/* PROPER AMOUNT OF PAGES WERE FOUND. NOW SPLIT THE FOUND */
+/* AREA AND RETURN THE PART NOT NEEDED. */
+/* ---------------------------------------------------------------- */
+ noOfPagesAllocated = noOfPagesToAllocate;
+ allocPageRef = cfreepageList[i];
+ removeCommonArea(allocPageRef, i);
+ Uint32 retNo = (1 << i) - noOfPagesToAllocate;
+ Uint32 retPageRef = allocPageRef + noOfPagesToAllocate;
+ returnCommonArea(retPageRef, retNo);
+ return;
+ }//if
+ }//for
+/* ---------------------------------------------------------------- */
+/* PROPER AMOUNT OF PAGES WERE NOT FOUND. FIND AS MUCH AS */
+/* POSSIBLE. */
+/* ---------------------------------------------------------------- */
+ for (Uint32 j = firstListToCheck; (Uint32)~j; j--) {
+ ljam();
+ if (cfreepageList[j] != RNIL) {
+ ljam();
+/* ---------------------------------------------------------------- */
+/* SOME AREA WAS FOUND, ALLOCATE ALL OF IT. */
+/* ---------------------------------------------------------------- */
+ allocPageRef = cfreepageList[j];
+ removeCommonArea(allocPageRef, j);
+ noOfPagesAllocated = 1 << j;
+ findFreeLeftNeighbours(allocPageRef, noOfPagesAllocated,
+ noOfPagesToAllocate);
+ findFreeRightNeighbours(allocPageRef, noOfPagesAllocated,
+ noOfPagesToAllocate);
+
+ return;
+ }//if
+ }//for
+/* ---------------------------------------------------------------- */
+/* NO FREE AREA AT ALL EXISTED. RETURN ZERO PAGES */
+/* ---------------------------------------------------------------- */
+ noOfPagesAllocated = 0;
+ return;
+}//allocConsPages()
+
+void Dbtup::returnCommonArea(Uint32 retPageRef, Uint32 retNo)
+{
+ do {
+ ljam();
+ if (retNo == 0) {
+ ljam();
+ return;
+ }//if
+ Uint32 list = nextHigherTwoLog(retNo) - 1;
+ retNo -= (1 << list);
+ insertCommonArea(retPageRef, list);
+ retPageRef += (1 << list);
+ } while (1);
+}//Dbtup::returnCommonArea()
+
+void Dbtup::findFreeLeftNeighbours(Uint32& allocPageRef,
+ Uint32& noPagesAllocated,
+ Uint32 noOfPagesToAllocate)
+{
+ PagePtr pageFirstPtr, pageLastPtr;
+ Uint32 remainAllocate = noOfPagesToAllocate - noPagesAllocated;
+ while (allocPageRef > 0) {
+ ljam();
+ pageLastPtr.i = allocPageRef - 1;
+ ptrCheckGuard(pageLastPtr, cnoOfPage, page);
+ if (pageLastPtr.p->pageWord[ZPAGE_STATE_POS] != ZFREE_COMMON) {
+ ljam();
+ return;
+ } else {
+ ljam();
+ pageFirstPtr.i = pageLastPtr.p->pageWord[ZPAGE_FIRST_CLUST_POS];
+ ndbrequire(pageFirstPtr.i != RNIL);
+ Uint32 list = nextHigherTwoLog(pageLastPtr.i - pageFirstPtr.i);
+ removeCommonArea(pageFirstPtr.i, list);
+ Uint32 listSize = 1 << list;
+ if (listSize > remainAllocate) {
+ ljam();
+ Uint32 retNo = listSize - remainAllocate;
+ returnCommonArea(pageFirstPtr.i, retNo);
+ allocPageRef = pageFirstPtr.i + retNo;
+ noPagesAllocated = noOfPagesToAllocate;
+ return;
+ } else {
+ ljam();
+ allocPageRef = pageFirstPtr.i;
+ noPagesAllocated += listSize;
+ remainAllocate -= listSize;
+ }//if
+ }//if
+ }//while
+}//Dbtup::findFreeLeftNeighbours()
+
+void Dbtup::findFreeRightNeighbours(Uint32& allocPageRef,
+ Uint32& noPagesAllocated,
+ Uint32 noOfPagesToAllocate)
+{
+ PagePtr pageFirstPtr, pageLastPtr;
+ Uint32 remainAllocate = noOfPagesToAllocate - noPagesAllocated;
+ if (remainAllocate == 0) {
+ ljam();
+ return;
+ }//if
+ while ((allocPageRef + noPagesAllocated) < cnoOfPage) {
+ ljam();
+ pageFirstPtr.i = allocPageRef + noPagesAllocated;
+ ptrCheckGuard(pageFirstPtr, cnoOfPage, page);
+ if (pageFirstPtr.p->pageWord[ZPAGE_STATE_POS] != ZFREE_COMMON) {
+ ljam();
+ return;
+ } else {
+ ljam();
+ pageLastPtr.i = pageFirstPtr.p->pageWord[ZPAGE_LAST_CLUST_POS];
+ ndbrequire(pageLastPtr.i != RNIL);
+ Uint32 list = nextHigherTwoLog(pageLastPtr.i - pageFirstPtr.i);
+ removeCommonArea(pageFirstPtr.i, list);
+ Uint32 listSize = 1 << list;
+ if (listSize > remainAllocate) {
+ ljam();
+ Uint32 retPageRef = pageFirstPtr.i + remainAllocate;
+ Uint32 retNo = listSize - remainAllocate;
+ returnCommonArea(retPageRef, retNo);
+ noPagesAllocated += remainAllocate;
+ return;
+ } else {
+ ljam();
+ noPagesAllocated += listSize;
+ remainAllocate -= listSize;
+ }//if
+ }//if
+ }//while
+}//Dbtup::findFreeRightNeighbours()
+
+void Dbtup::insertCommonArea(Uint32 insPageRef, Uint32 insList)
+{
+ cnoOfAllocatedPages -= (1 << insList);
+ PagePtr pageLastPtr, pageInsPtr;
+
+ pageInsPtr.i = insPageRef;
+ ptrCheckGuard(pageInsPtr, cnoOfPage, page);
+ ndbrequire(insList < 16);
+ pageLastPtr.i = (pageInsPtr.i + (1 << insList)) - 1;
+
+ pageInsPtr.p->pageWord[ZPAGE_NEXT_CLUST_POS] = cfreepageList[insList];
+ pageInsPtr.p->pageWord[ZPAGE_PREV_CLUST_POS] = RNIL;
+ pageInsPtr.p->pageWord[ZPAGE_LAST_CLUST_POS] = pageLastPtr.i;
+ cfreepageList[insList] = pageInsPtr.i;
+
+ ptrCheckGuard(pageLastPtr, cnoOfPage, page);
+ pageLastPtr.p->pageWord[ZPAGE_FIRST_CLUST_POS] = pageInsPtr.i;
+ pageLastPtr.p->pageWord[ZPAGE_NEXT_POS] = RNIL;
+}//Dbtup::insertCommonArea()
+
+void Dbtup::removeCommonArea(Uint32 remPageRef, Uint32 list)
+{
+ cnoOfAllocatedPages += (1 << list);
+ PagePtr pagePrevPtr, pageNextPtr, pageLastPtr, pageSearchPtr, remPagePtr;
+
+ remPagePtr.i = remPageRef;
+ ptrCheckGuard(remPagePtr, cnoOfPage, page);
+ ndbrequire(list < 16);
+ if (cfreepageList[list] == remPagePtr.i) {
+ ljam();
+ cfreepageList[list] = remPagePtr.p->pageWord[ZPAGE_NEXT_CLUST_POS];
+ pageNextPtr.i = cfreepageList[list];
+ if (pageNextPtr.i != RNIL) {
+ ljam();
+ ptrCheckGuard(pageNextPtr, cnoOfPage, page);
+ pageNextPtr.p->pageWord[ZPAGE_PREV_CLUST_POS] = RNIL;
+ }//if
+ } else {
+ pageSearchPtr.i = cfreepageList[list];
+ while (true) {
+ ljam();
+ ptrCheckGuard(pageSearchPtr, cnoOfPage, page);
+ pagePrevPtr = pageSearchPtr;
+ pageSearchPtr.i = pageSearchPtr.p->pageWord[ZPAGE_NEXT_CLUST_POS];
+ if (pageSearchPtr.i == remPagePtr.i) {
+ ljam();
+ break;
+ }//if
+ }//while
+ pageNextPtr.i = remPagePtr.p->pageWord[ZPAGE_NEXT_CLUST_POS];
+ pagePrevPtr.p->pageWord[ZPAGE_NEXT_CLUST_POS] = pageNextPtr.i;
+ if (pageNextPtr.i != RNIL) {
+ ljam();
+ ptrCheckGuard(pageNextPtr, cnoOfPage, page);
+ pageNextPtr.p->pageWord[ZPAGE_PREV_CLUST_POS] = pagePrevPtr.i;
+ }//if
+ }//if
+ remPagePtr.p->pageWord[ZPAGE_NEXT_CLUST_POS] = RNIL;
+ remPagePtr.p->pageWord[ZPAGE_LAST_CLUST_POS] = RNIL;
+ remPagePtr.p->pageWord[ZPAGE_PREV_CLUST_POS] = RNIL;
+
+ pageLastPtr.i = (remPagePtr.i + (1 << list)) - 1;
+ ptrCheckGuard(pageLastPtr, cnoOfPage, page);
+ pageLastPtr.p->pageWord[ZPAGE_FIRST_CLUST_POS] = RNIL;
+}//Dbtup::removeCommonArea()
+
+