code: public void applicationRemoved(String appId, boolean cleanupLocalDirs) {
      logger.info("Application {} removed, cleanupLocalDirs = {}", appId, cleanupLocalDirs);
      Iterator<Map.Entry<AppExecId, ExecutorShuffleInfo>> it = executors.entrySet().iterator();
      while (it.hasNext()) {
        Map.Entry<AppExecId, ExecutorShuffleInfo> entry = it.next();
        AppExecId fullId = entry.getKey();
        final ExecutorShuffleInfo executor = entry.getValue();
  
        // Only touch executors associated with the appId that was removed.
        if (appId.equals(fullId.appId)) {
          it.remove();
          if (db != null) {
            try {
              db.delete(dbAppExecKey(fullId));
            } catch (IOException e) {
              logger.error("Error deleting {} from executor state db", appId, e);
            }
          }
  
          if (cleanupLocalDirs) {
            logger.info("Cleaning up executor {}'s {} local dirs", fullId, executor.localDirs.length);
  
            // Execute the actual deletion in a different thread, as it may take some time.
            directoryCleaner.execute(() -> deleteExecutorDirs(executor.localDirs));
          }
        }
      }
    }
docs: Removes our metadata of all executors registered for the given application, and optionally
  also deletes the local directories associated with the executors of that application in a
  separate thread.
  
  It is not valid to call registerExecutor() for an executor with this appId after invoking
  this method.