<br><font size=2 face="sans-serif">Hello,</font>
<br>
<br><font size=2 face="sans-serif">We are exploring the ways to add parallel
query execution in Mondrian. One simple prototype we implemented goes through
the batches in FastBatchingCellReader and runs every batch in a new worker
thread. To make the ThreadLocals available to the worker thread we changed
ThreadLocal in RolapStar and other places to InheritableThreadLocal.</font>
<br>
<br><font size=2 face="sans-serif">The objectives are simple,</font>
<br><font size=2 face="sans-serif">- In case an MDX results in more than
one sql for fact data, these sqls should run in parallel</font>
<br><font size=2 face="sans-serif">- No support for explicit transactions
/ real time updates to the database</font>
<br><font size=2 face="sans-serif">- Thread pooling, life cycle management
and related things will follow later</font>
<br>
<br><font size=2 face="sans-serif">We used JProfiler to run QueryRunner
to identify the biggest bottlenecks indicated by thread monitor wait period.
QueryRunner was run with 5 threads, 100 seconds and random queries set
to false (5, 100, false). Profiling report was generated on the snapshot
immediately after QueryRunner exited. It was run on a Dell Latitude D620
with Core 2 Duo (2 Cores), 2 GB RAM, WinXp SP2 32 bit, Sun jdk 1.5.0_07.
Mondrian connects to Mysql 5 running on the same box.</font>
<br>
<br><font size=2 face="sans-serif">Monitor Usage Statistics</font>
<br><font size=2 face="sans-serif">Session: &nbsp; &nbsp; &nbsp; &nbsp;
QueryRunner</font>
<br><font size=2 face="sans-serif">Statistics: &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;Monitor Usage Statistics Grouped by Monitors</font>
<br><font size=2 face="sans-serif">Sorted by: &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp;Block duration</font>
<br>
<br><font size=2 face="sans-serif">Without parallel batch execution</font>
<br><font size=2 face="sans-serif">Monitors &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;Block count &nbsp; &nbsp; &nbsp; &nbsp;Block
duration</font>
<br><font size=2 face="sans-serif">mondrian.rolap.RolapBaseCubeMeasure
(id: 11) &nbsp; &nbsp; &nbsp; &nbsp;3490 &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;9700 ms &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.RolapCube (id: 12) &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;2426 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;10 s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.RolapSchema$Pool (id:
7) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;15
s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">java.util.HashMap (id: 18) &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;11851 &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;35 s &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.SmartMemberReader (id:
25) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;24
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;42
s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">java.lang.Class (id: 10) &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp;129733 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;139 s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;</font>
<br>
<br><font size=2 face="sans-serif">With parallel batch execution</font>
<br><font size=2 face="sans-serif">Monitors &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;Block count &nbsp; &nbsp; &nbsp; &nbsp;Block
duration &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.RolapCube (id: 11) &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;1846 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;10 s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.agg.Aggregation (id:
42) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;1023 &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;12 s &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">java.util.HashMap (id: 20) &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4435 &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;19 s &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.RolapSchema$Pool (id:
7) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;21
s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">mondrian.rolap.SmartMemberReader (id:
23) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;35
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;57
s &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br><font size=2 face="sans-serif">java.lang.Class (id: 5) &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp;91145 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp;106 s &nbsp; &nbsp; &nbsp; &nbsp;</font>
<br>
<br><font size=2 face="sans-serif">We are anlyzing these options to reduce
lock contentions and improve performance</font>
<br><font size=2 face="sans-serif">a) Replacing the synchronization with
Read and Write RenentrantLocks with reduced scope</font>
<br><font size=2 face="sans-serif">b) Using ConcurrentHashMap</font>
<br><font size=2 face="sans-serif">c) Replace syncronized lazy initialize
with static initialize at load time</font>
<br>
<br><font size=2 face="sans-serif">To verify functional correctness after
multithreaded batch execution we adapted QueryRunner to do result verification.
We observed an issue of result set member ordering in case we toggle the
MondrianProperties.instance().DisableCaching between multiple test runs
in the same process. Apart from that all the existing test run successfully</font>
<br>
<br><font size=2 face="sans-serif">We tried out various optimizations with
varying degree of success</font>
<br>
<br><font size=2 face="sans-serif">This is a simplistic approach but seems
to be working. </font>
<br>
<br><font size=2 face="sans-serif">We will post more on this once we have
more statistics to validate the benifits of this approach. </font>
<br><font size=2 face="sans-serif">Please let us know if there are any
other approaches we should be considering.</font>
<br>
<br><font size=2 face="sans-serif">-Ajit</font>