public static void updatePmfProperties(Configuration conf) {
    // take a read lock to check if the datasource properties changed.
    // Most common case is that datasource properties do not change
    boolean useCompactorPool = MetastoreConf.getBoolVar(conf, COMPACTOR_USE_CUSTOM_POOL);
    Properties propsFromConf = PersistenceManagerProvider.getDataSourceProps(conf);
    pmfReadLock.lock();
    // keep track of if the read-lock is acquired by this thread
    // so that we can unlock it before leaving this method
    // this is needed because pmf methods below could throw JDOException (unchecked exception)
    // which can lead to readLock not being acquired at the end of the inner try-finally
    // block below
    boolean readLockAcquired = true;
    try {
      // if pmf properties change, need to update, release read lock and take write lock
      if (pmf == null || (compactorPmf == null && useCompactorPool) || !propsFromConf.equals(prop)) {
        pmfReadLock.unlock();
        readLockAcquired = false;
        pmfWriteLock.lock();
        try {
          // check if we need to update pmf again here in case some other thread already did it
          // for us after releasing readlock and before acquiring write lock above
          boolean propChanged = !propsFromConf.equals(prop);
          if (pmf == null || (compactorPmf == null && useCompactorPool)  || propChanged) {
            logPropChanges(propsFromConf);
            // OK, now we really need to re-initialize pmf and pmf properties
            closePmfIfNeeded(true, propChanged);
            closePmfIfNeeded(false, propChanged);
            // update the pmf properties object then initialize pmf using them
            prop = propsFromConf;
            retryLimit = MetastoreConf.getIntVar(conf, ConfVars.HMS_HANDLER_ATTEMPTS);
            retryInterval = MetastoreConf
                .getTimeVar(conf, ConfVars.HMS_HANDLER_INTERVAL, TimeUnit.MILLISECONDS);
            // init PMF with retry logic
            if (pmf == null) {
              pmf = retry(() -> initPMF(conf, false));
            }
            if (compactorPmf == null && useCompactorPool) {
              compactorPmf = retry(() -> initPMF(conf, true));
            }
            if (databaseProduct == null) {
              String url = MetastoreConf.getVar(conf, MetastoreConf.ConfVars.CONNECT_URL_KEY);
              databaseProduct = DatabaseProduct.determineDatabaseProduct(url, conf);
            }
          }
          // downgrade by acquiring read lock before releasing write lock
          pmfReadLock.lock();
          readLockAcquired = true;
        } finally {
          pmfWriteLock.unlock();
        }
      }
    } finally {
      if (readLockAcquired) {
        pmfReadLock.unlock();
      }
    }
  }
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