DbtuxMeta.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:17k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #define DBTUX_META_CPP
  14. #include "Dbtux.hpp"
  15. /*
  16.  * Create index.
  17.  *
  18.  * For historical reasons it looks like we are adding random fragments
  19.  * and attributes to existing index.  In fact all fragments must be
  20.  * created at one time and they have identical attributes.
  21.  */
  22. void
  23. Dbtux::execTUXFRAGREQ(Signal* signal)
  24. {
  25.   jamEntry();
  26.   if (signal->theData[0] == (Uint32)-1) {
  27.     jam();
  28.     abortAddFragOp(signal);
  29.     return;
  30.   }
  31.   const TuxFragReq reqCopy = *(const TuxFragReq*)signal->getDataPtr();
  32.   const TuxFragReq* const req = &reqCopy;
  33.   IndexPtr indexPtr;
  34.   indexPtr.i = RNIL;
  35.   FragOpPtr fragOpPtr;
  36.   fragOpPtr.i = RNIL;
  37.   TuxFragRef::ErrorCode errorCode = TuxFragRef::NoError;
  38.   do {
  39.     // get the index record
  40.     if (req->tableId >= c_indexPool.getSize()) {
  41.       jam();
  42.       errorCode = TuxFragRef::InvalidRequest;
  43.       break;
  44.     }
  45.     c_indexPool.getPtr(indexPtr, req->tableId);
  46.     if (indexPtr.p->m_state != Index::NotDefined &&
  47.         indexPtr.p->m_state != Index::Defining) {
  48.       jam();
  49.       errorCode = TuxFragRef::InvalidRequest;
  50.       indexPtr.i = RNIL;        // leave alone
  51.       break;
  52.     }
  53.     // get new operation record
  54.     c_fragOpPool.seize(fragOpPtr);
  55.     ndbrequire(fragOpPtr.i != RNIL);
  56.     new (fragOpPtr.p) FragOp();
  57.     fragOpPtr.p->m_userPtr = req->userPtr;
  58.     fragOpPtr.p->m_userRef = req->userRef;
  59.     fragOpPtr.p->m_indexId = req->tableId;
  60.     fragOpPtr.p->m_fragId = req->fragId;
  61.     fragOpPtr.p->m_fragNo = indexPtr.p->m_numFrags;
  62.     fragOpPtr.p->m_numAttrsRecvd = 0;
  63. #ifdef VM_TRACE
  64.     if (debugFlags & DebugMeta) {
  65.       debugOut << "Seize frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl;
  66.     }
  67. #endif
  68.     // check if index has place for more fragments
  69.     ndbrequire(indexPtr.p->m_numFrags < MaxIndexFragments);
  70.     // seize new fragment record
  71.     FragPtr fragPtr;
  72.     c_fragPool.seize(fragPtr);
  73.     if (fragPtr.i == RNIL) {
  74.       jam();
  75.       errorCode = TuxFragRef::NoFreeFragment;
  76.       break;
  77.     }
  78.     new (fragPtr.p) Frag(c_scanOpPool);
  79.     fragPtr.p->m_tableId = req->primaryTableId;
  80.     fragPtr.p->m_indexId = req->tableId;
  81.     fragPtr.p->m_fragOff = req->fragOff;
  82.     fragPtr.p->m_fragId = req->fragId;
  83.     fragPtr.p->m_numAttrs = req->noOfAttr;
  84.     fragPtr.p->m_storeNullKey = true;  // not yet configurable
  85.     fragPtr.p->m_tupIndexFragPtrI = req->tupIndexFragPtrI;
  86.     fragPtr.p->m_tupTableFragPtrI[0] = req->tupTableFragPtrI[0];
  87.     fragPtr.p->m_tupTableFragPtrI[1] = req->tupTableFragPtrI[1];
  88.     fragPtr.p->m_accTableFragPtrI[0] = req->accTableFragPtrI[0];
  89.     fragPtr.p->m_accTableFragPtrI[1] = req->accTableFragPtrI[1];
  90.     // add the fragment to the index
  91.     indexPtr.p->m_fragId[indexPtr.p->m_numFrags] = req->fragId;
  92.     indexPtr.p->m_fragPtrI[indexPtr.p->m_numFrags] = fragPtr.i;
  93.     indexPtr.p->m_numFrags++;
  94.     // save under operation
  95.     fragOpPtr.p->m_fragPtrI = fragPtr.i;
  96.     // prepare to receive attributes
  97.     if (fragOpPtr.p->m_fragNo == 0) {
  98.       jam();
  99.       // receiving first fragment
  100.       ndbrequire(
  101.           indexPtr.p->m_state == Index::NotDefined &&
  102.           DictTabInfo::isOrderedIndex(req->tableType) &&
  103.           req->noOfAttr > 0 &&
  104.           req->noOfAttr <= MaxIndexAttributes &&
  105.           indexPtr.p->m_descPage == RNIL);
  106.       indexPtr.p->m_state = Index::Defining;
  107.       indexPtr.p->m_tableType = (DictTabInfo::TableType)req->tableType;
  108.       indexPtr.p->m_tableId = req->primaryTableId;
  109.       indexPtr.p->m_fragOff = req->fragOff;
  110.       indexPtr.p->m_numAttrs = req->noOfAttr;
  111.       indexPtr.p->m_storeNullKey = true;  // not yet configurable
  112.       // allocate attribute descriptors
  113.       if (! allocDescEnt(indexPtr)) {
  114.         jam();
  115.         errorCode = TuxFragRef::NoFreeAttributes;
  116.         break;
  117.       }
  118.     } else {
  119.       // receiving subsequent fragment
  120.       jam();
  121.       ndbrequire(
  122.           indexPtr.p->m_state == Index::Defining &&
  123.           indexPtr.p->m_tableType == (DictTabInfo::TableType)req->tableType &&
  124.           indexPtr.p->m_tableId == req->primaryTableId &&
  125.           indexPtr.p->m_fragOff == req->fragOff &&
  126.           indexPtr.p->m_numAttrs == req->noOfAttr);
  127.     }
  128.     // copy metadata address to each fragment
  129.     fragPtr.p->m_descPage = indexPtr.p->m_descPage;
  130.     fragPtr.p->m_descOff = indexPtr.p->m_descOff;
  131. #ifdef VM_TRACE
  132.     if (debugFlags & DebugMeta) {
  133.       debugOut << "Add frag " << fragPtr.i << " " << *fragPtr.p << endl;
  134.     }
  135. #endif
  136.     // error inserts
  137.     if (ERROR_INSERTED(12001) && fragOpPtr.p->m_fragNo == 0 ||
  138.         ERROR_INSERTED(12002) && fragOpPtr.p->m_fragNo == 1) {
  139.       jam();
  140.       errorCode = (TuxFragRef::ErrorCode)1;
  141.       CLEAR_ERROR_INSERT_VALUE;
  142.       break;
  143.     }
  144.     // success
  145.     TuxFragConf* const conf = (TuxFragConf*)signal->getDataPtrSend();
  146.     conf->userPtr = req->userPtr;
  147.     conf->tuxConnectPtr = fragOpPtr.i;
  148.     conf->fragPtr = fragPtr.i;
  149.     conf->fragId = fragPtr.p->m_fragId;
  150.     sendSignal(req->userRef, GSN_TUXFRAGCONF,
  151.         signal, TuxFragConf::SignalLength, JBB);
  152.     return;
  153.   } while (0);
  154.   // error
  155.   TuxFragRef* const ref = (TuxFragRef*)signal->getDataPtrSend();
  156.   ref->userPtr = req->userPtr;
  157.   ref->errorCode = errorCode;
  158.   sendSignal(req->userRef, GSN_TUXFRAGREF,
  159.       signal, TuxFragRef::SignalLength, JBB);
  160.   if (fragOpPtr.i != RNIL) {
  161. #ifdef VM_TRACE
  162.     if (debugFlags & DebugMeta) {
  163.       debugOut << "Release on frag error frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl;
  164.     }
  165. #endif
  166.     c_fragOpPool.release(fragOpPtr);
  167.   }
  168.   if (indexPtr.i != RNIL) {
  169.     jam();
  170.     // let DICT drop the unfinished index
  171.   }
  172. }
  173. void
  174. Dbtux::execTUX_ADD_ATTRREQ(Signal* signal)
  175. {
  176.   jamEntry();
  177.   const TuxAddAttrReq reqCopy = *(const TuxAddAttrReq*)signal->getDataPtr();
  178.   const TuxAddAttrReq* const req = &reqCopy;
  179.   // get the records
  180.   FragOpPtr fragOpPtr;
  181.   IndexPtr indexPtr;
  182.   FragPtr fragPtr;
  183.   c_fragOpPool.getPtr(fragOpPtr, req->tuxConnectPtr);
  184.   c_indexPool.getPtr(indexPtr, fragOpPtr.p->m_indexId);
  185.   c_fragPool.getPtr(fragPtr, fragOpPtr.p->m_fragPtrI);
  186.   TuxAddAttrRef::ErrorCode errorCode = TuxAddAttrRef::NoError;
  187.   do {
  188.     // expected attribute id
  189.     const unsigned attrId = fragOpPtr.p->m_numAttrsRecvd++;
  190.     ndbrequire(
  191.         indexPtr.p->m_state == Index::Defining &&
  192.         attrId < indexPtr.p->m_numAttrs &&
  193.         attrId == req->attrId);
  194.     // define the attribute
  195.     DescEnt& descEnt = getDescEnt(indexPtr.p->m_descPage, indexPtr.p->m_descOff);
  196.     DescAttr& descAttr = descEnt.m_descAttr[attrId];
  197.     descAttr.m_attrDesc = req->attrDescriptor;
  198.     descAttr.m_primaryAttrId = req->primaryAttrId;
  199.     descAttr.m_typeId = req->extTypeInfo & 0xFF;
  200.     descAttr.m_charset = (req->extTypeInfo >> 16);
  201. #ifdef VM_TRACE
  202.     if (debugFlags & DebugMeta) {
  203.       debugOut << "Add frag " << fragPtr.i << " attr " << attrId << " " << descAttr << endl;
  204.     }
  205. #endif
  206.     // check that type is valid and has a binary comparison method
  207.     const NdbSqlUtil::Type& type = NdbSqlUtil::getTypeBinary(descAttr.m_typeId);
  208.     if (type.m_typeId == NdbSqlUtil::Type::Undefined ||
  209.         type.m_cmp == 0) {
  210.       jam();
  211.       errorCode = TuxAddAttrRef::InvalidAttributeType;
  212.       break;
  213.     }
  214. #ifdef dbtux_uses_charset
  215.     if (descAttr.m_charset != 0) {
  216.       CHARSET_INFO *cs = get_charset(descAttr.m_charset, MYF(0));
  217.       // here use the non-binary type
  218.       if (! NdbSqlUtil::usable_in_ordered_index(descAttr.m_typeId, cs)) {
  219.         jam();
  220.         errorCode = TuxAddAttrRef::InvalidCharset;
  221.         break;
  222.       }
  223.     }
  224. #endif
  225.     const bool lastAttr = (indexPtr.p->m_numAttrs == fragOpPtr.p->m_numAttrsRecvd);
  226.     if (ERROR_INSERTED(12003) && fragOpPtr.p->m_fragNo == 0 && attrId == 0 ||
  227.         ERROR_INSERTED(12004) && fragOpPtr.p->m_fragNo == 0 && lastAttr ||
  228.         ERROR_INSERTED(12005) && fragOpPtr.p->m_fragNo == 1 && attrId == 0 ||
  229.         ERROR_INSERTED(12006) && fragOpPtr.p->m_fragNo == 1 && lastAttr) {
  230.       errorCode = (TuxAddAttrRef::ErrorCode)1;
  231.       CLEAR_ERROR_INSERT_VALUE;
  232.       break;
  233.     }
  234.     if (lastAttr) {
  235.       jam();
  236.       // initialize tree header
  237.       TreeHead& tree = fragPtr.p->m_tree;
  238.       new (&tree) TreeHead();
  239.       // make these configurable later
  240.       tree.m_nodeSize = MAX_TTREE_NODE_SIZE;
  241.       tree.m_prefSize = MAX_TTREE_PREF_SIZE;
  242.       const unsigned maxSlack = MAX_TTREE_NODE_SLACK;
  243.       // size up to and including first 2 entries
  244.       const unsigned pref = tree.getSize(AccPref);
  245.       if (! (pref <= tree.m_nodeSize)) {
  246.         jam();
  247.         errorCode = TuxAddAttrRef::InvalidNodeSize;
  248.         break;
  249.       }
  250.       const unsigned slots = (tree.m_nodeSize - pref) / TreeEntSize;
  251.       // leave out work space entry
  252.       tree.m_maxOccup = 2 + slots - 1;
  253.       // min occupancy of interior node must be at least 2
  254.       if (! (2 + maxSlack <= tree.m_maxOccup)) {
  255.         jam();
  256.         errorCode = TuxAddAttrRef::InvalidNodeSize;
  257.         break;
  258.       }
  259.       tree.m_minOccup = tree.m_maxOccup - maxSlack;
  260.       // root node does not exist (also set by ctor)
  261.       tree.m_root = NullTupLoc;
  262. #ifdef VM_TRACE
  263.       if (debugFlags & DebugMeta) {
  264.         if (fragOpPtr.p->m_fragNo == 0) {
  265.           debugOut << "Index id=" << indexPtr.i;
  266.           debugOut << " nodeSize=" << tree.m_nodeSize;
  267.           debugOut << " headSize=" << NodeHeadSize;
  268.           debugOut << " prefSize=" << tree.m_prefSize;
  269.           debugOut << " entrySize=" << TreeEntSize;
  270.           debugOut << " minOccup=" << tree.m_minOccup;
  271.           debugOut << " maxOccup=" << tree.m_maxOccup;
  272.           debugOut << endl;
  273.         }
  274.       }
  275. #endif
  276.       // fragment is defined
  277. #ifdef VM_TRACE
  278.       if (debugFlags & DebugMeta) {
  279.         debugOut << "Release frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl;
  280.       }
  281. #endif
  282.       c_fragOpPool.release(fragOpPtr);
  283.     }
  284.     // success
  285.     TuxAddAttrConf* conf = (TuxAddAttrConf*)signal->getDataPtrSend();
  286.     conf->userPtr = fragOpPtr.p->m_userPtr;
  287.     conf->lastAttr = lastAttr;
  288.     sendSignal(fragOpPtr.p->m_userRef, GSN_TUX_ADD_ATTRCONF,
  289.         signal, TuxAddAttrConf::SignalLength, JBB);
  290.     return;
  291.   } while (0);
  292.   // error
  293.   TuxAddAttrRef* ref = (TuxAddAttrRef*)signal->getDataPtrSend();
  294.   ref->userPtr = fragOpPtr.p->m_userPtr;
  295.   ref->errorCode = errorCode;
  296.   sendSignal(fragOpPtr.p->m_userRef, GSN_TUX_ADD_ATTRREF,
  297.       signal, TuxAddAttrRef::SignalLength, JBB);
  298. #ifdef VM_TRACE
  299.     if (debugFlags & DebugMeta) {
  300.       debugOut << "Release on attr error frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl;
  301.     }
  302. #endif
  303.   c_fragOpPool.release(fragOpPtr);
  304.   // let DICT drop the unfinished index
  305. }
  306. /*
  307.  * LQH aborts on-going create index operation.
  308.  */
  309. void
  310. Dbtux::abortAddFragOp(Signal* signal)
  311. {
  312.   FragOpPtr fragOpPtr;
  313.   IndexPtr indexPtr;
  314.   c_fragOpPool.getPtr(fragOpPtr, signal->theData[1]);
  315.   c_indexPool.getPtr(indexPtr, fragOpPtr.p->m_indexId);
  316. #ifdef VM_TRACE
  317.   if (debugFlags & DebugMeta) {
  318.     debugOut << "Release on abort frag op " << fragOpPtr.i << " " << *fragOpPtr.p << endl;
  319.   }
  320. #endif
  321.   c_fragOpPool.release(fragOpPtr);
  322.   // let DICT drop the unfinished index
  323. }
  324. /*
  325.  * Set index online.  Currently at system restart this arrives before
  326.  * build and is therefore not correct.
  327.  */
  328. void
  329. Dbtux::execALTER_INDX_REQ(Signal* signal)
  330. {
  331.   jamEntry();
  332.   const AlterIndxReq reqCopy = *(const AlterIndxReq*)signal->getDataPtr();
  333.   const AlterIndxReq* const req = &reqCopy;
  334.   // set index online after build
  335.   IndexPtr indexPtr;
  336.   c_indexPool.getPtr(indexPtr, req->getIndexId());
  337.   indexPtr.p->m_state = Index::Online;
  338. #ifdef VM_TRACE
  339.   if (debugFlags & DebugMeta) {
  340.     debugOut << "Online index " << indexPtr.i << " " << *indexPtr.p << endl;
  341.   }
  342. #endif
  343.   // success
  344.   AlterIndxConf* const conf = (AlterIndxConf*)signal->getDataPtrSend();
  345.   conf->setUserRef(reference());
  346.   conf->setConnectionPtr(req->getConnectionPtr());
  347.   conf->setRequestType(req->getRequestType());
  348.   conf->setTableId(req->getTableId());
  349.   conf->setIndexId(req->getIndexId());
  350.   conf->setIndexVersion(req->getIndexVersion());
  351.   sendSignal(req->getUserRef(), GSN_ALTER_INDX_CONF,
  352.       signal, AlterIndxConf::SignalLength, JBB);
  353. }
  354. /*
  355.  * Drop index.
  356.  *
  357.  * Uses same DROP_TAB_REQ signal as normal tables.
  358.  */
  359. void
  360. Dbtux::execDROP_TAB_REQ(Signal* signal)
  361. {
  362.   jamEntry();
  363.   const DropTabReq reqCopy = *(const DropTabReq*)signal->getDataPtr();
  364.   const DropTabReq* const req = &reqCopy;
  365.   IndexPtr indexPtr;
  366.   Uint32 tableId = req->tableId;
  367.   Uint32 senderRef = req->senderRef;
  368.   Uint32 senderData = req->senderData;
  369.   if (tableId >= c_indexPool.getSize()) {
  370.     jam();
  371.     // reply to sender
  372.     DropTabConf* const conf = (DropTabConf*)signal->getDataPtrSend();
  373.     conf->senderRef = reference();
  374.     conf->senderData = senderData;
  375.     conf->tableId = tableId;
  376.     sendSignal(senderRef, GSN_DROP_TAB_CONF,
  377.        signal, DropTabConf::SignalLength, JBB);
  378.     return;
  379.   }
  380.   
  381.   c_indexPool.getPtr(indexPtr, req->tableId);
  382.   // drop works regardless of index state
  383. #ifdef VM_TRACE
  384.   if (debugFlags & DebugMeta) {
  385.     debugOut << "Drop index " << indexPtr.i << " " << *indexPtr.p << endl;
  386.   }
  387. #endif
  388.   ndbrequire(req->senderRef != 0);
  389.   dropIndex(signal, indexPtr, req->senderRef, req->senderData);
  390. }
  391. void
  392. Dbtux::dropIndex(Signal* signal, IndexPtr indexPtr, Uint32 senderRef, Uint32 senderData)
  393. {
  394.   jam();
  395.   indexPtr.p->m_state = Index::Dropping;
  396.   // drop fragments
  397.   while (indexPtr.p->m_numFrags > 0) {
  398.     jam();
  399.     Uint32 i = --indexPtr.p->m_numFrags;
  400.     FragPtr fragPtr;
  401.     c_fragPool.getPtr(fragPtr, indexPtr.p->m_fragPtrI[i]);
  402.     c_fragPool.release(fragPtr);
  403.   }
  404.   // drop attributes
  405.   if (indexPtr.p->m_descPage != RNIL) {
  406.     jam();
  407.     freeDescEnt(indexPtr);
  408.     indexPtr.p->m_descPage = RNIL;
  409.   }
  410.   if (senderRef != 0) {
  411.     jam();
  412.     // reply to sender
  413.     DropTabConf* const conf = (DropTabConf*)signal->getDataPtrSend();
  414.     conf->senderRef = reference();
  415.     conf->senderData = senderData;
  416.     conf->tableId = indexPtr.i;
  417.     sendSignal(senderRef, GSN_DROP_TAB_CONF,
  418.         signal, DropTabConf::SignalLength, JBB);
  419.   }
  420.   new (indexPtr.p) Index();
  421. }
  422. /*
  423.  * Subroutines.
  424.  */
  425. bool
  426. Dbtux::allocDescEnt(IndexPtr indexPtr)
  427. {
  428.   jam();
  429.   const unsigned size = DescHeadSize + indexPtr.p->m_numAttrs * DescAttrSize;
  430.   DescPagePtr pagePtr;
  431.   pagePtr.i = c_descPageList;
  432.   while (pagePtr.i != RNIL) {
  433.     jam();
  434.     c_descPagePool.getPtr(pagePtr);
  435.     if (pagePtr.p->m_numFree >= size) {
  436.       jam();
  437.       break;
  438.     }
  439.     pagePtr.i = pagePtr.p->m_nextPage;
  440.   }
  441.   if (pagePtr.i == RNIL) {
  442.     jam();
  443.     if (! c_descPagePool.seize(pagePtr)) {
  444.       jam();
  445.       return false;
  446.     }
  447.     new (pagePtr.p) DescPage();
  448.     // add in front of list
  449.     pagePtr.p->m_nextPage = c_descPageList;
  450.     c_descPageList = pagePtr.i;
  451.     pagePtr.p->m_numFree = DescPageSize;
  452.   }
  453.   ndbrequire(pagePtr.p->m_numFree >= size);
  454.   indexPtr.p->m_descPage = pagePtr.i;
  455.   indexPtr.p->m_descOff = DescPageSize - pagePtr.p->m_numFree;
  456.   pagePtr.p->m_numFree -= size;
  457.   DescEnt& descEnt = getDescEnt(indexPtr.p->m_descPage, indexPtr.p->m_descOff);
  458.   descEnt.m_descHead.m_indexId = indexPtr.i;
  459.   descEnt.m_descHead.pad1 = 0;
  460.   return true;
  461. }
  462. void
  463. Dbtux::freeDescEnt(IndexPtr indexPtr)
  464. {
  465.   DescPagePtr pagePtr;
  466.   c_descPagePool.getPtr(pagePtr, indexPtr.p->m_descPage);
  467.   Uint32* const data = pagePtr.p->m_data;
  468.   const unsigned size = DescHeadSize + indexPtr.p->m_numAttrs * DescAttrSize;
  469.   unsigned off = indexPtr.p->m_descOff;
  470.   // move the gap to the free area at the top
  471.   while (off + size < DescPageSize - pagePtr.p->m_numFree) {
  472.     jam();
  473.     // next entry to move over the gap
  474.     DescEnt& descEnt2 = *(DescEnt*)&data[off + size];
  475.     Uint32 indexId2 = descEnt2.m_descHead.m_indexId;
  476.     Index& index2 = *c_indexPool.getPtr(indexId2);
  477.     unsigned size2 = DescHeadSize + index2.m_numAttrs * DescAttrSize;
  478.     ndbrequire(
  479.         index2.m_descPage == pagePtr.i &&
  480.         index2.m_descOff == off + size);
  481.     // move the entry (overlapping copy if size < size2)
  482.     unsigned i;
  483.     for (i = 0; i < size2; i++) {
  484.       jam();
  485.       data[off + i] = data[off + size + i];
  486.     }
  487.     off += size2;
  488.     // adjust page offset in index and all fragments
  489.     index2.m_descOff -= size;
  490.     for (i = 0; i < index2.m_numFrags; i++) {
  491.       jam();
  492.       Frag& frag2 = *c_fragPool.getPtr(index2.m_fragPtrI[i]);
  493.       frag2.m_descOff -= size;
  494.       ndbrequire(
  495.           frag2.m_descPage == index2.m_descPage &&
  496.           frag2.m_descOff == index2.m_descOff);
  497.     }
  498.   }
  499.   ndbrequire(off + size == DescPageSize - pagePtr.p->m_numFree);
  500.   pagePtr.p->m_numFree += size;
  501. }