smartmemberreader.java
来自「数据仓库展示程序」· Java 代码 · 共 576 行 · 第 1/2 页
JAVA
576 行
/*
// $Id: //open/mondrian/src/main/mondrian/rolap/SmartMemberReader.java#26 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// (C) Copyright 2001-2005 Kana Software, Inc. and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//
// jhyde, 21 December, 2001
*/
package mondrian.rolap;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import mondrian.olap.Util;
/**
* <code>SmartMemberReader</code> implements {@link MemberReader} by keeping a
* cache of members and their children. If a member is 'in cache', there is a
* list of its children. Its children are not necessarily 'in cache'.
*
* <p>Cache retention. We have not implemented a cache flushing policy. Members
* are never removed from the cache.</p>
*
* <p>Uniqueness. We need to ensure that there is never more than one {@link
* RolapMember} object representing the same member.</p>
*
* @author jhyde
* @since 21 December, 2001
* @version $Id: //open/mondrian/src/main/mondrian/rolap/SmartMemberReader.java#26 $
**/
public class SmartMemberReader implements MemberReader, MemberCache {
private final MemberReader source;
/** Maps {@link RolapMember} to a {@link ChildrenList} of its children, and
* records usages.
* Locking strategy is to lock the parent SmartMemberReader. **/
private final Map mapMemberToChildren;
/** Maps a {@link MemberKey} to a {@link SoftReference} to a
* {@link RolapMember}, and is used to ensure that there is at most one
* object representing a given member.
* The soft reference allows members to be forgotten.
* Locking strategy is to lock the parent SmartMemberReader. **/
private final Map mapKeyToMember;
private List rootMembers;
private final Map mapLevelToMembers;
SmartMemberReader(MemberReader source) {
this.source = source;
if (!source.setCache(this)) {
throw Util.newInternal(
"MemberSource (" + source + ", " + source.getClass() +
") does not support cache-writeback");
}
this.mapLevelToMembers = new HashMap();
this.mapKeyToMember = new HashMap();
this.mapMemberToChildren = new HashMap();
}
// implement MemberReader
public RolapHierarchy getHierarchy() {
return source.getHierarchy();
}
// implement MemberSource
public boolean setCache(MemberCache cache) {
// we do not support cache writeback -- we must be masters of our
// own cache
return false;
}
// implement MemberCache
public Object makeKey(RolapMember parent, Object key) {
return new MemberKey(parent, key);
}
// implement MemberCache
// synchronization: Must synchronize, because uses mapKeyToMember
public synchronized RolapMember getMember(Object key) {
SoftReference ref = (SoftReference) mapKeyToMember.get(key);
if (ref == null) {
return null;
}
final RolapMember rolapMember = (RolapMember) ref.get();
if (rolapMember == null) {
// Referenced member has been garbage collected; remove the hash
// table entry too.
mapKeyToMember.put(key,null);
}
return rolapMember;
}
// implement MemberCache
// synchronization: Must synchronize, because modifies mapKeyToMember
public synchronized Object putMember(Object key, RolapMember value) {
return mapKeyToMember.put(key, new SoftReference(value));
}
// implement MemberReader
public RolapMember[] getMembers() {
List v = new ArrayList();
RolapLevel[] levels = (RolapLevel[]) getHierarchy().getLevels();
// todo: optimize by walking to children for members we know about
for (int i = 0; i < levels.length; i++) {
getMembersInLevel(v, levels[i], 0, Integer.MAX_VALUE);
}
return RolapUtil.toArray(v);
}
public List getRootMembers() {
if (rootMembers == null) {
rootMembers = source.getRootMembers();
}
return rootMembers;
}
/**
* @synchronization modifies mapLevelToMembers
*/
public synchronized List getMembersInLevel(RolapLevel level,
int startOrdinal,
int endOrdinal) {
SoftReference ref = (SoftReference) mapLevelToMembers.get(level);
if (ref != null) {
List members = (List) ref.get();
if (members != null) {
return members;
}
mapLevelToMembers.remove(level);
}
List members = source.getMembersInLevel(level, startOrdinal, endOrdinal);
ref = new SoftReference(members);
mapLevelToMembers.put(level, ref);
return members;
}
private void getMembersInLevel(List result,
RolapLevel level,
int startOrdinal,
int endOrdinal) {
final List membersInLevel =
getMembersInLevel(level, startOrdinal, endOrdinal);
result.addAll(membersInLevel);
}
public void getMemberChildren(RolapMember parentMember, List children) {
List parentMembers = new ArrayList();
parentMembers.add(parentMember);
getMemberChildren(parentMembers, children);
}
public synchronized void getMemberChildren(List parentMembers,
List children) {
List missed = new ArrayList();
for (Iterator it = parentMembers.iterator(); it.hasNext();) {
RolapMember parent = (RolapMember) it.next();
SoftReference ref = (SoftReference)
mapMemberToChildren.get(parent);
if (ref == null) {
missed.add(parent);
} else {
ChildrenList v = (ChildrenList) ref.get();
if (v == null) {
mapMemberToChildren.remove(parent);
missed.add(parent);
} else {
children.addAll(v.list);
}
}
}
if (missed.size() > 0) {
readMemberChildren(missed, children);
}
}
public RolapMember lookupMember(String[] uniqueNameParts,
boolean failIfNotFound) {
return RolapUtil.lookupMember(this, uniqueNameParts, failIfNotFound);
}
/**
* A <code>ChildrenList</code> is held in the
* {@link SmartMemberReader#mapMemberToChildren} cache.
**/
private static class ChildrenList {
private final RolapMember member;
private final List list;
ChildrenList(RolapMember member, List list) {
this.member = member;
this.list = list;
}
public String toString() {
return super.toString()
+ " {member="
+ member
+ ", childCount="
+ list.size()
+ "}";
}
};
/**
* Reads the children of <code>member</code> into cache, and also into
* <code>result</code>.
*
* @param result Children are written here, in order
* @param members Members whose children to read
**/
private void readMemberChildren(List members, List result) {
if (false) {
// Pre-condition disabled. It makes sense to have the pre-
// condition, because lists of parent members are typically
// sorted by construction, and we should be able to exploit this
// when constructing the (significantly larger) set of children.
// But currently BasicQueryTest.testBasketAnalysis() fails this
// assert, and I haven't had time to figure out why.
// -- jhyde, 2004/6/10.
Util.assertPrecondition(isSorted(members), "isSorted(members)");
}
List children = new ArrayList();
source.getMemberChildren(members, children);
// Put them in a temporary hash table first. Register them later, when
// we know their size (hence their 'cost' to the cache pool).
Map tempMap = new HashMap();
for (int i = 0, n = members.size(); i < n; i++) {
tempMap.put(members.get(i), new ArrayList());
}
for (int i = 0, childrenCount = children.size(); i < childrenCount; i++) {
// todo: We could optimize here. If members.length is small, it's
// more efficient to drive from members, rather than hashing
// children.length times. We could also exploit the fact that the
// result is sorted by ordinal and therefore, unless the "members"
// contains members from different levels, children of the same
// member will be contiguous.
RolapMember child = (RolapMember) children.get(i);
List list = (ArrayList) tempMap.get(child.getParentMember());
list.add(child);
result.add(child);
}
synchronized (this) {
for (Iterator keys = tempMap.keySet().iterator(); keys.hasNext();) {
RolapMember member = (RolapMember) keys.next();
List list = (ArrayList) tempMap.get(member);
if (!hasChildren(member)) {
putChildren(member, list);
}
}
}
}
/**
* Returns true if every element of <code>members</code> is not null and is
* strictly less than the following element; false otherwise.
*/
public boolean isSorted(List members) {
final int count = members.size();
if (count == 0) {
return true;
}
RolapMember m1 = (RolapMember) members.get(0);
if (m1 == null) {
// Special case check for 0th element, just in case length == 1.
return false;
}
for (int i = 1; i < count; i++) {
RolapMember m0 = m1;
m1 = (RolapMember) members.get(i);
if (m1 == null || compare(m0, m1, false) >= 0) {
return false;
}
}
return true;
}
public synchronized boolean hasChildren(RolapMember member) {
return mapMemberToChildren.get(member) != null;
}
public synchronized boolean hasLevelMembers(RolapLevel level) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?