Fix bug # 15222: The composite datasource has a few operations which are somewhat "expensive". Have these behaviors on by default, but expose a method on the composite datasources so that they can be selectively turned off [for Mail/News, for example] if the capability is not needed/used (such as negative assertions). Review: waterson@netscape.com. Additional Mail/News Testing: putterman@netscape.com

This commit is contained in:
rjc@netscape.com
1999-10-01 04:07:55 +00:00
parent 1b791c25a3
commit 468db4922a
5 changed files with 245 additions and 71 deletions

View File

@@ -90,9 +90,12 @@ public:
nsIRDFNode* target,
PRBool tv);
protected:
nsCOMPtr<nsISupportsArray> mObservers;
virtual ~CompositeDataSourceImpl(void);
nsCOMPtr<nsISupportsArray> mObservers;
PRBool mAllowNegativeAssertions;
PRBool mCoalesceDuplicateArcs;
virtual ~CompositeDataSourceImpl(void);
};
@@ -105,7 +108,9 @@ protected:
class CompositeEnumeratorImpl : public nsISimpleEnumerator
{
public:
CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource);
CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
PRBool aAllowNegativeAssertions,
PRBool aCoalesceDuplicateArcs);
virtual ~CompositeEnumeratorImpl();
// nsISupports interface
@@ -126,11 +131,18 @@ protected:
nsISimpleEnumerator* mCurrent;
nsIRDFNode* mResult;
PRInt32 mNext;
nsVoidArray mAlreadyReturned;
PRBool mAllowNegativeAssertions;
PRBool mCoalesceDuplicateArcs;
};
CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource)
: mCompositeDataSource(aCompositeDataSource),
CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
PRBool aAllowNegativeAssertions,
PRBool aCoalesceDuplicateArcs)
: mCompositeDataSource(aCompositeDataSource),
mAllowNegativeAssertions(aAllowNegativeAssertions),
mCoalesceDuplicateArcs(aCoalesceDuplicateArcs),
mCurrent(nsnull),
mResult(nsnull),
mNext(0)
@@ -142,10 +154,18 @@ CompositeEnumeratorImpl::CompositeEnumeratorImpl(CompositeDataSourceImpl* aCompo
CompositeEnumeratorImpl::~CompositeEnumeratorImpl(void)
{
if (mCoalesceDuplicateArcs == PR_TRUE)
{
for (PRInt32 i = mAlreadyReturned.Count() - 1; i >= 0; --i)
{
nsIRDFNode *node = (nsIRDFNode *) mAlreadyReturned[i];
NS_RELEASE(node);
}
}
NS_IF_RELEASE(mCurrent);
NS_IF_RELEASE(mResult);
NS_RELEASE(mCompositeDataSource);
NS_IF_RELEASE(mCurrent);
NS_IF_RELEASE(mResult);
NS_RELEASE(mCompositeDataSource);
}
@@ -221,33 +241,66 @@ CompositeEnumeratorImpl::HasMoreElements(PRBool* aResult)
rv = result->QueryInterface(nsIRDFNode::GetIID(), (void**) &mResult);
if (NS_FAILED(rv)) return rv;
// See if any previous data source negates this
PRBool hasNegation = PR_FALSE;
for (i = mNext - 1; i >= 0; --i) {
nsIRDFDataSource* datasource =
(nsIRDFDataSource*) mCompositeDataSource->mDataSources[i];
if (mAllowNegativeAssertions == PR_TRUE)
{
// See if any previous data source negates this
PRBool hasNegation = PR_FALSE;
for (i = mNext - 1; i >= 0; --i)
{
nsIRDFDataSource* datasource =
(nsIRDFDataSource*) mCompositeDataSource->mDataSources[i];
rv = HasNegation(datasource, mResult, &hasNegation);
if (NS_FAILED(rv)) return rv;
if (hasNegation)
break;
}
// if so, we've gotta keep looking
if (hasNegation) {
NS_RELEASE(mResult);
continue;
}
rv = HasNegation(datasource, mResult, &hasNegation);
if (NS_FAILED(rv)) return rv;
if (hasNegation)
break;
}
// if so, we've gotta keep looking
if (hasNegation)
{
NS_RELEASE(mResult);
continue;
}
}
if (mCoalesceDuplicateArcs == PR_TRUE)
{
// Now see if we've returned it once already.
// XXX N.B. performance here...may want to hash if things get large?
PRBool alreadyReturned = PR_FALSE;
for (i = mAlreadyReturned.Count() - 1; i >= 0; --i)
{
if (mAlreadyReturned[i] == mResult)
{
alreadyReturned = PR_TRUE;
break;
}
}
if (alreadyReturned == PR_TRUE)
{
NS_RELEASE(mResult);
continue;
}
}
// If we get here, then we've really found one. It'll
// remain cached in mResult until GetNext() sucks it out.
*aResult = PR_TRUE;
// Remember that we returned it, so we don't return duplicates.
// XXX I wonder if we should make unique-checking be
// optional. This could get to be pretty expensive (this
// implementation turns iteration into O(n^2)).
if (mCoalesceDuplicateArcs == PR_TRUE)
{
mAlreadyReturned.AppendElement(mResult);
NS_ADDREF(mResult);
}
return NS_OK;
} while (1);
@@ -292,7 +345,9 @@ public:
CompositeArcsInOutEnumeratorImpl(CompositeDataSourceImpl* aCompositeDataSource,
nsIRDFNode* aNode,
Type aType);
Type aType,
PRBool aAllowNegativeAssertions,
PRBool aCoalesceDuplicateArcs);
virtual ~CompositeArcsInOutEnumeratorImpl();
@@ -305,15 +360,21 @@ public:
private:
nsIRDFNode* mNode;
Type mType;
PRBool mAllowNegativeAssertions;
PRBool mCoalesceDuplicateArcs;
};
CompositeArcsInOutEnumeratorImpl::CompositeArcsInOutEnumeratorImpl(
CompositeDataSourceImpl* aCompositeDataSource,
nsIRDFNode* aNode,
Type aType)
: CompositeEnumeratorImpl(aCompositeDataSource),
Type aType,
PRBool aAllowNegativeAssertions,
PRBool aCoalesceDuplicateArcs)
: CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
mNode(aNode),
mType(aType)
mType(aType),
mAllowNegativeAssertions(aAllowNegativeAssertions),
mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
{
NS_ADDREF(mNode);
}
@@ -361,7 +422,9 @@ public:
nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
PRBool aTruthValue);
PRBool aTruthValue,
PRBool aAllowNegativeAssertions,
PRBool aCoalesceDuplicateArcs);
virtual ~CompositeAssertionEnumeratorImpl();
@@ -376,6 +439,8 @@ private:
nsIRDFResource* mProperty;
nsIRDFNode* mTarget;
PRBool mTruthValue;
PRBool mAllowNegativeAssertions;
PRBool mCoalesceDuplicateArcs;
};
@@ -384,12 +449,16 @@ CompositeAssertionEnumeratorImpl::CompositeAssertionEnumeratorImpl(
nsIRDFResource* aSource,
nsIRDFResource* aProperty,
nsIRDFNode* aTarget,
PRBool aTruthValue)
: CompositeEnumeratorImpl(aCompositeDataSource),
PRBool aTruthValue,
PRBool aAllowNegativeAssertions,
PRBool aCoalesceDuplicateArcs)
: CompositeEnumeratorImpl(aCompositeDataSource, aAllowNegativeAssertions, aCoalesceDuplicateArcs),
mSource(aSource),
mProperty(aProperty),
mTarget(aTarget),
mTruthValue(aTruthValue)
mTruthValue(aTruthValue),
mAllowNegativeAssertions(aAllowNegativeAssertions),
mCoalesceDuplicateArcs(aCoalesceDuplicateArcs)
{
NS_IF_ADDREF(mSource);
NS_ADDREF(mProperty); // always must be specified
@@ -449,6 +518,8 @@ NS_NewRDFCompositeDataSource(nsIRDFCompositeDataSource** result)
CompositeDataSourceImpl::CompositeDataSourceImpl(void)
: mAllowNegativeAssertions(PR_TRUE),
mCoalesceDuplicateArcs(PR_TRUE)
{
NS_INIT_REFCNT();
@@ -540,6 +611,9 @@ CompositeDataSourceImpl::GetSource(nsIRDFResource* property,
PRBool tv,
nsIRDFResource** source)
{
if ((mAllowNegativeAssertions == PR_FALSE) && (tv == PR_FALSE))
return(NS_RDF_NO_VALUE);
PRInt32 count = mDataSources.Count();
for (PRInt32 i = 0; i < count; ++i) {
nsIRDFDataSource* ds = NS_STATIC_CAST(nsIRDFDataSource*, mDataSources[i]);
@@ -551,6 +625,8 @@ CompositeDataSourceImpl::GetSource(nsIRDFResource* property,
if (rv == NS_RDF_NO_VALUE)
continue;
if (mAllowNegativeAssertions == PR_FALSE) return(NS_OK);
// okay, found it. make sure we don't have the opposite
// asserted in a more local data source
if (!HasAssertionN(count-1, *source, property, target, !tv))
@@ -580,7 +656,11 @@ CompositeDataSourceImpl::GetSources(nsIRDFResource* aProperty,
if (! aResult)
return NS_ERROR_NULL_POINTER;
*aResult = new CompositeAssertionEnumeratorImpl(this, nsnull, aProperty, aTarget, aTruthValue);
if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
return(NS_RDF_NO_VALUE);
*aResult = new CompositeAssertionEnumeratorImpl(this, nsnull, aProperty,
aTarget, aTruthValue, mAllowNegativeAssertions, mCoalesceDuplicateArcs);
if (! *aResult)
return NS_ERROR_OUT_OF_MEMORY;
@@ -606,6 +686,9 @@ CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource,
if (! aResult)
return NS_ERROR_NULL_POINTER;
if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
return(NS_RDF_NO_VALUE);
PRInt32 count = mDataSources.Count();
for (PRInt32 i = 0; i < count; ++i) {
nsIRDFDataSource* ds = NS_STATIC_CAST(nsIRDFDataSource*, mDataSources[i]);
@@ -619,14 +702,14 @@ CompositeDataSourceImpl::GetTarget(nsIRDFResource* aSource,
// okay, found it. make sure we don't have the opposite
// asserted in an earlier data source
if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) {
// whoops, it's been negated.
NS_RELEASE(*aResult);
return NS_RDF_NO_VALUE;
}
else {
return NS_OK;
if (mAllowNegativeAssertions == PR_TRUE) {
if (HasAssertionN(count-1, aSource, aProperty, *aResult, !aTruthValue)) {
// whoops, it's been negated.
NS_RELEASE(*aResult);
return NS_RDF_NO_VALUE;
}
}
return NS_OK;
}
}
@@ -677,7 +760,11 @@ CompositeDataSourceImpl::GetTargets(nsIRDFResource* aSource,
if (! aResult)
return NS_ERROR_NULL_POINTER;
*aResult = new CompositeAssertionEnumeratorImpl(this, aSource, aProperty, nsnull, aTruthValue);
if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
return(NS_RDF_NO_VALUE);
*aResult = new CompositeAssertionEnumeratorImpl(this, aSource, aProperty,
nsnull, aTruthValue, mAllowNegativeAssertions, mCoalesceDuplicateArcs);
if (! *aResult)
return NS_ERROR_OUT_OF_MEMORY;
@@ -703,6 +790,9 @@ CompositeDataSourceImpl::Assert(nsIRDFResource* aSource,
if (! aTarget)
return NS_ERROR_NULL_POINTER;
if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
return(NS_RDF_ASSERTION_REJECTED);
nsresult rv;
// XXX Need to add back the stuff for unblocking ...
@@ -900,6 +990,12 @@ CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource,
if (! aResult)
return NS_ERROR_NULL_POINTER;
if ((mAllowNegativeAssertions == PR_FALSE) && (aTruthValue == PR_FALSE))
{
*aResult = PR_FALSE;
return(NS_OK);
}
nsresult rv;
// Otherwise, look through all the data sources to see if anyone
@@ -913,14 +1009,18 @@ CompositeDataSourceImpl::HasAssertion(nsIRDFResource* aSource,
if (*aResult)
return NS_OK;
PRBool hasNegation;
rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation);
if (NS_FAILED(rv)) return rv;
if (mAllowNegativeAssertions == PR_TRUE)
{
PRBool hasNegation;
rv = datasource->HasAssertion(aSource, aProperty, aTarget, !aTruthValue, &hasNegation);
if (NS_FAILED(rv)) return rv;
if (hasNegation) {
*aResult = PR_FALSE;
return NS_OK;
}
if (hasNegation)
{
*aResult = PR_FALSE;
return NS_OK;
}
}
}
// If we get here, nobody had the assertion at all
@@ -973,7 +1073,9 @@ CompositeDataSourceImpl::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator**
return NS_ERROR_NULL_POINTER;
nsISimpleEnumerator* result =
new CompositeArcsInOutEnumeratorImpl(this, aTarget, CompositeArcsInOutEnumeratorImpl::eArcsIn);
new CompositeArcsInOutEnumeratorImpl(this, aTarget,
CompositeArcsInOutEnumeratorImpl::eArcsIn,
mAllowNegativeAssertions, mCoalesceDuplicateArcs);
if (! result)
return NS_ERROR_OUT_OF_MEMORY;
@@ -996,7 +1098,9 @@ CompositeDataSourceImpl::ArcLabelsOut(nsIRDFResource* aSource,
return NS_ERROR_NULL_POINTER;
nsISimpleEnumerator* result =
new CompositeArcsInOutEnumeratorImpl(this, aSource, CompositeArcsInOutEnumeratorImpl::eArcsOut);
new CompositeArcsInOutEnumeratorImpl(this, aSource,
CompositeArcsInOutEnumeratorImpl::eArcsOut,
mAllowNegativeAssertions, mCoalesceDuplicateArcs);
if (! result)
return NS_ERROR_OUT_OF_MEMORY;
@@ -1181,6 +1285,34 @@ CompositeDataSourceImpl::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSource
// fit in. Right now, the new datasource gets stuck at the end.
// need to add the observers of the CompositeDataSourceImpl to the new data source.
NS_IMETHODIMP
CompositeDataSourceImpl::GetAllowNegativeAssertions(PRBool *aAllowNegativeAssertions)
{
*aAllowNegativeAssertions = mAllowNegativeAssertions;
return(NS_OK);
}
NS_IMETHODIMP
CompositeDataSourceImpl::SetAllowNegativeAssertions(PRBool aAllowNegativeAssertions)
{
mAllowNegativeAssertions = aAllowNegativeAssertions;
return(NS_OK);
}
NS_IMETHODIMP
CompositeDataSourceImpl::GetCoalesceDuplicateArcs(PRBool *aCoalesceDuplicateArcs)
{
*aCoalesceDuplicateArcs = mCoalesceDuplicateArcs;
return(NS_OK);
}
NS_IMETHODIMP
CompositeDataSourceImpl::SetCoalesceDuplicateArcs(PRBool aCoalesceDuplicateArcs)
{
mCoalesceDuplicateArcs = aCoalesceDuplicateArcs;
return(NS_OK);
}
NS_IMETHODIMP
CompositeDataSourceImpl::AddDataSource(nsIRDFDataSource* aDataSource)
{
@@ -1224,13 +1356,17 @@ CompositeDataSourceImpl::OnAssert(nsIRDFResource* aSource,
// datasource actually served up the OnAssert(): we could use
// HasAssertionN() to only search datasources _before_ the
// datasource that coughed up the assertion.
nsresult rv;
PRBool hasAssertion;
rv = HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
if (NS_FAILED(rv)) return rv;
nsresult rv = NS_OK;
if (! hasAssertion)
return NS_OK;
if (mAllowNegativeAssertions == PR_TRUE)
{
PRBool hasAssertion;
rv = HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
if (NS_FAILED(rv)) return rv;
if (! hasAssertion)
return(NS_OK);
}
if (mObservers) {
PRUint32 count;
@@ -1260,12 +1396,16 @@ CompositeDataSourceImpl::OnUnassert(nsIRDFResource* aSource,
// HasAssertionN() to only search datasources _before_ the
// datasource that coughed up the assertion.
nsresult rv;
PRBool hasAssertion;
rv = HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
if (NS_FAILED(rv)) return rv;
if (hasAssertion)
return NS_OK;
if (mAllowNegativeAssertions == PR_TRUE)
{
PRBool hasAssertion;
rv = HasAssertion(aSource, aProperty, aTarget, PR_TRUE, &hasAssertion);
if (NS_FAILED(rv)) return rv;
if (hasAssertion)
return NS_OK;
}
if (mObservers) {
PRUint32 count;
@@ -1337,9 +1477,3 @@ CompositeDataSourceImpl::OnMove(nsIRDFResource* aOldSource,
}
return NS_OK;
}