<br><font size=2 face="Verdana">Hi,</font>
<br><font size=2 face="Verdana">&nbsp;</font>
<br><font size=2 face="Verdana">We are proposing optimization of synchronization
blocks involved in loading of data from DB.</font>
<br><font size=2 face="Verdana">&nbsp;</font>
<br><font size=2 face="Verdana">Current system is synchronized on Aggregation
object while their segments are loaded from DB. We did analysis using JProfiler
to identify the maximum lock contentions.</font>
<br><font size=2 face="Verdana">&nbsp;</font>
<br><font size=2 face="Verdana"><b>Issues with the current implementation</b>:</font>
<br><font size=2 face="Verdana">1. Because of the lock at Aggregation,
requests are forced to wait even though they are not needed. Eg., If any
previous request is loading a new segment to Aggregation all the requests
that need the same aggregation will be blocked regardless of segment data
availability. </font>
<br><font size=2 face="Verdana">2. Aggregation is locked for entire period
of creating segment, firing sql, loading result set back on to segments.
So aggregation is locked when DB is processing data.</font>
<br><font size=2 face="Verdana">&nbsp;</font>
<br><font size=2 face="Verdana">We got 2 different working solutions to
address this issue</font>
<br><font size=2 face="Verdana">&nbsp;</font>
<br><font size=2 face="Verdana"><b>Approach 1: Keep locking on Aggregation
itself, but optimization the duration lock (CR 9325)</b></font>
<br><font size=2 face="Verdana">Changes made for this solution:</font>
<br><font size=2 face="Verdana"><b>1. Syncronized block removed from AggregationManager.load()</b></font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; Because this blocks covers
call to Aggregation.optimizePredicates(), Aggregation.load() but both these
methods are already Synchronized. </font>
<br><font size=2 face="Verdana"><b>2. Made Aggregation.optimizePredicates()
</b></font><font size=2 color=#c20000 face="Verdana"><b>non</b></font><font size=2 face="Verdana"><b>
synchronized</b><br>
 &nbsp; &nbsp;Uses <b>maxConstraints,star fields</b> of aggregation instance
but they are read only and set <b>only </b>in constructor. <br>
 &nbsp; &nbsp;Parameters to this method</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;columns
: created at CellRequest, it is read only access in the method. This is
related Aggregation object but columns list will remain same for the life
time of the Aggregation class.</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;predicates
: created at FBCR which is unique to a single request, it is also read
only and has no association to Aggregation object. </font>
<br><font size=2 face="Verdana"><b>3. Made Aggregation.load() </b></font><font size=2 color=#c20000 face="Verdana"><b>non</b></font><font size=2 face="Verdana"><b>
synchronized</b><br>
 &nbsp; &nbsp;Uses constrainedColumnsBitKey,segmentRefs fields of aggregation
instance.</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; constrainedColumnsBitKey
: This is read only and set in constructor</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; segmentRefs
: We are still synchronizing on aggregation when accessing this</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp;Parameters to this
method</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; columns
: created at CellRequest, this is set to columns instance variable. columns
list will remain same for the life time of the Aggregation class so we
have made change to set only at the first time load is called on aggregation.
This will happen only during creation of Aggregation instance and it will
be threadlocal at that point. </font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; predicates
: has no association to Aggregation object</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pinnedSegments
: has no association to Aggregation object</font>
<br><font size=2 face="Verdana">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Measures:
has no association to Aggregation object<b><br>
4. Changes in Aggregation.load()</b> &nbsp;<br>
 &nbsp; &nbsp;New Segments are added to segmentRefs only after they are
loaded with the data. This will ensure that none of the Segments are exposed
to other threads when they are loading. </font>
<p><font size=2 face="Verdana"><b>Advantages with this approach</b><br>
 &nbsp; &nbsp;1. Aggregation object is locked only during the time of adding
loaded Segments to segmentRefs.<br>
 &nbsp; &nbsp;2. This approach requires only minor modifications to the
existing locking strategy</font>
<p><font size=2 face="Verdana"><b>Disadvantage with this approach</b><br>
 &nbsp; &nbsp;If more than one request comes at the same time for a same
new segment of an existing aggregation, both the requests will fire query
and load the segment data. This issue is already exists in the current
version too, but window in which this can happen is small, this will happen
only until one of the request reaches the AggregationManager.load(). With
the new change this will happen until segment is set to AggregationManager.segmentRefs.</font>
<p><font size=2 face="Verdana"><b>Approach 2: Move the lock from Aggregation
to Segment wherever it is possible (CR 9366) <br>
 &nbsp; &nbsp;1. Synchronized block removed from AggregationManager.load()
</b>: reason same as approach 1<br>
<b> &nbsp; &nbsp;2. Made Aggregation.optimizePredicates() </b></font><font size=2 color=#c20000 face="Verdana"><b>non</b></font><font size=2 face="Verdana"><b>
synchronized </b>: reason same as Approach 1<b><br>
 &nbsp; &nbsp;3. Made Aggregation.load() </b></font><font size=2 color=#c20000 face="Verdana"><b>non</b></font><font size=2 face="Verdana"><b>
synchronized </b>: reason same as Approach 1<b><br>
 &nbsp; &nbsp;4. Changes in Aggregation.load() &nbsp;<br>
 &nbsp; &nbsp; &nbsp; &nbsp;</b>Aggregation object is altered only when
New Segments are added to segmentRefs, so we have Sync block covering add
to segmentRefs &nbsp; &nbsp; <b><br>
 &nbsp; &nbsp;5. Made Aggregation.getCellValue() </b></font><font size=2 color=#c20000 face="Verdana"><b>non</b></font><font size=2 face="Verdana"><b>
synchronized &nbsp; <br>
 &nbsp; &nbsp; &nbsp; &nbsp;</b>Only access to segmentRefs needs to be
Synchronized, introduced sync block to cover access to segmentRefs and
when segment is not ready and segment would contain the requested value(which
means another thread is loading the segment) current request will be blocked
until segment is loaded. And return value once segment is ready. If segment
fails to load it will return null similar to when segment is not found.
</font>
<p><font size=2 face="Verdana"><b>Advantage with this approach</b><br>
 &nbsp; &nbsp;1.Aggregation object is locked only during the time of adding
Segments to segmentRefs. <br>
 &nbsp; &nbsp;2. Concurrent requests will be blocked only if both the requests
are for same segment which is loading. This is a significant improvement
from Approach 1, because this reduces number of blocking requests. </font>
<p><font size=2 face="Verdana"><b>Disadvantage with this approach</b><br>
 &nbsp; &nbsp;1.Locking strategy has been changed to part on Aggregation
and part on Segment. This also means that we need more testing.<br>
 &nbsp; &nbsp;2.We are using segment state for synchronization, this piece
of code already exists but not used currently.</font>
<p><font size=2 face="Verdana">We have attached both our implementations
to the forum post: http://forums.pentaho.org/showthread.php?t=54274<br>
ConcurrentMDXTest class is to detected lock issues, this test is skewed
towards simulating concurrent access of same aggregation, this is not valid
for performance comparison of different implementations. <br>
<br>
Please give your inputs on which approach we should move forward and issues
or improvements we can make on to that approach. Also it would be of great
help if you can give us some more scenarios for concurrent testing.</font>
<p><font size=2 face="Verdana">Thanks,<br>
Thiyagu, Tushar</font>