@Override
  public Iterator<ICachedMNode> getChildren(ICachedMNode parent)
      throws MetadataException, IOException {
    SchemaPageContext cxt = new SchemaPageContext();
    int pageIdx = getPageIndex(getNodeAddress(parent));

    short segId = getSegIndex(getNodeAddress(parent));
    ISchemaPage page = getPageInstance(pageIdx, cxt), pageHeldLock;
    page.getLock().readLock().lock();
    page = validatePage(page, parent, cxt);
    pageHeldLock = page;

    try {
      while (page.getAsSegmentedPage() == null) {
        page = getPageInstance(getPageIndex(page.getAsInternalPage().getNextSegAddress()), cxt);
      }

      long actualSegAddr = page.getAsSegmentedPage().getNextSegAddress(segId);
      Queue<ICachedMNode> initChildren = page.getAsSegmentedPage().getChildren(segId);

      return new Iterator<ICachedMNode>() {
        long nextSeg = actualSegAddr;
        Queue<ICachedMNode> children = initChildren;

        @Override
        public boolean hasNext() {
          if (!children.isEmpty()) {
            return true;
          }
          if (nextSeg < 0) {
            return false;
          }

          try {
            ISchemaPage nPage;
            while (children.isEmpty() && nextSeg >= 0) {
              boolean hasThisPage = cxt.referredPages.containsKey(getPageIndex(nextSeg));
              nPage = getPageInstance(getPageIndex(nextSeg), cxt);
              children = nPage.getAsSegmentedPage().getChildren(getSegIndex(nextSeg));
              nextSeg = nPage.getAsSegmentedPage().getNextSegAddress(getSegIndex(nextSeg));
              // children iteration need not pin page, consistency is guaranteed by upper layer
              if (!hasThisPage) {
                cxt.referredPages.remove(nPage.getPageIndex());
                nPage.decrementAndGetRefCnt();
              }
            }
          } catch (MetadataException | IOException e) {
            logger.error(e.getMessage());
            return false;
          }

          return !children.isEmpty();
        }

        @Override
        public ICachedMNode next() {
          return children.poll();
        }
      };
    } finally {
      // safety of iterator should be guaranteed by upper layer
      pageHeldLock.getLock().readLock().unlock();
      pagePool.releaseReferent(cxt);
    }
  }
Since transplant and replacement may invalidate page instance held by a blocked read-thread,
the read-thread need to validate its page object once it obtained the lock.

@param initPage page instance with read lock held
@param parent MTree node to read children, containing latest segment address
@param cxt update context if page/segment modified
@return validated page
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/schemafile/pagemgr/BTreePageManager.java