private ISchemaPage validatePage(ISchemaPage initPage, ICachedMNode parent, SchemaPageContext cxt)
      throws IOException, MetadataException {
    boolean safeFlag = false;
    // check like crabbing
    ISchemaPage crabPage;
    SchemaPageContext doubleCheckContext;
    while (getPageIndex(getNodeAddress(parent)) != initPage.getPageIndex()) {
      // transplanted, release the stale and obtain/lock the new
      doubleCheckContext = new SchemaPageContext();
      long addrB4Lock = getNodeAddress(parent);
      int piB4Lock = getPageIndex(addrB4Lock);

      initPage.decrementAndGetRefCnt();
      initPage.getLock().readLock().unlock();

      crabPage = getPageInstance(piB4Lock, doubleCheckContext);
      crabPage.getLock().readLock().lock();

      // UNNECESSARY to TRACE lock since the very page will be unlocked at end of read
      cxt.referredPages.remove(initPage.getPageIndex());
      cxt.referredPages.put(crabPage.getPageIndex(), crabPage);
      initPage = crabPage;
    }

    // a fresh context to read-through from global cache
    doubleCheckContext = new SchemaPageContext();
    crabPage = getPageInstance(initPage.getPageIndex(), doubleCheckContext);
    if (crabPage != initPage) {
      // replaced, the lock and ref count should be the same
      if (crabPage.getLock() != initPage.getLock()
          || crabPage.getRefCnt() != initPage.getRefCnt()) {
        crabPage.decrementAndGetRefCnt();
        initPage.decrementAndGetRefCnt();
        initPage.getLock().readLock().unlock();
        throw new MetadataException(
            "Page[%d] replacement error: Different ref count or lock object.");
      }
      // update context is enough, ref and lock is left for main read process
      cxt.referredPages.put(initPage.getPageIndex(), crabPage);
      initPage = crabPage;
    }
    // same page shall only be referred once
    crabPage.decrementAndGetRefCnt();
    return initPage;
  }
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