Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@FrankGasparovic
Copy link

Signed-off-by: Anubhav [email protected]

@FrankGasparovic
Copy link
Author

Copy link
Collaborator

@irinaepshteyn irinaepshteyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review is still in progress. These are the initial comments...

} catch (Exception e) {
LOGGER.error(String.format(
"Unable to set cache key '%s' to value '%s' due to redis exception", key, result), e);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error message should not be tied to redis. Could have other cache implementations.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

} catch (Exception e) {
LOGGER.error(String.format("Unable to get cache key '%s'", key), e);
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a unit test that policy evaluation returns expected result if cache get or set fails

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


String zone = key.getZoneId();
values.addAll(multiGet(cachedResult.getResolvedResourceUris().stream()
.map(resourceUri -> resourceKey(zone, resourceUri)).collect(Collectors.toList())));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you thought of including resolved URIs as part of evaluation result key to avoid another trip to the cache store? Something like:
zoneId:resourceId:resolvedURIList:...
Are we limited on the length of the key?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a unit test that verifies that get returns null if one of the resolved resources change. Resolved URI of the changed does not match resource URI in the request.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a unit test that verifies that get returns null if timestamps for any entity including resolved URIs are not present.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I take it back. Resolved UIRs could not be part of the eval result key as they are not known at the time of the request.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

// Only need to assemble keys for policy sets, the subject, and the policy evaluation result.
// Resource-related information will be captured in the resolved resource URIs from the cached
// policy evaluation result.
List<String> keys = new ArrayList<>();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If resolvedURI were part of evaluation result key we could assemble resource keys for resolved URIs here.

}
private void setEntityTimestamps(final PolicyEvaluationRequestCacheKey key, final PolicyEvaluationResult result) {
// This will lower the overall hit rate for policy evaluation but is required to ensure that if
// the cached timestamp for any entity involved in this decision is aged out, the cached decision will be used
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean WILL NOT be used?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do mean will, but I think the message is confusing. I rewrote it.

String key = getKey.apply(zoneId, entityId);
setIfNotExists(key, timestampValue());
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between setEntityIfNotExists and resetForEntity?
When eval result is being cached we could call resetForEntity to set the timestamp. It will create a entity key if doesn't exist.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setEntityIfNotExists will set the timestamp for the object if the object is not in the cache. resetForEntity will reset the timestamp regardless if the value if the value is in the cache

multisetForResources(zoneId, resourceEntities.stream().map(resource -> resource.getResourceIdentifier())
multisetForResources(zoneId, resourceEntities.stream().map(ResourceEntity::getResourceIdentifier)
.collect(Collectors.toList()));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are collecting resource Ids into a list and then build a map of keys inside multisetForResources. Could we combine it all in one call? Map streamed resourceEntities to resourceKey and collect into a map with the timestamp logging debug message for each... :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

multisetForSubjects(zoneId,
subjectEntities.stream().map(subject -> subject.getSubjectIdentifier()).collect(Collectors.toList()));
subjectEntities.stream().map(SubjectEntity::getSubjectIdentifier).collect(Collectors.toList()));
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as for resetForResources above. Could we combine resetForSubjects and multisetForSubjects in one long beautiful fluent java 8 call? :-)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

boolean havePrivilegeServiceAttributesChanged(final List<String> values, final DateTime policyEvalTimestampUTC) {
for (String value : values) {
if (null == value) {
return true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Values were already tested for nulls by isRequestCached before calling this method.

"Privilege service attributes have timestamp '%s' which is after "
+ "policy evaluation timestamp '%s'",
invalidationTimestampUTC, policyEvalTimestampUTC);
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you are using lazy string construction we could rely on debug to check the debug level. No need for extra isDebugEnabled call. Will message formatting work with %s or should we use {}?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@irinaepshteyn irinaepshteyn self-assigned this Apr 14, 2017
Copy link
Collaborator

@irinaepshteyn irinaepshteyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More comments...

// all entities involved in the request.
values.addAll(multiGet(cachedResult.getResolvedResourceUris().stream()
.map(resourceUri -> resourceKey(zone, resourceUri)).collect(Collectors.toList())));

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One optimization we could do here is to compare resource from request with resolved resource. If policy doesn't contain any template URIs then request resource and resolved resource are the same. In that case we don't have to perform a multiGet again. In that case when assembling keys for the first call to multiGet we need to include a resource from request again.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added


void resetForPolicySet(String zoneId, String policySetId);

void setPolicySetIfNotExists(String zoneId, String policySetId);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setPolicySetIfNotExists, setResourceIfNotExists, setSubjectIfNotExists do not need to be part of cache interface. These methods are implemented and used by AbstractPolicyEvaluationCache only. However, setIfNotExists should be defined by interface and implemented by each cache implementation.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that setPolicySetIfNotExists, setResourceIfNotExists and setSubjectIfNotExists should not be part of the cache interface (because these are only used internally in the AbstractPolicyEvaluationCache). But why should setIfNotExists be apart of the interface if it is also only use internally?

}
});
void setIfNotExists(final String key, final String value) {
this.redisTemplate.boundValueOps(key).setIfAbsent(value);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we set an expiration timeout on the key similar to what's done in line #89? The same comment applies to set function above. Timeout is only set on the key for eval result and not for any other.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Timeout should not be set for anything other then Policy Evaluation. This is because we would then be unnecessarily reevaluating requests when entities have no changed.

assertEquals(evalCache.size(), 0);
Map<String, String> timestampCache = (Map<String, String>) getInternalState(this.cache, "timestampCache");
assertEquals(timestampCache.size(), 1);
assertEquals(evalCache.size(), 1);
Copy link
Collaborator

@irinaepshteyn irinaepshteyn Apr 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be rename the test to testSetPolicySetChangedTimestamp?

Copy link
Collaborator

@irinaepshteyn irinaepshteyn Apr 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current implementation of the in-memory cache stores eval result and timestamps in the same map, not in different maps as before. There is no need to have different tests for setting eval result and setting timestamps.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do feel like there is value in this test because of the logic to check the key format.

}

@Test
public void testGetWithCacheHit() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test to assert that get returns cached result if eval result is cached but not timestamps for entities.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If eval is cached but timestamps for entities are not, then get should return null

this.cache.resetForResource(ZONE_NAME, XFILES_ID);
this.cache.resetForPolicySet(ZONE_NAME, POLICY_ONE.getName());
this.cache.resetForPolicySet(ZONE_NAME, POLICY_TWO.getName());
request.setAction(ACTION_GET);
Copy link
Collaborator

@irinaepshteyn irinaepshteyn Apr 14, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to call resets for each entity i every test? Get will return cached result if no timestamps.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do, get will return null if no timestamps.

Copy link
Collaborator

@irinaepshteyn irinaepshteyn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done reviewing.

@FrankGasparovic
Copy link
Author

FrankGasparovic commented May 10, 2017

Siva ran performance tests and he saw a 3ms increase in Policy Evaluation calls

@sanjeevchopra
Copy link
Contributor

@anubhavi25 @FrankGasparovic - pls review my 2nd commit

Set<String> cachedResolvedResourceUris = cachedEvalResult.getResolvedResourceUris();
//is requested resource id same as resolved resource uri ?
if (cachedResolvedResourceUris.size() == 1
&& cachedResolvedResourceUris.toArray()[0].equals(key.getResourceId())) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use cachedResolvedResourceUris.iterator().next() vs toArray() so that we don't have to copy contents to array.

Copy link
Author

@FrankGasparovic FrankGasparovic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good.

Copy link
Contributor

@anubhavi25 anubhavi25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good for the most part 👍

return entryValues.get(lastValueIndex - 2);
}

String getRequestedResourceLastModified() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing the name to just getResourceLastModified should suffice (and is also consistent with the naming convention used for the other get*LastModified methods).

@sanjeevchopra
Copy link
Contributor

Performance tests show no regression. A second test was run which only writes resource and subject keys (which have no TTL) to confirm that eviction is working as expected.

@sanjeevchopra sanjeevchopra merged commit 9596557 into develop May 31, 2017
@sanjeevchopra sanjeevchopra deleted the US66693 branch May 31, 2017 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants