@Override
  public Session createSession(
      final HttpServerExchange serverExchange, final SessionConfig config) {
    if (evictionQueue != null) {
      if (expireOldestUnusedSessionOnMax) {
        while (sessions.size() >= maxSize && !evictionQueue.isEmpty()) {

          String key = evictionQueue.poll();
          UndertowLogger.REQUEST_LOGGER.debugf("Removing session %s as max size has been hit", key);
          SessionImpl toRemove = sessions.get(key);
          if (toRemove != null) {
            toRemove.invalidate(
                null, SessionListener.SessionDestroyedReason.TIMEOUT); // todo: better reason
          }
        }
      } else if (sessions.size() >= maxSize) {
        if (statisticsEnabled) {
          rejectedSessionCount.incrementAndGet();
        }
        throw UndertowMessages.MESSAGES.tooManySessions(maxSize);
      }
    }
    if (config == null) {
      throw UndertowMessages.MESSAGES.couldNotFindSessionCookieConfig();
    }
    String sessionID = config.findSessionId(serverExchange);
    int count = 0;
    while (sessionID == null) {
      sessionID = sessionIdGenerator.createSessionId();
      if (sessions.containsKey(sessionID)) {
        sessionID = null;
      }
      if (count++ == 100) {
        // this should never happen
        // but we guard against pathalogical session id generators to prevent an infinite loop
        throw UndertowMessages.MESSAGES.couldNotGenerateUniqueSessionId();
      }
    }
    Object evictionToken;
    if (evictionQueue != null) {
      evictionToken = evictionQueue.offerLastAndReturnToken(sessionID);
    } else {
      evictionToken = null;
    }
    if (statisticsEnabled) {
      createdSessionCount.incrementAndGet();
    }
    final SessionImpl session =
        new SessionImpl(
            this,
            sessionID,
            config,
            serverExchange.getIoThread(),
            serverExchange.getConnection().getWorker(),
            evictionToken,
            defaultSessionTimeout);
    sessions.put(sessionID, session);
    config.setSessionId(serverExchange, session.getId());
    session.lastAccessed = System.currentTimeMillis();
    session.bumpTimeout();
    sessionListeners.sessionCreated(session, serverExchange);
    serverExchange.putAttachment(NEW_SESSION, session);
    return session;
  }