docs: @FFDCIgnore(NoSuchElementException.class)
      private void doInvalidations() {
          final boolean trace = TraceComponent.isAnyTracingEnabled();
  
          try {
              long now = System.currentTimeMillis();
  
              // loop through all the candidates eligible for invalidation
              BackedSession pmiStatSession = null; // fake session for pmi stats
              SessionStatistics pmiStats = null;
  
              if (trace && tc.isDebugEnabled())
                  tcInvoke(tcSessionMetaCache, "iterator");
  
              @SuppressWarnings("rawtypes")
              Iterator<Cache.Entry<String, ArrayList>> it = sessionMetaCache.iterator();
  
              if (trace && tc.isDebugEnabled())
                  tcReturn(tcSessionMetaCache, "iterator", it);
  
              while (it.hasNext()) {
                  if (trace && tc.isDebugEnabled())
                      tcInvoke(tcSessionMetaCache, "_iterator.next");
  
                  @SuppressWarnings("rawtypes")
                  Cache.Entry<String, ArrayList> entry;
                  try {
                      entry = it.next();
                  } catch (NoSuchElementException x) {
                      // ignore - some JCache providers might raise this instead of returning null when modified during iterator
                      entry = null;
                  }
                  String id = entry == null ? null : entry.getKey();
                  ArrayList<?> value = id == null ? null : entry.getValue();
  
                  if (trace && tc.isDebugEnabled())
                      tcReturn(tcSessionMetaCache, "_iterator.next", id, value);
  
                  if (id != null && !INVAL_KEY.equals(id)) {
                      SessionInfo sessionInfo = new SessionInfo(value);
                      long lastAccessTime = sessionInfo.getLastAccess();
                      short listenerTypes = sessionInfo.getListenerTypes();
                      int maxInactiveTime = sessionInfo.getMaxInactiveTime();
                      if ((listenerTypes & BackedSession.HTTP_SESSION_BINDING_LISTENER) == 0 // sessions that do NOT have binding listeners
                                      && maxInactiveTime >= 0
                                      && maxInactiveTime < (now - lastAccessTime) / 1000) {
                          if (now + _smc.getInvalidationCheckInterval() * 1000 <= System.currentTimeMillis()) {
                              // If the scan is taking more than pollInterval, just break and
                              // invalidate the sessions so far determined
                              break;
                          }
  
                          if (trace && tc.isDebugEnabled())
                              tcInvoke(tcSessionMetaCache, "remove", id, value);
  
                          boolean removed = sessionMetaCache.remove(id, value);
  
                          if (trace && tc.isDebugEnabled())
                              tcReturn(tcSessionMetaCache, "remove", removed);
  
                          if (removed) {
                              //delete sub rows
                              Set<String> propIds = sessionInfo.getSessionPropertyIds();
                              if (propIds != null && !propIds.isEmpty()) {
                                  HashSet<String> propKeys = new HashSet<String>();
                                  for (String propId : propIds)
                                      propKeys.add(createSessionAttributeKey(id, propId));
  
                                  if (trace && tc.isDebugEnabled())
                                      tcInvoke(tcSessionAttrCache, "removeAll", propKeys);
  
                                  sessionAttributeCache.removeAll(propKeys);
  
                                  if (trace && tc.isDebugEnabled())
                                      tcReturn(tcSessionAttrCache, "removeAll");
                              }
                          }
  
                          /*
                           * We already did cleanUpCache during the invalidation processing. Therefore, the session is no longer
                           * in our cache, and superRemove should return null. We need to create a temporary Session with an
                           * accurate Id and creationTime to send to the PMI counters.
                           */
                          superRemove(id);
                          long createTime = sessionInfo.getCreationTime();
                          //we don't want to retrieve session, so use a fake one for pmi
                          if (pmiStatSession == null)
                              pmiStatSession = new CacheSession();
                          if (pmiStats == null)
                              pmiStats = _iStore.getSessionStatistics();
                          pmiStatSession.setId(id);
                          pmiStatSession.setCreationTime(createTime);
                          if (pmiStats != null) {
                              pmiStats.sessionDestroyed(pmiStatSession);
                              pmiStats.sessionDestroyedByTimeout(pmiStatSession);
                          }
                      }
                  }
              }
          } catch (Exception x) {
              // auto FFDC
              Tr.error(tc, "ERROR_SESSION_INVAL", x);
          }
      }