smolnar82 commented on a change in pull request #337:
URL: https://github.com/apache/knox/pull/337#discussion_r433675431



##########
File path: 
gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
##########
@@ -319,16 +366,17 @@ protected void evictExpiredTokens() {
    */
   protected boolean needsEviction(final String tokenId) throws 
UnknownTokenException {
     // If the expiration time(+ grace period) has already passed, it should be 
considered expired
-    long expirationWithGrace = getTokenExpiration(tokenId) + 
TimeUnit.SECONDS.toMillis(tokenEvictionGracePeriod);
+    long expirationWithGrace = getTokenExpiration(tokenId, false) + 
TimeUnit.SECONDS.toMillis(tokenEvictionGracePeriod);
     return (expirationWithGrace <= System.currentTimeMillis());
   }
 
   /**
    * Get a list of tokens
    *
-   * @return List of tokens
+   * @return
    */
   protected List<String> getTokens() {
-    return new ArrayList<>(tokenExpirations.keySet());
+    return tokenExpirations.keySet().stream().collect(Collectors.toList());

Review comment:
       Should not we synchronize here too?

##########
File path: 
gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
##########
@@ -237,12 +249,37 @@ protected boolean isUnknown(final String token) {
 
   protected void updateExpiration(final String tokenId, long expiration) {
     synchronized (tokenExpirations) {
-      tokenExpirations.replace(tokenId, expiration);
+      if (tokenExpirations.containsKey(tokenId)) {
+        tokenExpirations.replace(tokenId, expiration);
+      } else {
+        tokenExpirations.put(tokenId, expiration);
+      }

Review comment:
       `Map.replace` also runs a `containsKey`:
   ```
   The default implementation is equivalent to, for this map:
    
    if (map.containsKey(key)) {
        return map.put(key, value);
    } else
        return null;
   ```
   I think a simple `put` is enough: you want to make sure you have the given 
expiration in `tokenExpirations`

##########
File path: 
gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/AliasBasedTokenStateService.java
##########
@@ -109,30 +133,52 @@ public long getTokenExpiration(final String tokenId) 
throws UnknownTokenExceptio
 
   @Override
   protected boolean isUnknown(final String tokenId) {
-    boolean isUnknown = false;
-    try {
-      isUnknown = 
(aliasService.getPasswordFromAliasForCluster(AliasService.NO_CLUSTER_NAME, 
tokenId) == null);
-    } catch (AliasServiceException e) {
-      log.errorAccessingTokenState(tokenId, e);
+    boolean isUnknown = super.isUnknown(tokenId);
+
+    // If it's not in the cache, then check the underlying alias
+    if (isUnknown) {
+      try {
+        isUnknown = 
(aliasService.getPasswordFromAliasForCluster(AliasService.NO_CLUSTER_NAME, 
tokenId) == null);
+      } catch (AliasServiceException e) {
+        log.errorAccessingTokenState(tokenId, e);
+      }
     }
     return isUnknown;
   }
 
   @Override
   protected void removeToken(final String tokenId) throws 
UnknownTokenException {
-    validateToken(tokenId);
-
     try {
       aliasService.removeAliasForCluster(AliasService.NO_CLUSTER_NAME, 
tokenId);
       aliasService.removeAliasForCluster(AliasService.NO_CLUSTER_NAME, tokenId 
+ TOKEN_MAX_LIFETIME_POSTFIX);
       log.removedTokenState(tokenId);
     } catch (AliasServiceException e) {
       log.failedToRemoveTokenState(tokenId, e);
     }
+    super.removeToken(tokenId);
+  }

Review comment:
       Why not invoke the new method as 
`removeTokens(Collections.singleton(tokenId))`?

##########
File path: 
gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
##########
@@ -254,7 +291,7 @@ protected void removeToken(final String tokenId) throws 
UnknownTokenException {
 
   protected boolean hasRemainingRenewals(final String tokenId, long 
renewInterval) {
     // Is the current time + 30-second buffer + the renewal interval is less 
than the max lifetime for the token?
-    return ((System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30) + 
renewInterval) < getMaxLifetime(tokenId));
+    return ((System.currentTimeMillis() + 30000 + renewInterval) < 
getMaxLifetime(tokenId));

Review comment:
       Why is this 30 seconds buffer added?

##########
File path: 
gateway-server/src/main/java/org/apache/knox/gateway/services/token/impl/DefaultTokenStateService.java
##########
@@ -237,12 +249,37 @@ protected boolean isUnknown(final String token) {
 
   protected void updateExpiration(final String tokenId, long expiration) {
     synchronized (tokenExpirations) {
-      tokenExpirations.replace(tokenId, expiration);
+      if (tokenExpirations.containsKey(tokenId)) {
+        tokenExpirations.replace(tokenId, expiration);
+      } else {
+        tokenExpirations.put(tokenId, expiration);
+      }
     }
   }
 
   protected void removeToken(final String tokenId) throws 
UnknownTokenException {
     validateToken(tokenId);
+    removeTokenState(tokenId);
+  }
+
+  /**
+   * Bulk removal of the specified tokens.
+   *
+   * @param tokenIds The unique identifiers of the tokens whose state should 
be removed.
+   *
+   * @throws UnknownTokenException
+   */
+  protected void removeTokens(final Set<String> tokenIds) throws 
UnknownTokenException {
+    // Duplicating the logic from removeToken(String) here because this method 
is supposed to be an optimization for
+    // sub-classes that access an external store, for which bulk token removal 
performs better than individual removal.
+    // Sub-classes will have implemented removeToken(String), and calling that 
here will undo any optimizations provided
+    // by the sub-class's implementation of this method.
+    for (String tokenId : tokenIds) {
+      removeTokenState(tokenId);
+    }
+  }
+
+  private void removeTokenState(final String tokenId) {

Review comment:
       I'm not sure if I agree that any non-optimized code should be left if we 
already know that code piece will result in causing performance issues.
   My two cents here:
   
   1. in `removeToken` I'd call `removeTokens(Collections.singleton(tokenId))`
   2. in `removeTokens` I'd **not** call a synchronized block `N` times. 
Instead, you may synchronize once, fetch the keyset and call the `removeAll` on 
that key set -> that collection is 
   
   > backed by the map, so changes to the map are reflected in the set, and 
vice-versa.
   
   Something like this:
   ```
       synchronized (tokenExpirations) {
         tokenExpirations.keySet().removeAll(tokenIds);
       }
   ```




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to