docs: protected void cleanupLocks( Set<String> activeSessionIds ) throws TimeoutException {
          try {
              ExecutionContext context = repository.context();
  
              DateTimeFactory dates = context.getValueFactories().getDateFactory();
              DateTime now = dates.create();
              DateTime newExpiration = dates.create(now, this.lockExtensionIntervalMillis);
  
              PropertyFactory propertyFactory = context.getPropertyFactory();
              SessionCache systemSession = repository.createSystemSession(context, false);
              SystemContent systemContent = new SystemContent(systemSession);
  
              Map<String, List<NodeKey>> lockedNodesByWorkspaceName = new HashMap<>();
              // Iterate over the locks ...
              CachedNode locksNode = systemContent.locksNode();
              ChildReferences childReferences = locksNode.getChildReferences(systemSession);
              if (childReferences.isEmpty()) {
                  // there are no locks, so nothing to do
                  return;
              }
              for (ChildReference ref : childReferences) {
                  NodeKey lockKey = ref.getKey();
                  CachedNode lockNode = systemSession.getNode(lockKey);
                  if (lockNode == null) {
                      //it may happen that another thread has performed a session.logout which means the lock might have been removed
                      continue;
                  }
                  ModeShapeLock lock = new ModeShapeLock(lockNode, systemSession);
                  NodeKey lockedNodeKey = lock.getLockedNodeKey();
                  if (lock.isSessionScoped() && activeSessionIds.contains(lock.getLockingSessionId())) {
                      //for active session locks belonging to the sessions of this process, we want to extend the expiration date
                      //so that other processes in a cluster can tell that this lock is still active
                      MutableCachedNode mutableLockNode = systemSession.mutable(lockKey);
                      Property prop = propertyFactory.create(ModeShapeLexicon.EXPIRATION_DATE, newExpiration);
                      mutableLockNode.setProperty(systemSession, prop);
                      //reflect the change in the expiry date in the internal map
                      this.locksByNodeKey.replace(lockedNodeKey, lock.withExpiryTime(newExpiration));
  
                      continue;
                  }
  
                  //if it's not an active session lock, we always check the expiry date
                  DateTime expirationDate = firstDate(lockNode.getProperty(ModeShapeLexicon.EXPIRATION_DATE, systemSession));
                  if (expirationDate.isBefore(now)) {
                      //remove the lock from the system area
                      systemContent.removeLock(lock);
                      //register the target node which needs cleaning
                      List<NodeKey> lockedNodes = lockedNodesByWorkspaceName.get(lock.getWorkspaceName());
                      if (lockedNodes == null) {
                          lockedNodes = new ArrayList<>();
                          lockedNodesByWorkspaceName.put(lock.getWorkspaceName(), lockedNodes);
                      }
                      lockedNodes.add(lockedNodeKey);
                  }
              }
              //persist all the changes to the locks from the system area
              systemSession.save();
  
              if (!lockedNodesByWorkspaceName.isEmpty()) {
                  //update each of nodes which has been unlocked
                  for (String workspaceName : lockedNodesByWorkspaceName.keySet()) {
                      SessionCache internalSession = repository.repositoryCache().createSession(context, workspaceName, false);
                      for (NodeKey lockedNodeKey : lockedNodesByWorkspaceName.get(workspaceName)) {
                          //clear the internal cache
                          this.locksByNodeKey.remove(lockedNodeKey);
  
                          CachedNode lockedNode = internalSession.getWorkspace().getNode(lockedNodeKey);
                          if (lockedNode != null) {
                              MutableCachedNode mutableLockedNode = internalSession.mutable(lockedNodeKey);
                              mutableLockedNode.removeProperty(internalSession, JcrLexicon.LOCK_IS_DEEP);
                              mutableLockedNode.removeProperty(internalSession, JcrLexicon.LOCK_OWNER);
                              mutableLockedNode.unlock();
                          }
                      }
                      internalSession.save();
                  }
              }
          } catch (TimeoutException te) {
              // there was a timeout while locking on some nodes (most likely mode:locks) so we should re-throw this to callers
              // so they can react
              throw te;
          } catch (Throwable t) {
              logger.error(t, JcrI18n.errorCleaningUpLocks, repository.name());
          }
      }