code: private void processModifiedPages(UpdateablePageCollection pageCollection) {
          val currentBatch = new ArrayList<PageWrapper>();
          pageCollection.collectLeafPages(currentBatch);
          while (!currentBatch.isEmpty()) {
              val parents = new HashSet<Long>();
              for (PageWrapper p : currentBatch) {
                  val context = new PageModificationContext(p, pageCollection);
                  if (p.needsFirstKeyUpdate()) {
                      updateFirstKey(context);
                  }
  
                  val splitResult = p.getPage().splitIfNecessary();
                  if (splitResult != null) {
                      processSplitPage(splitResult, context);
                  } else {
                      processModifiedPage(context);
                  }
  
                  // Make sure we process its parent as well.
                  PageWrapper parentPage = p.getParent();
                  if (parentPage == null && splitResult != null) {
                      // There was a split. Make sure that if this was the root, we create a new root to act as parent.
                      parentPage = PageWrapper.wrapNew(createEmptyIndexPage(), null, null);
                      pageCollection.insert(parentPage);
                  }
  
                  if (parentPage != null) {
                      // Update the parent page with new or deleted Page Pointers.
                      processParentPage(parentPage, context);
  
                      // Queue up the parent for processing.
                      parents.add(parentPage.getOffset());
                  }
              }
  
              // We are done with this level. Move up one process the pages at that level.
              currentBatch.clear();
              pageCollection.collectPages(parents, currentBatch);
          }
      }
docs: Processes all the pages in the given PageCollection, beginning with the Leaf Pages (in order of offsets), then
  moving on to their direct parents (in order of offsets), and so on until all pages in the Page Collection have
  been processed.
  <p>
  When this method completes:
  - All pages will have new offsets assigned (since they have all been touched).
  - Any overflowing pages will be split into two or more pages (and their parents updated appropriately).
  - Any empty pages will be removed (and their parents updated appropriately).
  - All non-leaf pages will be updated to point to the same leaf pages, but with new offsets.
  - A new root (index) page may be created.
  
  @param pageCollection An UpdateablePageCollection containing pages to be processed.