001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2012-2012 Pentaho and others 008// All Rights Reserved. 009*/ 010package mondrian.rolap; 011 012import mondrian.olap.*; 013import mondrian.rolap.RolapHierarchy.LimitedRollupMember; 014import mondrian.rolap.sql.*; 015 016import java.util.*; 017import java.util.concurrent.locks.*; 018 019/** 020 * A {@link SmartRestrictedMemberReader} is a subclass of 021 * {@link RestrictedMemberReader} which caches the access rights 022 * per children's list. We place them in this throw-away object 023 * to speed up partial rollup calculations. 024 * 025 * <p>The speed improvement is noticeable when dealing with very 026 * big dimensions with a lot of branches (like a parent-child 027 * hierarchy) because the 'partial' rollup policy forces us to 028 * navigate the tree and find the lowest level to rollup to and 029 * then figure out all of the children on which to constraint 030 * the SQL query. 031 */ 032class SmartRestrictedMemberReader extends RestrictedMemberReader { 033 034 SmartRestrictedMemberReader( 035 final MemberReader memberReader, 036 final Role role) 037 { 038 // We want to extend a RestrictedMemberReader with access details 039 // that we cache. 040 super(memberReader, role); 041 } 042 043 // Our little ad-hoc cache. 044 final Map<RolapMember, AccessAwareMemberList> 045 memberToChildren = 046 new WeakHashMap<RolapMember, AccessAwareMemberList>(); 047 048 // The lock for cache access. 049 final ReadWriteLock lock = new ReentrantReadWriteLock(); 050 051 @Override 052 public Map<? extends Member, Access> getMemberChildren( 053 RolapMember member, 054 List<RolapMember> children, 055 MemberChildrenConstraint constraint) 056 { 057 // Strip off the rollup wrapper. 058 if (member instanceof LimitedRollupMember) { 059 member = ((LimitedRollupMember)member).member; 060 } 061 try { 062 // Get the read lock. 063 lock.readLock().lock(); 064 065 AccessAwareMemberList memberList = 066 memberToChildren.get(member); 067 068 if (memberList != null) { 069 // Sadly, we need to do a hard cast here, 070 // but since we know what it is, it's fine. 071 children.addAll( 072 memberList.children); 073 074 return memberList.accessMap; 075 } 076 } finally { 077 lock.readLock().unlock(); 078 } 079 080 // No cache data. 081 try { 082 // Get a write lock. 083 lock.writeLock().lock(); 084 085 Map<? extends Member, Access> membersWithAccessDetails = 086 super.getMemberChildren( 087 member, 088 children, 089 constraint); 090 091 memberToChildren.put( 092 member, 093 new AccessAwareMemberList( 094 membersWithAccessDetails, 095 new ArrayList(membersWithAccessDetails.keySet()))); 096 097 return membersWithAccessDetails; 098 } finally { 099 lock.writeLock().unlock(); 100 } 101 } 102 103 private static class AccessAwareMemberList { 104 private final Map<? extends Member, Access> accessMap; 105 private final Collection<RolapMember> children; 106 public AccessAwareMemberList( 107 Map<? extends Member, Access> accessMap, 108 Collection<RolapMember> children) 109 { 110 this.accessMap = accessMap; 111 this.children = children; 112 } 113 } 114} 115 116// End SmartRestrictedMemberReader.java