Advertisement
Guest User

Untitled

a guest
Dec 7th, 2019
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.23 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////////////
  2. // Module Name:  btree.h/cpp
  3. // Authors:      Sergey Shershakov
  4. // Version:      0.1.0
  5. // Date:         01.05.2017
  6. //
  7. // This is a part of the course "Algorithms and Data Structures"
  8. // provided by  the School of Software Engineering of the Faculty
  9. // of Computer Science at the Higher School of Economics.
  10. ////////////////////////////////////////////////////////////////////////////////
  11.  
  12.  
  13. #include "btree.h"
  14.  
  15. #include <stdexcept>        // std::invalid_argument
  16. #include <cstring>          // memset
  17.  
  18.  
  19. namespace xi {
  20.  
  21.  
  22. //==============================================================================
  23. // class BaseBTree
  24. //==============================================================================
  25.  
  26.  
  27.  
  28. bool BaseBTree::Header::checkIntegrity()
  29. {
  30.     return (sign == VALID_SIGN) && (order >= 1) && (recSize > 0);
  31. }
  32.  
  33.  
  34.  
  35. BaseBTree::BaseBTree(UShort order, UShort recSize, IComparator* comparator, std::iostream* stream)
  36.     : _order(order),
  37.     _recSize(recSize),
  38.     _comparator(comparator),
  39.     _stream(stream),
  40.     _lastPageNum(0),
  41.     _rootPageNum(0)
  42.     , _rootPage(this)
  43. {
  44. }
  45.  
  46.  
  47. BaseBTree::BaseBTree(IComparator* comparator, std::iostream* stream):
  48.     BaseBTree(
  49.         0,      // порядок, 0 — д.б. прочитан из файла!
  50.         0,      // размер ключа, 0 —  --//--
  51.         comparator, stream)
  52. {
  53.  
  54. }
  55.  
  56.  
  57.  
  58. BaseBTree::~BaseBTree()
  59. {
  60. }
  61.  
  62.  
  63. void BaseBTree::resetBTree()
  64. {
  65.     _order = 0;
  66.     _recSize = 0;
  67.     _stream = nullptr;
  68.     _comparator = nullptr;      // для порядку его тоже сбасываем, но это не очень обязательно
  69. }
  70.  
  71.  
  72.  
  73.  
  74. void BaseBTree::readPage(UInt pnum, Byte* dst)
  75. {    
  76.     checkForOpenStream();
  77.     if (pnum == 0 || pnum > getLastPageNum())
  78.         throw std::invalid_argument("Can't read a non-existing page");
  79.  
  80.     readPageInternal(pnum, dst);
  81. }
  82.  
  83.  
  84. void BaseBTree::writePage(UInt pnum, const Byte* dst)
  85. {
  86.     checkForOpenStream();
  87.  
  88.     if (pnum == 0 || pnum > getLastPageNum())
  89.         throw std::invalid_argument("Can't write a non-existing page");
  90.  
  91.     writePageInternal(pnum, dst);
  92.  
  93. }
  94.  
  95.  
  96. bool BaseBTree::checkKeysNumber(UShort keysNum, bool isRoot)
  97. {
  98.     if (keysNum > getMaxKeys())
  99.         return false;                       // превышение по максимуму
  100.  
  101.     // NOTE: для корня пока даже 0 допустим, потом уточним, надо ли до 1 сокращать
  102.     if (isRoot)
  103.     //if (nt == nRoot)
  104.         return true;
  105.  
  106.     return (keysNum >= getMinKeys());        
  107. }
  108.  
  109.  
  110. void BaseBTree::checkKeysNumberExc(UShort keysNum, bool isRoot)
  111. {
  112.     if (!checkKeysNumber(keysNum,  isRoot))
  113.         throw std::invalid_argument("Invalid number of keys for a node");
  114. }
  115.  
  116.  
  117. UInt BaseBTree::allocPage(PageWrapper& pw, UShort keysNum, bool isLeaf /*= false*/)
  118. {
  119.     checkForOpenStream();
  120.     checkKeysNumberExc(keysNum, pw.isRoot());  // nt);
  121.     return allocPageInternal(pw, keysNum, pw.isRoot(),  isLeaf);
  122. }
  123.  
  124.  
  125. xi::UInt BaseBTree::allocNewRootPage(PageWrapper& pw)
  126. {
  127.     checkForOpenStream();
  128.     return allocPageInternal(pw, 0, true, false);
  129. }
  130.  
  131.  
  132.  
  133.  
  134. Byte* BaseBTree::search(const Byte* k)
  135. {
  136.     PageWrapper checkedNode(this);
  137.     checkedNode.readPage(_rootPageNum);
  138.     while (true)
  139.     {
  140.         UShort size = checkedNode.getKeysNum();
  141.         UShort keyIndex = 0;
  142.  
  143.         while (keyIndex < size)
  144.         {
  145.             Byte* currChildKey = checkedNode.getKey(keyIndex);
  146.  
  147.             if(currChildKey)
  148.             {
  149.                 if (_comparator->isEqual(currChildKey, k, getRecSize()))
  150.                 {
  151.                     memcpy(_searchKey, currChildKey, getRecSize());
  152.                     return _searchKey;
  153.                 }
  154.  
  155.                 if (!_comparator->compare(currChildKey, k, getRecSize()))
  156.                     break;
  157.             }
  158.             ++keyIndex;
  159.         }
  160.  
  161.         if (checkedNode.isLeaf())
  162.             return nullptr;
  163.  
  164.         checkedNode.readPageFromChild(checkedNode, keyIndex);
  165.     }
  166. }
  167.  
  168.  
  169. int BaseBTree::searchAll(const Byte* k, std::list<Byte*>& keys)
  170. {
  171.     int result = 0;
  172.     PageWrapper checkedNode(this);
  173.     checkedNode.readPage(_rootPageNum);
  174.     bool found = false;
  175.     int firstFoundIndex = 0;
  176.     while(!found)
  177.     {
  178.         UShort size = checkedNode.getKeysNum();
  179.         UShort keyIndex = 0;
  180.         while(keyIndex < size)
  181.         {
  182.             Byte* currChildKey = checkedNode.getKey(keyIndex);
  183.             if(currChildKey)
  184.             {
  185.                 if(_comparator->isEqual(currChildKey, k, getRecSize()))
  186.                 {
  187.                     found = true;
  188.                     firstFoundIndex = keyIndex;
  189.                     break;
  190.                 }
  191.                 if(!_comparator->compare(currChildKey, k, getRecSize()))
  192.                     break;
  193.             }
  194.             ++keyIndex;
  195.         }
  196.         if(found)
  197.             break;
  198.         if(checkedNode.isLeaf())
  199.             return 0;
  200.         checkedNode.readPageFromChild(checkedNode, keyIndex);
  201.     }
  202.  
  203.     for(int index = firstFoundIndex; index < checkedNode.getKeysNum(); ++index)
  204.     {
  205.         Byte* currChildKey = checkedNode.getKey(index);
  206.         if (!currChildKey || !_comparator->isEqual(currChildKey, k, getRecSize()))
  207.             return result;
  208.  
  209.         memcpy(_searchKey, currChildKey, getRecSize());
  210.         keys.push_back(_searchKey);
  211.         ++result;
  212.         if(!checkedNode.isLeaf())
  213.         {
  214.             if(index == firstFoundIndex)
  215.                 result += findMyClonesLeft(k, keys, checkedNode.getPageNum(), index);
  216.             result += findMyClonesRight(k, keys, checkedNode.getPageNum(), index);
  217.         }
  218.     }
  219.     return  result;
  220. }
  221.  
  222. int BaseBTree::findMyClonesLeft(const Byte* k, std::list<Byte*>& keys, UInt myHomePage, int myRoomNum)
  223. {
  224.     int result = 0;
  225.     PageWrapper checkedNode(this);
  226.     checkedNode.readPage(myHomePage);
  227.     PageWrapper leftSubtree(this);
  228.     leftSubtree.readPageFromChild(checkedNode, myRoomNum);
  229.     for(int index = leftSubtree.getKeysNum() - 1; index >= 0; --index)
  230.     {
  231.         Byte* currChildKey = leftSubtree.getKey(index);
  232.         if (!currChildKey || !_comparator->isEqual(currChildKey, k, getRecSize()))
  233.             return result;
  234.         memcpy(_searchKey, currChildKey, getRecSize());
  235.         keys.push_back(_searchKey);
  236.         ++result;
  237.         if(!leftSubtree.isLeaf())
  238.         {
  239.             if(index == leftSubtree.getKeysNum() - 1)
  240.                 result += findMyClonesRight(k, keys, leftSubtree.getPageNum(), index);
  241.  
  242.             result += findMyClonesLeft(k, keys, leftSubtree.getPageNum(), index);
  243.         }
  244.     }
  245.     return result;
  246. }
  247.  
  248.  
  249. int BaseBTree::findMyClonesRight(const Byte* k, std::list<Byte*>& keys, UInt myHomePage, int myRoomNum)
  250. {
  251.     int result = 0;
  252.     PageWrapper checkedNode(this);
  253.     checkedNode.readPage(myHomePage);
  254.     PageWrapper rightSubtree(this);
  255.     rightSubtree.readPageFromChild(checkedNode, myRoomNum + 1);
  256.     for(int index = 0; index < rightSubtree.getKeysNum(); ++index)
  257.     {
  258.         Byte* currChildKey = rightSubtree.getKey(index);
  259.         if (!currChildKey || !_comparator->isEqual(currChildKey, k, getRecSize()))
  260.             return result;
  261.         memcpy(_searchKey, currChildKey, getRecSize());
  262.         keys.push_back(_searchKey);
  263.         ++result;
  264.         if(!rightSubtree.isLeaf())
  265.         {
  266.             if(index == 0)
  267.                 result += findMyClonesLeft(k, keys, rightSubtree.getPageNum(), index);
  268.             result += findMyClonesRight(k, keys, rightSubtree.getPageNum(), index);
  269.         }
  270.     }
  271.     return result;
  272. }
  273.  
  274.  
  275. //UInt BaseBTree::allocPageInternal(UShort keysNum, NodeType nt, PageWrapper& pw)
  276. UInt BaseBTree::allocPageInternal(PageWrapper& pw, UShort keysNum, bool isRoot, bool isLeaf)
  277. {
  278.     // подготовим страничку для вывода
  279.     pw.clear();
  280.     pw.setKeyNumLeaf(keysNum, isRoot, isLeaf);    // nt);
  281.  
  282.     // пока что просто позиционируемся в конец, считая, что так и будет, но держать под контролем
  283.     _stream->seekg(0, std::ios_base::end);    
  284.     _stream->write((const char*)pw.getData(), getNodePageSize());
  285.  
  286.     ++_lastPageNum;
  287.     writePageCounter();
  288.  
  289.  
  290.     // TODO: flush-им на диск сразу?!
  291.     //_stream->flush();
  292.  
  293.     return _lastPageNum;
  294. }
  295.  
  296.  
  297.  
  298. void BaseBTree::readPageInternal(UInt pnum, Byte* dst)
  299. {
  300.     // позиционируемся и читаем
  301.     gotoPage(pnum);
  302.     _stream->read((char*)dst, getNodePageSize());
  303. }
  304.  
  305.  
  306. void BaseBTree::writePageInternal(UInt pnum, const Byte* dst)
  307. {
  308.     // позиционируемся и пишем
  309.     gotoPage(pnum);
  310.     _stream->write((const char*)dst, getNodePageSize());
  311. }
  312.  
  313.  
  314. void BaseBTree::gotoPage(UInt pnum)
  315. {
  316.     // рассчитаем смещение до нужной страницы
  317.     UInt pageOfs = FIRST_PAGE_OFS + getNodePageSize() * (pnum - 1);     // т.к. нумеруются с единицы
  318.     _stream->seekg(pageOfs, std::ios_base::beg);
  319. }
  320.  
  321.  
  322. void BaseBTree::loadTree()
  323. {
  324.     // _stream->seekg(0, std::ios_base::beg);       // пока загружаем с текущего места в потоке!
  325.     // читаем заголовок
  326.    
  327.     Header hdr;
  328.     readHeader(hdr);
  329.  
  330.     // если при чтении случилась пичалька
  331.     if (_stream->fail())
  332.     {
  333.         //_stream->close();
  334.         throw std::runtime_error("Can't read header");
  335.     }
  336.  
  337.     // проверяет заголовок на корректность
  338.     if (!hdr.checkIntegrity())
  339.     {
  340.         //_stream->close();
  341.         throw std::runtime_error("Stream is not a valid xi B-tree file");
  342.     }
  343.  
  344.     // задаем порядок и т.д.
  345.     setOrder(hdr.order, hdr.recSize);
  346.  
  347.     // далее без проверки читаем два следующих поля
  348.     readPageCounter();             // номер текущей свободной страницы
  349.     readRootPageNum();             // номер корневой страницы
  350.  
  351.     // если при чтении случилась пичалька
  352.     if (_stream->fail())
  353.     {
  354.         //_fileStream.close();
  355.         throw std::runtime_error("Can't read necessary fields. File corrupted");
  356.     }
  357.  
  358.     // загрузить корневую страницу
  359.     loadRootPage();
  360.  
  361. }
  362.  
  363.  
  364. void BaseBTree::loadRootPage()  //PageWrapper& pw)
  365. {
  366.     if (getRootPageNum() == 0)
  367.         throw std::runtime_error("Root page is not defined");
  368.  
  369.     _rootPage.readPage(getRootPageNum());
  370.     _rootPage.setAsRoot(false);               // в файл номер страницы не пишем, т.к. только что прочитали оттуда его
  371.  
  372. }
  373.  
  374.  
  375. void BaseBTree::createTree(UShort order, UShort recSize)
  376. {
  377.     setOrder(order, recSize);
  378.  
  379.     writeHeader();                  // записываем заголовок файла
  380.     writePageCounter();             // и номер текущей свободной страницы
  381.     writeRootPageNum();             // и номер корневой страницы
  382.  
  383.  
  384.     // создать корневую страницу
  385.     createRootPage();
  386. }
  387.  
  388.  
  389. void BaseBTree::createRootPage()
  390. {
  391.     _rootPage.allocPage(0, true);
  392.     _rootPage.setAsRoot();
  393. }
  394. void BaseBTree::changeRootPage()
  395. {
  396.     _rootPage.allocPage(0, true);
  397.     _rootPage.setAsRoot();
  398. }
  399.  
  400. void BaseBTree::checkForOpenStream()
  401. {
  402.     if (!isOpen())
  403.         throw std::runtime_error("Stream is not ready");
  404.  
  405. }
  406.  
  407.  
  408. void BaseBTree::writeHeader()
  409. {    
  410.     Header hdr(_order, _recSize);    
  411.     _stream->write((const char*)(void*)&hdr, HEADER_SIZE);
  412.  
  413. }
  414.  
  415. void BaseBTree::readHeader(Header& hdr)
  416. {
  417.     _stream->seekg(HEADER_OFS, std::ios_base::beg);
  418.     _stream->read((char*)&hdr, HEADER_SIZE);
  419.  
  420. }
  421.  
  422.  
  423.  
  424. void BaseBTree::writePageCounter() //UInt pc)
  425. {
  426.     _stream->seekg(PAGE_COUNTER_OFS, std::ios_base::beg);
  427.     _stream->write((const char*)&_lastPageNum, PAGE_COUNTER_SZ);
  428. }
  429.  
  430.  
  431.  
  432. //xi::UInt
  433. void BaseBTree::readPageCounter()
  434. {
  435.     _stream->seekg(PAGE_COUNTER_OFS, std::ios_base::beg);    
  436.     _stream->read((char*)&_lastPageNum, PAGE_COUNTER_SZ);
  437. }
  438.  
  439.  
  440.  
  441. void BaseBTree::writeRootPageNum() //UInt rpn)
  442. {
  443.     _stream->seekg(ROOT_PAGE_NUM_OFS, std::ios_base::beg);
  444.     _stream->write((const char*)&_rootPageNum, ROOT_PAGE_NUM_SZ);
  445.  
  446. }
  447.  
  448.  
  449.  
  450. //xi::UInt
  451. void BaseBTree::readRootPageNum()
  452. {
  453.     _stream->seekg(ROOT_PAGE_NUM_OFS, std::ios_base::beg);
  454.     _stream->read((char*)&_rootPageNum, ROOT_PAGE_NUM_SZ);
  455. }
  456.  
  457.  
  458.  
  459. void BaseBTree::setRootPageNum(UInt pnum, bool writeFlag /*= true*/)
  460. {
  461.     _rootPageNum = pnum;
  462.     if (writeFlag)
  463.         writeRootPageNum();
  464. }
  465.  
  466.  
  467.  
  468. void BaseBTree::setOrder(UShort order, UShort recSize)
  469. {
  470.     // метод закрытый, корректность параметров должно проверять в вызывающих методах
  471.  
  472.     _order = order;
  473.     _recSize = recSize;
  474.  
  475.     _minKeys = order - 1;
  476.     _maxKeys = 2 * order - 1;
  477.  
  478.     // проверим максимальное число ключей
  479.     if (_maxKeys > MAX_KEYS_NUM)
  480.         throw std::invalid_argument("For a given B-tree order, there is an excess of the maximum number of keys");
  481.  
  482.     _keysSize = _recSize * _maxKeys;                // область памяти под ключи
  483.     _cursorsOfs = _keysSize + KEYS_OFS;             // смещение области курсоров на дочерние
  484.     _nodePageSize = _cursorsOfs + CURSOR_SZ * (2 * order);  // размер узла целиком, опр. концом области страницы
  485.  
  486.     // Q: номер текущей корневой надо устанавливать?
  487.  
  488.     // пока-что распределяем память под рабочую страницу/узел здесь, но это сомнительно
  489.     reallocWorkPages();
  490. }
  491.  
  492.  
  493. void BaseBTree::reallocWorkPages()
  494. {
  495.     _rootPage.reallocData(_nodePageSize);
  496. }
  497.  
  498.  
  499.  
  500.  
  501.  
  502. //==============================================================================
  503. // class BaseBTree::PageWrapper
  504. //==============================================================================
  505.  
  506.  
  507.  
  508. BaseBTree::PageWrapper::PageWrapper(BaseBTree* tr) :
  509.     _data(nullptr)
  510.     , _tree(tr)
  511.     , _pageNum(0)
  512. {
  513.     // если к моменту создания странички дерево уже в работе (открыто), надо
  514.     // сразу распределить память!
  515.     if (_tree->isOpen())
  516.         reallocData(_tree->getNodePageSize());
  517.  
  518. }
  519.  
  520.  
  521. BaseBTree::PageWrapper::~PageWrapper()
  522. {
  523.     reallocData(0);
  524. }
  525.  
  526.  
  527. void BaseBTree::PageWrapper::reallocData(UInt sz)
  528. {
  529.     if (_data)
  530.         delete[] _data;
  531.  
  532.     if (sz)
  533.         _data = new Byte[sz];
  534.        
  535. }
  536.  
  537. void BaseBTree::PageWrapper::clear()
  538. {
  539.     if (!_data)
  540.         return;
  541.  
  542.     // работая с сырыми блоками данных единственно и можно применять низкоуровневые C-функции
  543.     memset(_data, 0, _tree->getNodePageSize());
  544. }
  545.  
  546.  
  547.  
  548. void BaseBTree::PageWrapper::setKeyNumLeaf(UShort keysNum, bool isRoot, bool isLeaf) //NodeType nt)
  549. {
  550.     _tree->checkKeysNumberExc(keysNum, isRoot);
  551.  
  552.     // логически приплюсовываем
  553.     if (isLeaf)
  554.         keysNum |= LEAF_NODE_MASK; // 0x8000;
  555.  
  556.     // способ записи типизированного объекта, начиная с адреса [0]
  557.     *((UShort*)&_data[0]) = keysNum;
  558. }
  559.  
  560.  
  561.  
  562. void BaseBTree::PageWrapper::setKeyNum(UShort keysNum, bool isRoot) //NodeType nt)
  563. {
  564.     _tree->checkKeysNumberExc(keysNum, isRoot);
  565.  
  566.  
  567.     UShort kldata = *((UShort*)&_data[0]);      // взяли сущ. значение
  568.     kldata &= LEAF_NODE_MASK;                   // оставили от него только флаг "лист"
  569.     kldata |= keysNum;                          // приилили число ключей (там точно не будет 1 в старшем)
  570.  
  571.     *((UShort*)&_data[0]) = kldata;             // записали
  572. }
  573.  
  574.  
  575.  
  576. void BaseBTree::PageWrapper::setLeaf(bool isLeaf)
  577. {
  578.     UShort kldata = *((UShort*)&_data[0]);      // взяли сущ. значение
  579.     kldata &= ~LEAF_NODE_MASK;                  // оставили от него только часть с числом ключей
  580.     if (isLeaf)
  581.         kldata |= LEAF_NODE_MASK;   // 0x8000;  // приилили флаг, если надо
  582.  
  583.     *((UShort*)&_data[0]) = kldata;             // записали
  584. }
  585.  
  586.  
  587.  
  588. bool BaseBTree::PageWrapper::isLeaf() const
  589. {
  590.     UShort info = *((UShort*)&_data[0]);
  591.  
  592.     return (info & LEAF_NODE_MASK) != 0;
  593. }
  594.  
  595. UShort BaseBTree::PageWrapper::getKeysNum() const
  596. {
  597.     UShort info = *((UShort*)&_data[0]);
  598.  
  599.     return (info & ~LEAF_NODE_MASK);
  600. }
  601.  
  602.  
  603.  
  604. Byte* BaseBTree::PageWrapper::getKey(UShort num)
  605. {
  606.     // рассчитываем смещение
  607.     //UInt kofst = KEYS_OFS + _tree->getRecSize() * num;
  608.     int kofst = getKeyOfs(num);
  609.     if (kofst == -1)
  610.         return nullptr;
  611.  
  612.     return (_data + kofst);
  613. }
  614.  
  615.  
  616. const Byte* BaseBTree::PageWrapper::getKey(UShort num) const
  617. {
  618.     int kofst = getKeyOfs(num);
  619.     if (kofst == -1)
  620.         return nullptr;
  621.  
  622.     return (_data + kofst);
  623. }
  624.  
  625.  
  626. void BaseBTree::PageWrapper::copyKey(Byte* dst, const Byte* src)
  627. {
  628.     memcpy(
  629.         dst,                        // куда
  630.         src,                        // откуда
  631.         _tree->getRecSize());       // размер ключа
  632. }
  633.  
  634. void BaseBTree::PageWrapper::copyKeys(Byte* dst, const Byte* src, UShort num)
  635. {
  636.     memcpy(
  637.         dst,                        // куда
  638.         src,                        // откуда
  639.         _tree->getRecSize() * num   // размер: размер записи на число элементов
  640.         );
  641.  
  642. }
  643.  
  644. void BaseBTree::PageWrapper::copyCursors(Byte* dst, const Byte* src, UShort num)
  645. {
  646.     memcpy(
  647.         dst,                        // куда
  648.         src,                        // откуда
  649.         num * CURSOR_SZ             // размер
  650.         );
  651. }
  652.  
  653. UInt BaseBTree::PageWrapper::getCursor(UShort cnum)
  654. {
  655.     //if (cnum > getKeysNum())
  656.     int curOfs = getCursorOfs(cnum);
  657.     if (curOfs == -1)
  658.         throw std::invalid_argument("Wrong cursor number");
  659.  
  660.     return *((const UInt*)(_data + curOfs));
  661. }
  662.  
  663.  
  664. Byte* BaseBTree::PageWrapper::getCursorPtr(UShort cnum)
  665. {
  666.     int curOfs = getCursorOfs(cnum);
  667.     if (curOfs == -1)
  668.         throw std::invalid_argument("Wrong cursor number");
  669.  
  670.     return (_data + curOfs);
  671.  
  672. }
  673.  
  674. void BaseBTree::PageWrapper::setCursor(UShort cnum, UInt cval)
  675. {
  676.     int curOfs = getCursorOfs(cnum);
  677.     if (curOfs == -1)
  678.         throw std::invalid_argument("Wrong cursor number");
  679.  
  680.     //not a leaf anymore
  681.     this->setLeaf(false);
  682.     *((UInt*)(_data + curOfs)) = cval;
  683. }
  684.  
  685.  
  686. int BaseBTree::PageWrapper::getCursorOfs(UShort cnum) const
  687. {
  688.     if (cnum > getKeysNum())
  689.         return -1;
  690.  
  691.     // рассчитываем смещением
  692.     return _tree->getCursorsOfs() + CURSOR_SZ * cnum;
  693. }
  694.  
  695. int BaseBTree::PageWrapper::getKeyOfs(UShort num) const
  696. {
  697.     if (num >= getKeysNum())
  698.         return -1;
  699.  
  700.     // рассчитываем смещение
  701.     return KEYS_OFS + _tree->getRecSize() * num;
  702. }
  703.  
  704.  
  705. void BaseBTree::PageWrapper::setAsRoot(bool writeFlag /*= true*/)
  706. {
  707.     _tree->_rootPageNum = _pageNum;         // ид корень по номеру страницы в памяти
  708.  
  709.     if (!writeFlag)
  710.         return;
  711.  
  712.     // если же надо записать в файл сразу...
  713.     if (_pageNum == 0)
  714.         throw std::runtime_error("Can't set a page as root until allocate a page in a file");
  715.  
  716.     // если же под страницу есть номер, запишем его в файл
  717.     _tree->setRootPageNum(_pageNum, true);
  718. }
  719.  
  720.  
  721.  
  722. void BaseBTree::PageWrapper::readPageFromChild(PageWrapper& pw, UShort chNum)
  723. {
  724.     UInt cur = pw.getCursor(chNum);
  725.     if (cur == 0)
  726.         throw std::invalid_argument("Cursor does not point to a existing node/page");
  727.    
  728.     readPage(cur);
  729. }
  730.  
  731.  
  732. void BaseBTree::PageWrapper::writePage()
  733. {
  734.     if (getPageNum() == 0)
  735.         throw std::runtime_error("Page number not set. Can't write");
  736.  
  737.     _tree->writePage(getPageNum(), _data);
  738. }
  739.  
  740.  
  741.  
  742. void BaseBTree::PageWrapper::splitChild(UShort iChild)
  743. {
  744.     if (isFull())
  745.         throw std::domain_error("A parent node is full, so its child can't be splitted");
  746.     if (iChild > getKeysNum())
  747.         throw std::invalid_argument("Cursor not exists");
  748.  
  749.     PageWrapper child(_tree);
  750.     child.readPageFromChild(*this, iChild);
  751.  
  752.     if(!child.isFull())
  753.         throw std::invalid_argument("Splitted child must be full!");
  754.  
  755.     bool isLeaf = child.isLeaf();
  756.     Byte* medianaValue = child.getKey(_tree->_order - 1);
  757.  
  758.     this->setKeyNum(getKeysNum() + 1);
  759.  
  760.     for(UShort i = getKeysNum() - 1; i > iChild; --i)
  761.     {
  762.         Byte* left = this->getKey(i - 1);
  763.         Byte* current = this->getKey(i);
  764.         copyKey(current, left);
  765.     }
  766.     for(UShort i = getKeysNum() - 1; i > iChild; --i)
  767.     {
  768.         Byte* leftCursor = getCursorPtr(i);
  769.         Byte* currCursor = getCursorPtr(i + 1);
  770.         copyCursors(currCursor, leftCursor, 1);
  771.     }
  772.  
  773.     copyKey(this->getKey(iChild), medianaValue);
  774.  
  775.     PageWrapper rightChild(_tree);
  776.     rightChild.allocPage(_tree->_order - 1, isLeaf);
  777.     this->setCursor(iChild + 1, rightChild.getPageNum());
  778.  
  779.     rightChild.copyKeys(rightChild.getKey(0), child.getKey(_tree->_order), _tree->_order - 1);
  780.     rightChild.copyCursors(rightChild.getCursorPtr(0), child.getCursorPtr(_tree->_order), _tree->_order);
  781.  
  782.     child.setKeyNum(_tree->_order - 1);
  783.  
  784.     rightChild.writePage();
  785.     child.writePage();
  786.     this->writePage();
  787.  
  788. }
  789.  
  790.  
  791. void BaseBTree::PageWrapper::insertNonFull(const Byte* k)
  792. {
  793.     if (isFull())
  794.         throw std::domain_error("Node is full. Can't insert");
  795.  
  796.     IComparator* c = _tree->getComparator();
  797.     if (!c)
  798.         throw std::runtime_error("Comparator not set. Can't insert");
  799.  
  800.     if(this->isLeaf())
  801.     {
  802.         this->setKeyNum(this->getKeysNum() + 1);
  803.         int position = -1;
  804.  
  805.         for (int i = 0; i < this->getKeysNum() - 1; ++i)
  806.         {
  807.             if(!c->compare(this->getKey(i), k, _tree->getRecSize()))
  808.             {
  809.                 position = i;
  810.                 break;
  811.             }
  812.         }
  813.  
  814.         if(position == -1)
  815.             copyKey(this->getKey(this->getKeysNum() - 1), k);
  816.         else
  817.         {
  818.             for (int i = this->getKeysNum() - 2; i >= position; --i)
  819.             {
  820.                 Byte* current = this->getKey(i);
  821.                 Byte* right = this->getKey(i + 1);
  822.                 copyKey(right, current);
  823.             }
  824.             Byte* current = this->getKey(position);
  825.             copyKey(current, k);
  826.         }
  827.         this->writePage();
  828.     }
  829.  
  830.     else
  831.     {
  832.         int position = 0;
  833.         for (int i = this->getKeysNum() - 1; i >= 0; --i)
  834.         {
  835.             if(c->compare(this->getKey(i), k, _tree->getRecSize()))
  836.             {
  837.                 position = i + 1;
  838.                 break;
  839.             }
  840.         }
  841.  
  842.         PageWrapper child(_tree);
  843.         child.readPageFromChild(*this, position);
  844.         if(child.isFull())
  845.         {
  846.             this->splitChild(position);
  847.             if(!c->compare(k, this->getKey(position), _tree->getRecSize()))
  848.                 child.readPageFromChild(*this, position + 1);
  849.             else
  850.                 child.readPageFromChild(*this, position);
  851.         }
  852.         child.insertNonFull(k);
  853.     }
  854. }
  855.  
  856. void BaseBTree::insert(const Byte* k)
  857. {
  858.     PageWrapper root (this);
  859.     root.readPage(_rootPageNum);
  860.     bool check = root.isLeaf();
  861.     if(root.isFull())
  862.     {
  863.         PageWrapper newRoot(this);
  864.         newRoot.allocNewRootPage();
  865.         newRoot.setAsRoot(true);
  866.         bool isLeaf = root.isLeaf();
  867.         Byte* medianaValue = root.getKey(_order - 1);
  868.  
  869.         newRoot.setKeyNum(1);
  870.         newRoot.copyKey(newRoot.getKey(0), medianaValue);
  871.  
  872.         PageWrapper rightChild(this);
  873.         rightChild.allocPage(_order - 1, isLeaf);
  874.         newRoot.setCursor(1, rightChild.getPageNum());
  875.  
  876.         rightChild.copyKeys(rightChild.getKey(0), root.getKey(_order), _order - 1);
  877.         rightChild.copyCursors(rightChild.getCursorPtr(0), root.getCursorPtr(_order), _order);
  878.  
  879.         root.setKeyNum(_order - 1);
  880.  
  881.         rightChild.writePage();
  882.         root.writePage();
  883.         newRoot.setCursor(0, root.getPageNum());
  884.         newRoot.setLeaf(false);
  885.  
  886.         newRoot.writePage();
  887.  
  888.         newRoot.insertNonFull(k);
  889.     }
  890.     else
  891.         root.insertNonFull(k);
  892. }
  893.  
  894.  
  895.  
  896.  
  897.  
  898.  
  899. //==============================================================================
  900. // class FileBaseBTree
  901. //==============================================================================
  902.  
  903. FileBaseBTree::FileBaseBTree()
  904.     : BaseBTree(0, 0, nullptr, nullptr)
  905. {
  906. }
  907.  
  908.  
  909. FileBaseBTree::FileBaseBTree(UShort order, UShort recSize, IComparator* comparator,
  910.     const std::string& fileName)
  911.     : FileBaseBTree()
  912. {
  913.     _comparator = comparator;
  914.  
  915.     checkTreeParams(order, recSize);
  916.     createInternal(order, recSize, fileName);
  917. }
  918.  
  919.  
  920. FileBaseBTree::FileBaseBTree(const std::string& fileName, IComparator* comparator)
  921.     : FileBaseBTree()
  922. {
  923.     _comparator = comparator;
  924.     loadInternal(fileName); // , comparator);
  925. }
  926.  
  927. FileBaseBTree::~FileBaseBTree()
  928. {
  929.     close();            // именно для удобства такого использования не кидаем внутри искл. ситуацию!
  930. }
  931.  
  932.  
  933.  
  934. void FileBaseBTree::create(UShort order, UShort recSize, //IComparator* comparator,
  935.     const std::string& fileName)
  936. {
  937.     if (isOpen())
  938.         throw std::runtime_error("B-tree file is already open");
  939.  
  940.     checkTreeParams(order, recSize);
  941.     createInternal(order, recSize, fileName);
  942. }
  943.  
  944.  
  945. void FileBaseBTree::createInternal(UShort order, UShort recSize, // IComparator* comparator,
  946.     const std::string& fileName)
  947. {
  948.     _fileStream.open(fileName,
  949.         std::fstream::in | std::fstream::out |      // чтение запись
  950.         std::fstream::trunc |                       // обязательно грохнуть имеющееся (если вдруг) содержимое
  951.         std::fstream::binary);                      // бинарничек
  952.  
  953.     // если открыть не удалось
  954.     if (_fileStream.fail())
  955.     {
  956.         // пытаемся закрыть и уходим
  957.         _fileStream.close();
  958.         throw std::runtime_error("Can't open file for writing");
  959.     }
  960.  
  961.     // если же все ок, сохраняем параметры и двигаемся дальше
  962.     //_comparator = comparator;
  963.     _fileName = fileName;
  964.     _stream = &_fileStream;                         // привязываем к потоку
  965.  
  966.     createTree(order, recSize);                     // в базовом дереве
  967. }
  968.  
  969.  
  970. void FileBaseBTree::open(const std::string& fileName) //, IComparator* comparator)
  971. {
  972.     if (isOpen())
  973.         throw std::runtime_error("B-tree file is already open");
  974.  
  975.     loadInternal(fileName); // , comparator);
  976. }
  977.  
  978.  
  979. void FileBaseBTree::loadInternal(const std::string& fileName) // , IComparator* comparator)
  980. {
  981.     _fileStream.open(fileName,
  982.         std::fstream::in | std::fstream::out |      // чтение запись
  983.                                                     //  здесь не должно быть trunc, чтобы сущ. не убить
  984.         std::fstream::binary);                      // бинарничек
  985.  
  986.     // если открыть не удалось
  987.     if (_fileStream.fail())
  988.     {
  989.         // пытаемся закрыть и уходим
  990.         _fileStream.close();
  991.         throw std::runtime_error("Can't open file for reading");
  992.     }
  993.  
  994.     // если же все ок, сохраняем параметры и двигаемся дальше
  995.     //_comparator = comparator;
  996.     _fileName = fileName;
  997.     _stream = &_fileStream;         // привязываем к потоку
  998.  
  999.  
  1000.     try {
  1001.         loadTree();
  1002.     }
  1003.     catch (std::exception& e)
  1004.     {
  1005.         _fileStream.close();
  1006.         throw e;
  1007.     }
  1008.     catch (...)                     // для левых исключений
  1009.     {
  1010.         _fileStream.close();
  1011.         throw std::runtime_error("Error when loading btree");
  1012.     }
  1013. }
  1014.  
  1015.  
  1016. void FileBaseBTree::close()
  1017. {
  1018.     if (!isOpen())
  1019.         return;
  1020.  
  1021.     closeInternal();
  1022. }
  1023.  
  1024.  
  1025. void FileBaseBTree::closeInternal()
  1026. {
  1027.     // NOTE: возможно, перед закрытием надо что-то записать в файл? — иметь в виду!
  1028.     _fileStream.close();
  1029.  
  1030.     // переводим объект в состояние сконструированного БЕЗ параметров
  1031.     resetBTree();
  1032. }
  1033.  
  1034. void FileBaseBTree::checkTreeParams(UShort order, UShort recSize)
  1035. {
  1036.     if (order < 1 || recSize == 0)
  1037.         throw std::invalid_argument("B-tree order can't be less than 1 and record siaze can't be 0");
  1038.  
  1039. }
  1040.  
  1041. bool FileBaseBTree::isOpen() const
  1042. {
  1043.     return (_fileStream.is_open()); // && _fileStream.good());
  1044. }
  1045.  
  1046.  
  1047.  
  1048.  
  1049. } // namespace xi
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement