code: ReleaseResult change(SemaphoreEndpoint endpoint, UUID invocationUid, int permits) {
          if (permits == 0) {
              return ReleaseResult.failed(Collections.<AcquireInvocationKey>emptyList());
          }
  
          Collection<AcquireInvocationKey> cancelled = cancelWaitKeys(endpoint, invocationUid);
  
          long sessionId = endpoint.sessionId();
          if (sessionId != NO_SESSION_ID) {
              SessionSemaphoreState state = sessionStates.get(sessionId);
              if (state == null) {
                  state = new SessionSemaphoreState();
                  sessionStates.put(sessionId, state);
              }
  
              long threadId = endpoint.threadId();
              if (state.containsInvocation(threadId, invocationUid)) {
                  Collection<AcquireInvocationKey> c = Collections.emptyList();
                  return ReleaseResult.successful(c, c);
              }
  
              state.invocationRefUids.put(threadId, Tuple2.of(invocationUid, permits));
          }
  
          available += permits;
          initialized = true;
  
          Collection<AcquireInvocationKey> acquired =
                  permits > 0 ? assignPermitsToWaitKeys() : Collections.<AcquireInvocationKey>emptyList();
  
          return ReleaseResult.successful(acquired, cancelled);
      }
docs: Changes the number of permits by adding the given permit value. Permits
  are not changed if it is a retry of a previous successful change request
  of a session-aware proxy. Permits are changed again if it is a retry of
  a successful change request of a sessionless proxy. If number of permits
  increase, new assignments can be done. Returns completed wait keys after
  successful change if there are any. Returns cancelled wait keys of
  the same endpoint if there are any.