private static PersistenceManagerFactory initPMF(Configuration conf, boolean forCompactor) {
    DataSourceProvider dsp = DataSourceProviderFactory.tryGetDataSourceProviderOrNull(conf);
    PersistenceManagerFactory pmf = null;

    // Any preexisting datanucleus property should be passed along
    Map<Object, Object> dsProp = new HashMap<>(prop);
    int maxPoolSize = -1;
    
    if (forCompactor) {
      maxPoolSize = MetastoreConf.getIntVar(conf, ConfVars.HIVE_COMPACTOR_CONNECTION_POOLING_MAX_CONNECTIONS);
      dsProp.put(ConfVars.CONNECTION_POOLING_MAX_CONNECTIONS.getVarname(), maxPoolSize);
    }
    if (dsp == null) {
      pmf = JDOHelper.getPersistenceManagerFactory(dsProp);
    } else {
      DataSource ds = null;
      DataSource ds2 = null;
      String sourceName = forCompactor ? "objectstore-compactor" : "objectstore";
      try (DataSourceProvider.DataSourceNameConfigurator configurator =
               new DataSourceProvider.DataSourceNameConfigurator(conf, sourceName)) {
        ds = (maxPoolSize > 0) ? dsp.create(conf, maxPoolSize) : dsp.create(conf);
        databaseProduct = DatabaseProduct.determineDatabaseProduct(ds, conf);
        // The secondary connection factory is used for schema generation, and for value generation operations.
        // We use a different pool for the secondary connection factory to avoid resource starvation.
        // DataNucleus uses locks for schema generation and value generation, under normal circumstances 2 connections
        // should be sufficient.
        configurator.resetName(sourceName + "-secondary");
        int maxSecondaryPoolSize = Math.max(2, MetastoreConf.getIntVar(conf, ConfVars.CONNECTION_POOLING_MAX_SECONDARY_CONNECTIONS));
        ds2 = dsp.create(conf, maxSecondaryPoolSize);
        dsProp.put(PropertyNames.PROPERTY_CONNECTION_FACTORY, ds);
        dsProp.put(PropertyNames.PROPERTY_CONNECTION_FACTORY2, ds2);
        dsProp.put(ConfVars.MANAGER_FACTORY_CLASS.getVarname(),
            "org.datanucleus.api.jdo.JDOPersistenceManagerFactory");
        pmf = JDOHelper.getPersistenceManagerFactory(dsProp);
      } catch (SQLException e) {
        LOG.warn("Could not create PersistenceManagerFactory using "
            + "connection pool properties, will fall back", e);
        pmf = JDOHelper.getPersistenceManagerFactory(prop);
      } finally {
        if (pmf == null && ds instanceof AutoCloseable) {
          try (AutoCloseable close1 = (AutoCloseable) ds;
               AutoCloseable close2 = (AutoCloseable) ds2 ) {
            LOG.debug("Trying to close the dangling datasource as the pmf is null");
          } catch (Exception e) {
            LOG.warn("Failed to close the DataSource", e);
          }
        }
      }
    }
    assert pmf != null;
    DataStoreCache dsc = pmf.getDataStoreCache();
    if (dsc != null) {
      String objTypes = MetastoreConf.getVar(conf, ConfVars.CACHE_PINOBJTYPES);
      LOG.info(
          "Setting MetaStore object pin classes with hive.metastore.cache.pinobjtypes=\"{}\"",
          objTypes);
      if (org.apache.commons.lang3.StringUtils.isNotEmpty(objTypes)) {
        String[] typeTokens = objTypes.toLowerCase().split(",");
        for (String type : typeTokens) {
          type = type.trim();
          if (PINCLASSMAP.containsKey(type)) {
            dsc.pinAll(true, PINCLASSMAP.get(type));
          } else {
            LOG.warn("{} is not one of the pinnable object types: {}", type,
                org.apache.commons.lang3.StringUtils.join(PINCLASSMAP.keySet(), " "));
          }
        }
      }
    } else {
      LOG.warn("PersistenceManagerFactory returned null DataStoreCache object. "
          + "Unable to initialize object pin types defined by hive.metastore.cache.pinobjtypes");
    }
    return pmf;
  }
This method updates the PersistenceManagerFactory and its properties if the given
configuration is different from its current set of properties. Most common case is that
the persistenceManagerFactory properties do not change, and hence this method is optimized to
be non-blocking in such cases. However, if the properties are different, this method blocks
other threads until the properties are updated, current pmf is closed and
a new pmf is re-initialized. Note that when a PersistenceManagerFactory is re-initialized all
the PersistenceManagers which are instantiated using old factory become invalid and will throw
JDOUserException. Hence it is recommended that this method is called in the setup/init phase
of the Metastore service when there are no other active threads serving clients.

@param conf Configuration which provides the datanucleus/datasource properties for comparison
standalone-metastore/metastore-server/src/main/java/org/apache/hadoop/hive/metastore/PersistenceManagerProvider.java