Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /** \brief Для не полностью заполненного текущего узла разделяет напополам его
- * полностью заполненного ребенка, определяемого курсором номер \c iChild на два нода/страницы.
- *
- * Параметр \c iChild представляет индекс курсора, который не может быть 0, что означает
- * нарушение целостности (нет страницы с таким ребенком).
- * Т.к. в процессе сплита один из ключей ребенка уйдет в этот родительский нод,
- * данный нод должен иметь хотя бы один свободный слот под этот ключ. Если это не так,
- * полетит исключительная ситуация.
- * Для того, чтобы не было неопределенности по поводу индексов, заполненности и проч.
- * в соответствующем ребенке, подразумеваем, что он полностью заполнен. Если это не так,
- * кидаем искл. ситуацию.
- */
- void BaseBTree::PageWrapper::splitChild(UShort iChild)
- {
- if (isFull())
- throw std::domain_error("A parent node is full, so its child can't be splitted");
- if (iChild > getKeysNum())
- throw std::invalid_argument("Cursor not exists");
- // Ребенок, которого мы будем сплитить - полностью заполнен
- PageWrapper* currentChild = new PageWrapper(_tree);
- currentChild->readPageFromChild(*this, iChild);
- // Позиция центрального элемента
- UShort midPos = currentChild->getKeysNum() / 2;
- Byte* midKey = currentChild->getKey(midPos);
- // Новый ребенок идущий от текущей вершины
- PageWrapper* newAddedChild = new PageWrapper(_tree);
- newAddedChild->allocPage(currentChild->getKeysNum() - iChild, true);
- UShort j = 0;
- // Копируем в newAddedChild ключи начиная после центрального элемента из currentChild
- for(UShort i = midPos + 1; i < currentChild->getKeysNum(); i++)
- {
- newAddedChild->copyKey(newAddedChild->getKey(j), currentChild->getKey(i));
- j++;
- }
- // Добавляем центральный ключ в текущую вершину
- insertNonFull(currentChild->getKey(midPos));
- // Уменьшаем количество ключей в currentChild: теперь значащие ключи лежат ДО mid pos
- currentChild->setKeyNum(midPos);
- // Теперь надо найти позицию куда ключ был вставлен в текущей вершине
- // и установить курсор справа от этой позиции на newAddedChild
- UShort pos;
- for(pos = 0; pos < getKeysNum(); pos++)
- {
- // Если ключ равен вставленому, то позиция найдена
- if(_tree->_comparator->isEqual(getKey(pos), midKey, _tree->getRecSize()))
- break;
- }
- // Позиция была найдена
- if(pos < getKeysNum())
- {
- // Устанавливаем значение правого курсора вставленной вершины на newAddedChild
- setCursor(pos + 1, newAddedChild->getPageNum());
- }
- writePage();
- currentChild->writePage();
- newAddedChild->writePage();
- }
- /** \brief Вставляет в не полностью заполненный узел ключ k с учетом порядка.
- *
- * Если узел полный, кидает исключение.
- * Если для дерева не задан компаратор, кидает исключение.
- */
- void BaseBTree::PageWrapper::insertNonFull(const Byte* toInsert)
- {
- if (isFull())
- throw std::domain_error("Node is full. Can't insert");
- IComparator* c = _tree->getComparator();
- if (!c)
- throw std::runtime_error("Comparator not set. Can't insert");
- UShort amount_Of_Keys = getKeysNum();
- UShort pos = 0;
- UShort recordSize = _tree->getRecSize();
- Byte* key = getKey(pos);
- // Пока ключ не null и меньше чем то что нужно вставить
- while (key && c->compare(key,toInsert,recordSize))
- {
- // Встретили пустое значение
- if((pos > 0 && *(getKey(pos - 1)) != 0 && *(getKey(pos)) == 0))
- break;
- pos++;
- key = getKey(pos);
- }
- // Если последний ключ уже занят, то увеличиваем кол-во ключей
- if(*(getKey(amount_Of_Keys - 1)) != 0)
- setKeyNum(amount_Of_Keys + 1);
- // Перемещаем ключи начиная с pos на одну ячейку вперед
- UShort lastElPos = getKeysNum() - 1;
- if(lastElPos > pos)
- // Перемещаем курсоры начиная с pos на одну ячейку вперед
- copyCursors(getCursorPtr(pos + 1), getCursorPtr(pos), CURSOR_SZ);
- // Добавленный курсор(справа) от вставленной вершины обозначим как 0 для наглядности
- setCursor(pos + 1, 0);
- while(lastElPos > pos)
- {
- copyKey(getKey(lastElPos), getKey(lastElPos - 1));
- lastElPos--;
- }
- // В освобожденную ячейку помещаем значение, которое хотели вставить
- *(getKey(pos)) = *toInsert;
- writePage();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement