You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Peter <ji...@zeus.net.au> on 2011/12/31 05:18:55 UTC

DynamicPolicyProvider DelegateCombinerSecurityManager performance & scalability

Reviewing my policy provider code, I found a HashSet<Permission> being used to cache permissions before adding to an already published PermissionCollection.  This was done to batch add permissions to that PermissionCollection so the jvm would optimise the write lock outside of the Iterator loop.

The set was used to avoid duplicate Permission objects.

Well it performed like chunky custard at a posh restraunt: not good.  

Due of course to the previously mentioned poor hashCode and equals implementations some permissions have. 

I could have used the PermissionComparator and a TreeSet for much better performance, however I discovered I could eliminate the Set entirely by not mutating published PermissionCollection's and replacing them on write instead.

This significantly improved the policy's single thread performance, I'll revisit the previously failling event tests that required increase delays, to see if I can't match or better sun's policy provider.  It certainly seems as fast now, based on test times.

DelegateCombinerSecurityManager has some neat performance optimisations that help both single threaded performance and scalability.

Permission checks are only performed once per AccessControlContext, results are cached, so the same permission isn't checked twice (unless cleared by a policy refresh). AccessControlContext has good hashcode and equals implementations. While the cache performes well under concurrent access, a PermissionComparator is used in a TreeSet that utilises soft references to avoid invoking Permission hashCode or equals.  JVM's TreeSet implementation uses a backing TreeMap which was replaced in 2009 with Harmony's red black tree implementation, modified further by Sun for optimum compatibility.  The TreeSet is wrapped with a multi read single write collection wrapper, then wrapped again by a soft reference collection wrapper.

A DomainCombiner is used to create a context (cached for reuse) to execute permission checks on ProtectionDomains in parallel. If the the number of domains in a context exceed 3, they're broken into separate tasks and submitted to an executor, the first protection domain to fail causes the other tasks to be cancelled, returning the result to the caller.  Contexts with 3 or less domains are typically priviledged or mostly priviledged and return quickly without needing to be divided.

The executor is tuned to the number of cpu cores and load, I'm thinking about providing a Property or two so administrators can fine tune it to their environment.

If the executor reaches its thread limit, tasks are executed by the caller instead, using SynchronousBlockingQueue, which has a queue size of zero and uses a lock free algorithm to hand tasks off to executor threads.  Since there may be many domains in a context, if load reduces on the executor, and more threads become available, the tasks will be divided among threads and execute in parallel.

Over time the cache will grow and reduce the executors load and in doing so reduce the number of writes to the cache, which will eventually become mostly read, for very good concurrency.  I can imagine that hotspot will also contribute.

The new SecurityManager and policy providers should remove any concerns about security impacting performance.

I haven't done anything about reimplementing SocketPermission at this stage, any help would of course be appreciated.

Cheers,

Peter.