1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This Original Code has been modified by IBM Corporation.
9 * Modifications made by IBM described herein are
10 * Copyright (c) International Business Machines
13 * Modifications to Mozilla code or documentation
14 * identified per MPL Section 3.3
16 * Date Modified by Description of modification
17 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
23 Implementation for an in-memory RDF data store.
27 1) Instrument this code to gather space and time performance
30 2) Optimize lookups for datasources which have a small number
31 of properties + fanning out to a large number of targets.
33 3) Complete implementation of thread-safety; specifically, make
34 assertions be reference counted objects (so that a cursor can
35 still refer to an assertion that gets removed from the graph).
42 #include "nsIOutputStream.h"
43 #include "nsIRDFDataSource.h"
44 #include "nsIRDFLiteral.h"
45 #include "nsIRDFNode.h"
46 #include "nsIRDFObserver.h"
47 #include "nsIRDFInMemoryDataSource.h"
48 #include "nsIRDFPropagatableDataSource.h"
49 #include "nsIRDFPurgeableDataSource.h"
50 #include "nsIRDFService.h"
51 #include "nsIServiceManager.h"
52 #include "nsISupportsArray.h"
53 #include "nsCOMArray.h"
54 #include "nsEnumeratorUtils.h"
58 #include "nsRDFBaseDataSources.h"
60 #include "nsReadableUtils.h"
61 #include "nsXPIDLString.h"
62 #include "nsFixedSizeAllocator.h"
69 #include "rdfIDataSource.h"
70 #include "rdfITripleVisitor.h"
73 static PRLogModuleInfo
* gLog
= nullptr;
77 // This struct is used as the slot value in the forward and reverse
80 // Assertion objects are reference counted, because each Assertion's
81 // ownership is shared between the datasource and any enumerators that
82 // are currently iterating over the datasource.
88 Create(nsFixedSizeAllocator
& aAllocator
,
89 nsIRDFResource
* aSource
,
90 nsIRDFResource
* aProperty
,
93 void* place
= aAllocator
.Alloc(sizeof(Assertion
));
95 ? ::new (place
) Assertion(aSource
, aProperty
, aTarget
, aTruthValue
)
98 Create(nsFixedSizeAllocator
& aAllocator
, nsIRDFResource
* aSource
) {
99 void* place
= aAllocator
.Alloc(sizeof(Assertion
));
101 ? ::new (place
) Assertion(aSource
)
105 Destroy(nsFixedSizeAllocator
& aAllocator
, Assertion
* aAssertion
) {
106 if (aAssertion
->mHashEntry
&& aAssertion
->u
.hash
.mPropertyHash
) {
107 PL_DHashTableEnumerate(aAssertion
->u
.hash
.mPropertyHash
,
108 DeletePropertyHashEntry
, &aAllocator
);
109 PL_DHashTableDestroy(aAssertion
->u
.hash
.mPropertyHash
);
110 aAssertion
->u
.hash
.mPropertyHash
= nullptr;
112 aAssertion
->~Assertion();
113 aAllocator
.Free(aAssertion
, sizeof(*aAssertion
)); }
115 static PLDHashOperator
116 DeletePropertyHashEntry(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
117 PRUint32 aNumber
, void* aArg
);
119 Assertion(nsIRDFResource
* aSource
, // normal assertion
120 nsIRDFResource
* aProperty
,
123 Assertion(nsIRDFResource
* aSource
); // PLDHashTable assertion variant
128 if (mRefCnt
== PR_UINT16_MAX
) {
129 NS_WARNING("refcount overflow, leaking Assertion");
135 void Release(nsFixedSizeAllocator
& aAllocator
) {
136 if (mRefCnt
== PR_UINT16_MAX
) {
137 NS_WARNING("refcount overflow, leaking Assertion");
141 Destroy(aAllocator
, this);
144 // For nsIRDFPurgeableDataSource
145 inline void Mark() { u
.as
.mMarked
= true; }
146 inline bool IsMarked() { return u
.as
.mMarked
; }
147 inline void Unmark() { u
.as
.mMarked
= false; }
149 // public for now, because I'm too lazy to go thru and clean this up.
151 // These are shared between hash/as (see the union below)
152 nsIRDFResource
* mSource
;
159 PLDHashTable
* mPropertyHash
;
163 nsIRDFResource
* mProperty
;
166 // make sure bool are final elements
172 // also shared between hash/as (see the union above)
173 // but placed after union definition to ensure that
174 // all 32-bit entries are long aligned
179 // Hide so that only Create() and Destroy() can be used to
180 // allocate and deallocate from the heap
181 static void* operator new(size_t) CPP_THROW_NEW
{ return 0; }
182 static void operator delete(void*, size_t) {}
187 PLDHashEntryHdr mHdr
;
189 Assertion
* mAssertions
;
193 Assertion::Assertion(nsIRDFResource
* aSource
)
199 MOZ_COUNT_CTOR(RDF_Assertion
);
203 u
.hash
.mPropertyHash
= PL_NewDHashTable(PL_DHashGetStubOps(),
204 nullptr, sizeof(Entry
), PL_DHASH_MIN_SIZE
);
207 Assertion::Assertion(nsIRDFResource
* aSource
,
208 nsIRDFResource
* aProperty
,
216 MOZ_COUNT_CTOR(RDF_Assertion
);
218 u
.as
.mProperty
= aProperty
;
219 u
.as
.mTarget
= aTarget
;
222 NS_ADDREF(u
.as
.mProperty
);
223 NS_ADDREF(u
.as
.mTarget
);
225 u
.as
.mInvNext
= nullptr;
226 u
.as
.mTruthValue
= aTruthValue
;
227 u
.as
.mMarked
= false;
230 Assertion::~Assertion()
232 MOZ_COUNT_DTOR(RDF_Assertion
);
235 fprintf(stdout
, "%d - RDF: Assertion\n", gInstanceCount
);
241 NS_RELEASE(u
.as
.mProperty
);
242 NS_RELEASE(u
.as
.mTarget
);
247 Assertion::DeletePropertyHashEntry(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
248 PRUint32 aNumber
, void* aArg
)
250 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
251 nsFixedSizeAllocator
* allocator
= static_cast<nsFixedSizeAllocator
*>(aArg
);
253 Assertion
* as
= entry
->mAssertions
;
255 Assertion
* doomed
= as
;
258 // Unlink, and release the datasource's reference.
259 doomed
->mNext
= doomed
->u
.as
.mInvNext
= nullptr;
260 doomed
->Release(*allocator
);
262 return PL_DHASH_NEXT
;
267 ////////////////////////////////////////////////////////////////////////
268 // InMemoryDataSource
269 class InMemoryArcsEnumeratorImpl
;
270 class InMemoryAssertionEnumeratorImpl
;
271 class InMemoryResourceEnumeratorImpl
;
273 class InMemoryDataSource
: public nsIRDFDataSource
,
274 public nsIRDFInMemoryDataSource
,
275 public nsIRDFPropagatableDataSource
,
276 public nsIRDFPurgeableDataSource
,
277 public rdfIDataSource
280 nsFixedSizeAllocator mAllocator
;
282 // These hash tables are keyed on pointers to nsIRDFResource
283 // objects (the nsIRDFService ensures that there is only ever one
284 // nsIRDFResource object per unique URI). The value of an entry is
285 // an Assertion struct, which is a linked list of (subject
286 // predicate object) triples.
287 PLDHashTable mForwardArcs
;
288 PLDHashTable mReverseArcs
;
290 nsCOMArray
<nsIRDFObserver
> mObservers
;
291 PRUint32 mNumObservers
;
293 // VisitFoo needs to block writes, [Un]Assert only allowed
294 // during mReadCount == 0
297 static PLDHashOperator
298 DeleteForwardArcsEntry(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
299 PRUint32 aNumber
, void* aArg
);
301 static PLDHashOperator
302 ResourceEnumerator(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
303 PRUint32 aNumber
, void* aArg
);
305 friend class InMemoryArcsEnumeratorImpl
;
306 friend class InMemoryAssertionEnumeratorImpl
;
307 friend class InMemoryResourceEnumeratorImpl
; // b/c it needs to enumerate mForwardArcs
309 // Thread-safe writer implementation methods.
311 LockedAssert(nsIRDFResource
* source
,
312 nsIRDFResource
* property
,
317 LockedUnassert(nsIRDFResource
* source
,
318 nsIRDFResource
* property
,
321 InMemoryDataSource(nsISupports
* aOuter
);
322 virtual ~InMemoryDataSource();
326 NS_NewRDFInMemoryDataSource(nsISupports
* aOuter
, const nsIID
& aIID
, void** aResult
);
329 NS_DECL_CYCLE_COLLECTING_AGGREGATED
330 NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource
)
332 // nsIRDFDataSource methods
333 NS_DECL_NSIRDFDATASOURCE
335 // nsIRDFInMemoryDataSource methods
336 NS_DECL_NSIRDFINMEMORYDATASOURCE
338 // nsIRDFPropagatableDataSource methods
339 NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
341 // nsIRDFPurgeableDataSource methods
342 NS_DECL_NSIRDFPURGEABLEDATASOURCE
344 // rdfIDataSource methods
345 NS_DECL_RDFIDATASOURCE
348 static PLDHashOperator
349 SweepForwardArcsEntries(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
350 PRUint32 aNumber
, void* aArg
);
353 // Implementation methods
355 GetForwardArcs(nsIRDFResource
* u
) {
356 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(&mForwardArcs
, u
, PL_DHASH_LOOKUP
);
357 return PL_DHASH_ENTRY_IS_BUSY(hdr
)
358 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
362 GetReverseArcs(nsIRDFNode
* v
) {
363 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(&mReverseArcs
, v
, PL_DHASH_LOOKUP
);
364 return PL_DHASH_ENTRY_IS_BUSY(hdr
)
365 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
369 SetForwardArcs(nsIRDFResource
* u
, Assertion
* as
) {
370 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(&mForwardArcs
, u
,
371 as
? PL_DHASH_ADD
: PL_DHASH_REMOVE
);
373 Entry
* entry
= reinterpret_cast<Entry
*>(hdr
);
375 entry
->mAssertions
= as
;
379 SetReverseArcs(nsIRDFNode
* v
, Assertion
* as
) {
380 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(&mReverseArcs
, v
,
381 as
? PL_DHASH_ADD
: PL_DHASH_REMOVE
);
383 Entry
* entry
= reinterpret_cast<Entry
*>(hdr
);
385 entry
->mAssertions
= as
;
390 LogOperation(const char* aOperation
,
391 nsIRDFResource
* asource
,
392 nsIRDFResource
* aProperty
,
394 bool aTruthValue
= true);
397 bool mPropagateChanges
;
400 //----------------------------------------------------------------------
402 // InMemoryAssertionEnumeratorImpl
406 * InMemoryAssertionEnumeratorImpl
408 class InMemoryAssertionEnumeratorImpl
: public nsISimpleEnumerator
411 InMemoryDataSource
* mDataSource
;
412 nsIRDFResource
* mSource
;
413 nsIRDFResource
* mProperty
;
417 Assertion
* mNextAssertion
;
418 nsCOMPtr
<nsISupportsArray
> mHashArcs
;
420 // Hide so that only Create() and Destroy() can be used to
421 // allocate and deallocate from the heap
422 static void* operator new(size_t) CPP_THROW_NEW
{ return 0; }
423 static void operator delete(void*, size_t) {}
425 InMemoryAssertionEnumeratorImpl(InMemoryDataSource
* aDataSource
,
426 nsIRDFResource
* aSource
,
427 nsIRDFResource
* aProperty
,
431 virtual ~InMemoryAssertionEnumeratorImpl();
434 static InMemoryAssertionEnumeratorImpl
*
435 Create(InMemoryDataSource
* aDataSource
,
436 nsIRDFResource
* aSource
,
437 nsIRDFResource
* aProperty
,
440 void* place
= aDataSource
->mAllocator
.Alloc(sizeof(InMemoryAssertionEnumeratorImpl
));
442 ? ::new (place
) InMemoryAssertionEnumeratorImpl(aDataSource
,
443 aSource
, aProperty
, aTarget
,
448 Destroy(InMemoryAssertionEnumeratorImpl
* aEnumerator
) {
449 // Keep the datasource alive for the duration of the stack
450 // frame so its allocator stays valid.
451 nsCOMPtr
<nsIRDFDataSource
> kungFuDeathGrip
= aEnumerator
->mDataSource
;
453 // Grab the pool from the datasource; since we keep the
454 // datasource alive, this has to be safe.
455 nsFixedSizeAllocator
& pool
= aEnumerator
->mDataSource
->mAllocator
;
456 aEnumerator
->~InMemoryAssertionEnumeratorImpl();
457 pool
.Free(aEnumerator
, sizeof(*aEnumerator
)); }
459 // nsISupports interface
462 // nsISimpleEnumerator interface
463 NS_DECL_NSISIMPLEENUMERATOR
466 ////////////////////////////////////////////////////////////////////////
469 InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
470 InMemoryDataSource
* aDataSource
,
471 nsIRDFResource
* aSource
,
472 nsIRDFResource
* aProperty
,
475 : mDataSource(aDataSource
),
477 mProperty(aProperty
),
480 mTruthValue(aTruthValue
),
481 mNextAssertion(nullptr)
483 NS_ADDREF(mDataSource
);
484 NS_IF_ADDREF(mSource
);
485 NS_ADDREF(mProperty
);
486 NS_IF_ADDREF(mTarget
);
489 mNextAssertion
= mDataSource
->GetForwardArcs(mSource
);
491 if (mNextAssertion
&& mNextAssertion
->mHashEntry
) {
492 // its our magical HASH_ENTRY forward hash for assertions
493 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(mNextAssertion
->u
.hash
.mPropertyHash
,
494 aProperty
, PL_DHASH_LOOKUP
);
495 mNextAssertion
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
496 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
501 mNextAssertion
= mDataSource
->GetReverseArcs(mTarget
);
504 // Add an owning reference from the enumerator
506 mNextAssertion
->AddRef();
509 InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
513 fprintf(stdout
, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount
);
517 mNextAssertion
->Release(mDataSource
->mAllocator
);
519 NS_IF_RELEASE(mDataSource
);
520 NS_IF_RELEASE(mSource
);
521 NS_IF_RELEASE(mProperty
);
522 NS_IF_RELEASE(mTarget
);
523 NS_IF_RELEASE(mValue
);
526 NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl
)
527 NS_IMPL_RELEASE_WITH_DESTROY(InMemoryAssertionEnumeratorImpl
, Destroy(this))
528 NS_IMPL_QUERY_INTERFACE1(InMemoryAssertionEnumeratorImpl
, nsISimpleEnumerator
)
531 InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult
)
538 while (mNextAssertion
) {
539 bool foundIt
= false;
540 if ((mProperty
== mNextAssertion
->u
.as
.mProperty
) &&
541 (mTruthValue
== mNextAssertion
->u
.as
.mTruthValue
)) {
543 mValue
= mNextAssertion
->u
.as
.mTarget
;
547 mValue
= mNextAssertion
->mSource
;
553 // Remember the last assertion we were holding on to
554 Assertion
* as
= mNextAssertion
;
557 mNextAssertion
= (mSource
) ? mNextAssertion
->mNext
: mNextAssertion
->u
.as
.mInvNext
;
559 // grab an owning reference from the enumerator to the next assertion
561 mNextAssertion
->AddRef();
563 // ...and release the reference from the enumerator to the old one.
564 as
->Release(mDataSource
->mAllocator
);
578 InMemoryAssertionEnumeratorImpl::GetNext(nsISupports
** aResult
)
583 rv
= HasMoreElements(&hasMore
);
584 if (NS_FAILED(rv
)) return rv
;
587 return NS_ERROR_UNEXPECTED
;
589 // Don't AddRef: we "transfer" ownership to the caller
596 ////////////////////////////////////////////////////////////////////////
600 * This class is a little bit bizarre in that it implements both the
601 * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
602 * Because the structure of the in-memory graph is pretty flexible, it's
603 * fairly easy to parameterize this class. The only funky thing to watch
604 * out for is the multiple inheritance clashes.
607 class InMemoryArcsEnumeratorImpl
: public nsISimpleEnumerator
610 // Hide so that only Create() and Destroy() can be used to
611 // allocate and deallocate from the heap
612 static void* operator new(size_t) CPP_THROW_NEW
{ return 0; }
613 static void operator delete(void*, size_t) {}
615 InMemoryDataSource
* mDataSource
;
616 nsIRDFResource
* mSource
;
618 nsAutoTArray
<nsCOMPtr
<nsIRDFResource
>, 8> mAlreadyReturned
;
619 nsIRDFResource
* mCurrent
;
620 Assertion
* mAssertion
;
621 nsCOMPtr
<nsISupportsArray
> mHashArcs
;
623 InMemoryArcsEnumeratorImpl(InMemoryDataSource
* aDataSource
,
624 nsIRDFResource
* aSource
,
625 nsIRDFNode
* aTarget
);
627 virtual ~InMemoryArcsEnumeratorImpl();
629 static PLDHashOperator
630 ArcEnumerator(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
631 PRUint32 aNumber
, void* aArg
);
634 // nsISupports interface
637 // nsISimpleEnumerator interface
638 NS_DECL_NSISIMPLEENUMERATOR
640 static InMemoryArcsEnumeratorImpl
*
641 Create(InMemoryDataSource
* aDataSource
,
642 nsIRDFResource
* aSource
,
643 nsIRDFNode
* aTarget
) {
644 void* place
= aDataSource
->mAllocator
.Alloc(sizeof(InMemoryArcsEnumeratorImpl
));
646 ? ::new (place
) InMemoryArcsEnumeratorImpl(aDataSource
, aSource
, aTarget
)
650 Destroy(InMemoryArcsEnumeratorImpl
* aEnumerator
) {
651 // Keep the datasource alive for the duration of the stack
652 // frame so its allocator stays valid.
653 nsCOMPtr
<nsIRDFDataSource
> kungFuDeathGrip
= aEnumerator
->mDataSource
;
655 // Grab the pool from the datasource; since we keep the
656 // datasource alive, this has to be safe.
657 nsFixedSizeAllocator
& pool
= aEnumerator
->mDataSource
->mAllocator
;
658 aEnumerator
->~InMemoryArcsEnumeratorImpl();
659 pool
.Free(aEnumerator
, sizeof(*aEnumerator
)); }
664 InMemoryArcsEnumeratorImpl::ArcEnumerator(PLDHashTable
* aTable
,
665 PLDHashEntryHdr
* aHdr
,
666 PRUint32 aNumber
, void* aArg
)
668 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
669 nsISupportsArray
* resources
= static_cast<nsISupportsArray
*>(aArg
);
671 resources
->AppendElement(entry
->mNode
);
672 return PL_DHASH_NEXT
;
676 InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource
* aDataSource
,
677 nsIRDFResource
* aSource
,
679 : mDataSource(aDataSource
),
684 NS_ADDREF(mDataSource
);
685 NS_IF_ADDREF(mSource
);
686 NS_IF_ADDREF(mTarget
);
689 // cast okay because it's a closed system
690 mAssertion
= mDataSource
->GetForwardArcs(mSource
);
692 if (mAssertion
&& mAssertion
->mHashEntry
) {
693 // its our magical HASH_ENTRY forward hash for assertions
694 nsresult rv
= NS_NewISupportsArray(getter_AddRefs(mHashArcs
));
695 if (NS_SUCCEEDED(rv
)) {
696 PL_DHashTableEnumerate(mAssertion
->u
.hash
.mPropertyHash
,
697 ArcEnumerator
, mHashArcs
.get());
699 mAssertion
= nullptr;
703 mAssertion
= mDataSource
->GetReverseArcs(mTarget
);
707 InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
711 fprintf(stdout
, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount
);
714 NS_RELEASE(mDataSource
);
715 NS_IF_RELEASE(mSource
);
716 NS_IF_RELEASE(mTarget
);
717 NS_IF_RELEASE(mCurrent
);
720 NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl
)
721 NS_IMPL_RELEASE_WITH_DESTROY(InMemoryArcsEnumeratorImpl
, Destroy(this))
722 NS_IMPL_QUERY_INTERFACE1(InMemoryArcsEnumeratorImpl
, nsISimpleEnumerator
)
725 InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult
)
727 NS_PRECONDITION(aResult
!= nullptr, "null ptr");
729 return NS_ERROR_NULL_POINTER
;
739 if (NS_FAILED(rv
= mHashArcs
->Count(&itemCount
))) return(rv
);
742 mCurrent
= static_cast<nsIRDFResource
*>
743 (mHashArcs
->ElementAt(itemCount
));
744 mHashArcs
->RemoveElementAt(itemCount
);
751 nsIRDFResource
* next
= mAssertion
->u
.as
.mProperty
;
753 // "next" is the property arc we are tentatively going to return
754 // in a subsequent GetNext() call. It is important to do two
755 // things, however, before that can happen:
756 // 1) Make sure it's not an arc we've already returned.
757 // 2) Make sure that |mAssertion| is not left pointing to
758 // another assertion that has the same property as this one.
759 // The first is a practical concern; the second a defense against
760 // an obscure crash and other erratic behavior. To ensure the
761 // second condition, skip down the chain until we find the next
762 // assertion with a property that doesn't match the current one.
763 // (All these assertions would be skipped via mAlreadyReturned
764 // checks anyways; this is even a bit faster.)
767 mAssertion
= (mSource
? mAssertion
->mNext
:
768 mAssertion
->u
.as
.mInvNext
);
770 while (mAssertion
&& (next
== mAssertion
->u
.as
.mProperty
));
772 bool alreadyReturned
= false;
773 for (PRInt32 i
= mAlreadyReturned
.Length() - 1; i
>= 0; --i
) {
774 if (mAlreadyReturned
[i
] == next
) {
775 alreadyReturned
= true;
780 if (! alreadyReturned
) {
794 InMemoryArcsEnumeratorImpl::GetNext(nsISupports
** aResult
)
799 rv
= HasMoreElements(&hasMore
);
800 if (NS_FAILED(rv
)) return rv
;
803 return NS_ERROR_UNEXPECTED
;
805 // Add this to the set of things we've already returned so that we
806 // can ensure uniqueness
807 mAlreadyReturned
.AppendElement(mCurrent
);
809 // Don't AddRef: we "transfer" ownership to the caller
817 ////////////////////////////////////////////////////////////////////////
818 // InMemoryDataSource
821 NS_NewRDFInMemoryDataSource(nsISupports
* aOuter
, const nsIID
& aIID
, void** aResult
)
823 NS_PRECONDITION(aResult
!= nullptr, "null ptr");
825 return NS_ERROR_NULL_POINTER
;
828 if (aOuter
&& !aIID
.Equals(NS_GET_IID(nsISupports
))) {
829 NS_ERROR("aggregation requires nsISupports");
830 return NS_ERROR_ILLEGAL_VALUE
;
833 InMemoryDataSource
* datasource
= new InMemoryDataSource(aOuter
);
835 return NS_ERROR_OUT_OF_MEMORY
;
836 NS_ADDREF(datasource
);
838 nsresult rv
= datasource
->Init();
839 if (NS_SUCCEEDED(rv
)) {
840 datasource
->fAggregated
.AddRef();
841 rv
= datasource
->AggregatedQueryInterface(aIID
, aResult
); // This'll AddRef()
842 datasource
->fAggregated
.Release();
845 NS_RELEASE(datasource
);
850 InMemoryDataSource::InMemoryDataSource(nsISupports
* aOuter
)
851 : mNumObservers(0), mReadCount(0)
853 NS_INIT_AGGREGATED(aOuter
);
855 static const size_t kBucketSizes
[] = {
858 sizeof(InMemoryArcsEnumeratorImpl
),
859 sizeof(InMemoryAssertionEnumeratorImpl
) };
861 static const PRInt32 kNumBuckets
= sizeof(kBucketSizes
) / sizeof(size_t);
863 // Per news://news.mozilla.org/39BEC105.5090206%40netscape.com
864 static const PRInt32 kInitialSize
= 1024;
866 mAllocator
.Init("nsInMemoryDataSource", kBucketSizes
, kNumBuckets
, kInitialSize
);
868 mForwardArcs
.ops
= nullptr;
869 mReverseArcs
.ops
= nullptr;
870 mPropagateChanges
= true;
875 InMemoryDataSource::Init()
877 if (!PL_DHashTableInit(&mForwardArcs
,
878 PL_DHashGetStubOps(),
881 PL_DHASH_MIN_SIZE
)) {
882 mForwardArcs
.ops
= nullptr;
883 return NS_ERROR_OUT_OF_MEMORY
;
885 if (!PL_DHashTableInit(&mReverseArcs
,
886 PL_DHashGetStubOps(),
889 PL_DHASH_MIN_SIZE
)) {
890 mReverseArcs
.ops
= nullptr;
891 return NS_ERROR_OUT_OF_MEMORY
;
896 gLog
= PR_NewLogModule("InMemoryDataSource");
903 InMemoryDataSource::~InMemoryDataSource()
907 fprintf(stdout
, "%d - RDF: InMemoryDataSource\n", gInstanceCount
);
910 if (mForwardArcs
.ops
) {
911 // This'll release all of the Assertion objects that are
912 // associated with this data source. We only need to do this
913 // for the forward arcs, because the reverse arcs table
914 // indexes the exact same set of resources.
915 PL_DHashTableEnumerate(&mForwardArcs
, DeleteForwardArcsEntry
, &mAllocator
);
916 PL_DHashTableFinish(&mForwardArcs
);
918 if (mReverseArcs
.ops
)
919 PL_DHashTableFinish(&mReverseArcs
);
921 PR_LOG(gLog
, PR_LOG_NOTICE
,
922 ("InMemoryDataSource(%p): destroyed.", this));
927 InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
928 PRUint32 aNumber
, void* aArg
)
930 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
931 nsFixedSizeAllocator
* allocator
= static_cast<nsFixedSizeAllocator
*>(aArg
);
933 Assertion
* as
= entry
->mAssertions
;
935 Assertion
* doomed
= as
;
938 // Unlink, and release the datasource's reference.
939 doomed
->mNext
= doomed
->u
.as
.mInvNext
= nullptr;
940 doomed
->Release(*allocator
);
942 return PL_DHASH_NEXT
;
946 ////////////////////////////////////////////////////////////////////////
948 NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource
)
949 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource
)
950 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mObservers
)
951 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
952 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource
)
953 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mObservers
)
954 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
956 NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource
)
957 NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource
)
958 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource
)
959 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource
)
960 NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource
)
961 NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource
)
962 NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource
)
963 NS_INTERFACE_MAP_ENTRY(rdfIDataSource
)
966 ////////////////////////////////////////////////////////////////////////
971 InMemoryDataSource::LogOperation(const char* aOperation
,
972 nsIRDFResource
* aSource
,
973 nsIRDFResource
* aProperty
,
977 if (! PR_LOG_TEST(gLog
, PR_LOG_NOTICE
))
981 aSource
->GetValue(getter_Copies(uri
));
983 ("InMemoryDataSource(%p): %s", this, aOperation
);
986 (" [(%p)%s]--", aSource
, (const char*) uri
);
988 aProperty
->GetValue(getter_Copies(uri
));
990 char tv
= (aTruthValue
? '-' : '!');
992 (" --%c[(%p)%s]--", tv
, aProperty
, (const char*) uri
);
994 nsCOMPtr
<nsIRDFResource
> resource
;
995 nsCOMPtr
<nsIRDFLiteral
> literal
;
997 if ((resource
= do_QueryInterface(aTarget
)) != nullptr) {
998 resource
->GetValue(getter_Copies(uri
));
1000 (" -->[(%p)%s]", aTarget
, (const char*) uri
);
1002 else if ((literal
= do_QueryInterface(aTarget
)) != nullptr) {
1003 nsXPIDLString value
;
1004 literal
->GetValue(getter_Copies(value
));
1005 nsAutoString
valueStr(value
);
1006 char* valueCStr
= ToNewCString(valueStr
);
1009 (" -->(\"%s\")\n", valueCStr
);
1015 (" -->(unknown-type)\n");
1022 InMemoryDataSource::GetURI(char* *uri
)
1024 NS_PRECONDITION(uri
!= nullptr, "null ptr");
1026 return NS_ERROR_NULL_POINTER
;
1033 InMemoryDataSource::GetSource(nsIRDFResource
* property
,
1036 nsIRDFResource
** source
)
1038 NS_PRECONDITION(source
!= nullptr, "null ptr");
1040 return NS_ERROR_NULL_POINTER
;
1042 NS_PRECONDITION(property
!= nullptr, "null ptr");
1044 return NS_ERROR_NULL_POINTER
;
1046 NS_PRECONDITION(target
!= nullptr, "null ptr");
1048 return NS_ERROR_NULL_POINTER
;
1050 for (Assertion
* as
= GetReverseArcs(target
); as
; as
= as
->u
.as
.mInvNext
) {
1051 if ((property
== as
->u
.as
.mProperty
) && (tv
== as
->u
.as
.mTruthValue
)) {
1052 *source
= as
->mSource
;
1058 return NS_RDF_NO_VALUE
;
1062 InMemoryDataSource::GetTarget(nsIRDFResource
* source
,
1063 nsIRDFResource
* property
,
1065 nsIRDFNode
** target
)
1067 NS_PRECONDITION(source
!= nullptr, "null ptr");
1069 return NS_ERROR_NULL_POINTER
;
1071 NS_PRECONDITION(property
!= nullptr, "null ptr");
1073 return NS_ERROR_NULL_POINTER
;
1075 NS_PRECONDITION(target
!= nullptr, "null ptr");
1077 return NS_ERROR_NULL_POINTER
;
1079 Assertion
*as
= GetForwardArcs(source
);
1080 if (as
&& as
->mHashEntry
) {
1081 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(as
->u
.hash
.mPropertyHash
, property
, PL_DHASH_LOOKUP
);
1082 Assertion
* val
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1083 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1086 if (tv
== val
->u
.as
.mTruthValue
) {
1087 *target
= val
->u
.as
.mTarget
;
1088 NS_IF_ADDREF(*target
);
1095 for (; as
!= nullptr; as
= as
->mNext
) {
1096 if ((property
== as
->u
.as
.mProperty
) && (tv
== (as
->u
.as
.mTruthValue
))) {
1097 *target
= as
->u
.as
.mTarget
;
1103 // If we get here, then there was no target with for the specified
1104 // property & truth value.
1106 return NS_RDF_NO_VALUE
;
1110 InMemoryDataSource::HasAssertion(nsIRDFResource
* source
,
1111 nsIRDFResource
* property
,
1117 return NS_ERROR_NULL_POINTER
;
1120 return NS_ERROR_NULL_POINTER
;
1123 return NS_ERROR_NULL_POINTER
;
1125 Assertion
*as
= GetForwardArcs(source
);
1126 if (as
&& as
->mHashEntry
) {
1127 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(as
->u
.hash
.mPropertyHash
, property
, PL_DHASH_LOOKUP
);
1128 Assertion
* val
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1129 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1132 if ((val
->u
.as
.mTarget
== target
) && (tv
== (val
->u
.as
.mTruthValue
))) {
1133 *hasAssertion
= true;
1140 for (; as
!= nullptr; as
= as
->mNext
) {
1141 // check target first as its most unique
1142 if (target
!= as
->u
.as
.mTarget
)
1145 if (property
!= as
->u
.as
.mProperty
)
1148 if (tv
!= (as
->u
.as
.mTruthValue
))
1152 *hasAssertion
= true;
1156 // If we get here, we couldn't find the assertion
1157 *hasAssertion
= false;
1162 InMemoryDataSource::GetSources(nsIRDFResource
* aProperty
,
1163 nsIRDFNode
* aTarget
,
1165 nsISimpleEnumerator
** aResult
)
1167 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1169 return NS_ERROR_NULL_POINTER
;
1171 NS_PRECONDITION(aTarget
!= nullptr, "null ptr");
1173 return NS_ERROR_NULL_POINTER
;
1175 NS_PRECONDITION(aResult
!= nullptr, "null ptr");
1177 return NS_ERROR_NULL_POINTER
;
1179 InMemoryAssertionEnumeratorImpl
* result
=
1180 InMemoryAssertionEnumeratorImpl::Create(this, nullptr, aProperty
,
1181 aTarget
, aTruthValue
);
1184 return NS_ERROR_OUT_OF_MEMORY
;
1193 InMemoryDataSource::GetTargets(nsIRDFResource
* aSource
,
1194 nsIRDFResource
* aProperty
,
1196 nsISimpleEnumerator
** aResult
)
1198 NS_PRECONDITION(aSource
!= nullptr, "null ptr");
1200 return NS_ERROR_NULL_POINTER
;
1202 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1204 return NS_ERROR_NULL_POINTER
;
1206 NS_PRECONDITION(aResult
!= nullptr, "null ptr");
1208 return NS_ERROR_NULL_POINTER
;
1210 InMemoryAssertionEnumeratorImpl
* result
=
1211 InMemoryAssertionEnumeratorImpl::Create(this, aSource
, aProperty
,
1212 nullptr, aTruthValue
);
1215 return NS_ERROR_OUT_OF_MEMORY
;
1225 InMemoryDataSource::LockedAssert(nsIRDFResource
* aSource
,
1226 nsIRDFResource
* aProperty
,
1227 nsIRDFNode
* aTarget
,
1231 LogOperation("ASSERT", aSource
, aProperty
, aTarget
, aTruthValue
);
1234 Assertion
* next
= GetForwardArcs(aSource
);
1235 Assertion
* prev
= next
;
1236 Assertion
* as
= nullptr;
1238 bool haveHash
= (next
) ? next
->mHashEntry
: false;
1240 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(next
->u
.hash
.mPropertyHash
, aProperty
, PL_DHASH_LOOKUP
);
1241 Assertion
* val
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1242 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1245 if (val
->u
.as
.mTarget
== aTarget
) {
1246 // Wow, we already had the assertion. Make sure that the
1247 // truth values are correct and bail.
1248 val
->u
.as
.mTruthValue
= aTruthValue
;
1257 // check target first as its most unique
1258 if (aTarget
== next
->u
.as
.mTarget
) {
1259 if (aProperty
== next
->u
.as
.mProperty
) {
1260 // Wow, we already had the assertion. Make sure that the
1261 // truth values are correct and bail.
1262 next
->u
.as
.mTruthValue
= aTruthValue
;
1272 as
= Assertion::Create(mAllocator
, aSource
, aProperty
, aTarget
, aTruthValue
);
1274 return NS_ERROR_OUT_OF_MEMORY
;
1276 // Add the datasource's owning reference.
1281 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(next
->u
.hash
.mPropertyHash
,
1282 aProperty
, PL_DHASH_LOOKUP
);
1283 Assertion
*asRef
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1284 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1288 as
->mNext
= asRef
->mNext
;
1293 hdr
= PL_DHashTableOperate(next
->u
.hash
.mPropertyHash
,
1294 aProperty
, PL_DHASH_ADD
);
1297 Entry
* entry
= reinterpret_cast<Entry
*>(hdr
);
1298 entry
->mNode
= aProperty
;
1299 entry
->mAssertions
= as
;
1305 // Link it in to the "forward arcs" table
1307 SetForwardArcs(aSource
, as
);
1313 // Link it in to the "reverse arcs" table
1315 next
= GetReverseArcs(aTarget
);
1316 as
->u
.as
.mInvNext
= next
;
1318 SetReverseArcs(aTarget
, next
);
1324 InMemoryDataSource::Assert(nsIRDFResource
* aSource
,
1325 nsIRDFResource
* aProperty
,
1326 nsIRDFNode
* aTarget
,
1329 NS_PRECONDITION(aSource
!= nullptr, "null ptr");
1331 return NS_ERROR_NULL_POINTER
;
1333 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1335 return NS_ERROR_NULL_POINTER
;
1337 NS_PRECONDITION(aTarget
!= nullptr, "null ptr");
1339 return NS_ERROR_NULL_POINTER
;
1342 NS_WARNING("Writing to InMemoryDataSource during read\n");
1343 return NS_RDF_ASSERTION_REJECTED
;
1347 rv
= LockedAssert(aSource
, aProperty
, aTarget
, aTruthValue
);
1348 if (NS_FAILED(rv
)) return rv
;
1351 for (PRInt32 i
= (PRInt32
)mNumObservers
- 1; mPropagateChanges
&& i
>= 0; --i
) {
1352 nsIRDFObserver
* obs
= mObservers
[i
];
1354 // XXX this should never happen, but it does, and we can't figure out why.
1355 NS_ASSERTION(obs
, "observer array corrupted!");
1359 obs
->OnAssert(this, aSource
, aProperty
, aTarget
);
1360 // XXX ignore return value?
1363 return NS_RDF_ASSERTION_ACCEPTED
;
1368 InMemoryDataSource::LockedUnassert(nsIRDFResource
* aSource
,
1369 nsIRDFResource
* aProperty
,
1370 nsIRDFNode
* aTarget
)
1373 LogOperation("UNASSERT", aSource
, aProperty
, aTarget
);
1376 Assertion
* next
= GetForwardArcs(aSource
);
1377 Assertion
* prev
= next
;
1378 Assertion
* root
= next
;
1379 Assertion
* as
= nullptr;
1381 bool haveHash
= (next
) ? next
->mHashEntry
: false;
1383 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(next
->u
.hash
.mPropertyHash
,
1384 aProperty
, PL_DHASH_LOOKUP
);
1385 prev
= next
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1386 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1390 if (aTarget
== next
->u
.as
.mTarget
) {
1397 // We don't even have the assertion, so just bail.
1404 PL_DHashTableRawRemove(root
->u
.hash
.mPropertyHash
, hdr
);
1406 if (next
&& next
->mNext
) {
1407 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(root
->u
.hash
.mPropertyHash
,
1408 aProperty
, PL_DHASH_ADD
);
1410 Entry
* entry
= reinterpret_cast<Entry
*>(hdr
);
1411 entry
->mNode
= aProperty
;
1412 entry
->mAssertions
= next
->mNext
;
1416 // If this second-level hash empties out, clean it up.
1417 if (!root
->u
.hash
.mPropertyHash
->entryCount
) {
1418 Assertion::Destroy(mAllocator
, root
);
1419 SetForwardArcs(aSource
, nullptr);
1424 prev
->mNext
= next
->mNext
;
1430 // check target first as its most unique
1431 if (aTarget
== next
->u
.as
.mTarget
) {
1432 if (aProperty
== next
->u
.as
.mProperty
) {
1434 SetForwardArcs(aSource
, next
->mNext
);
1436 prev
->mNext
= next
->mNext
;
1447 // We don't even have the assertion, so just bail.
1452 bool foundReverseArc
= false;
1455 next
= prev
= GetReverseArcs(aTarget
);
1459 SetReverseArcs(aTarget
, next
->u
.as
.mInvNext
);
1461 prev
->u
.as
.mInvNext
= next
->u
.as
.mInvNext
;
1464 foundReverseArc
= true;
1469 next
= next
->u
.as
.mInvNext
;
1473 NS_ASSERTION(foundReverseArc
, "in-memory db corrupted: unable to find reverse arc");
1476 // Unlink, and release the datasource's reference
1477 as
->mNext
= as
->u
.as
.mInvNext
= nullptr;
1478 as
->Release(mAllocator
);
1484 InMemoryDataSource::Unassert(nsIRDFResource
* aSource
,
1485 nsIRDFResource
* aProperty
,
1486 nsIRDFNode
* aTarget
)
1488 NS_PRECONDITION(aSource
!= nullptr, "null ptr");
1490 return NS_ERROR_NULL_POINTER
;
1492 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1494 return NS_ERROR_NULL_POINTER
;
1496 NS_PRECONDITION(aTarget
!= nullptr, "null ptr");
1498 return NS_ERROR_NULL_POINTER
;
1501 NS_WARNING("Writing to InMemoryDataSource during read\n");
1502 return NS_RDF_ASSERTION_REJECTED
;
1507 rv
= LockedUnassert(aSource
, aProperty
, aTarget
);
1508 if (NS_FAILED(rv
)) return rv
;
1511 for (PRInt32 i
= PRInt32(mNumObservers
) - 1; mPropagateChanges
&& i
>= 0; --i
) {
1512 nsIRDFObserver
* obs
= mObservers
[i
];
1514 // XXX this should never happen, but it does, and we can't figure out why.
1515 NS_ASSERTION(obs
, "observer array corrupted!");
1519 obs
->OnUnassert(this, aSource
, aProperty
, aTarget
);
1520 // XXX ignore return value?
1523 return NS_RDF_ASSERTION_ACCEPTED
;
1528 InMemoryDataSource::Change(nsIRDFResource
* aSource
,
1529 nsIRDFResource
* aProperty
,
1530 nsIRDFNode
* aOldTarget
,
1531 nsIRDFNode
* aNewTarget
)
1533 NS_PRECONDITION(aSource
!= nullptr, "null ptr");
1535 return NS_ERROR_NULL_POINTER
;
1537 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1539 return NS_ERROR_NULL_POINTER
;
1541 NS_PRECONDITION(aOldTarget
!= nullptr, "null ptr");
1543 return NS_ERROR_NULL_POINTER
;
1545 NS_PRECONDITION(aNewTarget
!= nullptr, "null ptr");
1547 return NS_ERROR_NULL_POINTER
;
1550 NS_WARNING("Writing to InMemoryDataSource during read\n");
1551 return NS_RDF_ASSERTION_REJECTED
;
1556 // XXX We can implement LockedChange() if we decide that this
1557 // is a performance bottleneck.
1559 rv
= LockedUnassert(aSource
, aProperty
, aOldTarget
);
1560 if (NS_FAILED(rv
)) return rv
;
1562 rv
= LockedAssert(aSource
, aProperty
, aNewTarget
, true);
1563 if (NS_FAILED(rv
)) return rv
;
1566 for (PRInt32 i
= PRInt32(mNumObservers
) - 1; mPropagateChanges
&& i
>= 0; --i
) {
1567 nsIRDFObserver
* obs
= mObservers
[i
];
1569 // XXX this should never happen, but it does, and we can't figure out why.
1570 NS_ASSERTION(obs
, "observer array corrupted!");
1574 obs
->OnChange(this, aSource
, aProperty
, aOldTarget
, aNewTarget
);
1575 // XXX ignore return value?
1578 return NS_RDF_ASSERTION_ACCEPTED
;
1583 InMemoryDataSource::Move(nsIRDFResource
* aOldSource
,
1584 nsIRDFResource
* aNewSource
,
1585 nsIRDFResource
* aProperty
,
1586 nsIRDFNode
* aTarget
)
1588 NS_PRECONDITION(aOldSource
!= nullptr, "null ptr");
1590 return NS_ERROR_NULL_POINTER
;
1592 NS_PRECONDITION(aNewSource
!= nullptr, "null ptr");
1594 return NS_ERROR_NULL_POINTER
;
1596 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1598 return NS_ERROR_NULL_POINTER
;
1600 NS_PRECONDITION(aTarget
!= nullptr, "null ptr");
1602 return NS_ERROR_NULL_POINTER
;
1605 NS_WARNING("Writing to InMemoryDataSource during read\n");
1606 return NS_RDF_ASSERTION_REJECTED
;
1611 // XXX We can implement LockedMove() if we decide that this
1612 // is a performance bottleneck.
1614 rv
= LockedUnassert(aOldSource
, aProperty
, aTarget
);
1615 if (NS_FAILED(rv
)) return rv
;
1617 rv
= LockedAssert(aNewSource
, aProperty
, aTarget
, true);
1618 if (NS_FAILED(rv
)) return rv
;
1621 for (PRInt32 i
= PRInt32(mNumObservers
) - 1; mPropagateChanges
&& i
>= 0; --i
) {
1622 nsIRDFObserver
* obs
= mObservers
[i
];
1624 // XXX this should never happen, but it does, and we can't figure out why.
1625 NS_ASSERTION(obs
, "observer array corrupted!");
1629 obs
->OnMove(this, aOldSource
, aNewSource
, aProperty
, aTarget
);
1630 // XXX ignore return value?
1633 return NS_RDF_ASSERTION_ACCEPTED
;
1638 InMemoryDataSource::AddObserver(nsIRDFObserver
* aObserver
)
1640 NS_PRECONDITION(aObserver
!= nullptr, "null ptr");
1642 return NS_ERROR_NULL_POINTER
;
1644 mObservers
.AppendObject(aObserver
);
1645 mNumObservers
= mObservers
.Count();
1651 InMemoryDataSource::RemoveObserver(nsIRDFObserver
* aObserver
)
1653 NS_PRECONDITION(aObserver
!= nullptr, "null ptr");
1655 return NS_ERROR_NULL_POINTER
;
1657 mObservers
.RemoveObject(aObserver
);
1658 // note: use Count() instead of just decrementing
1659 // in case aObserver wasn't in list, for example
1660 mNumObservers
= mObservers
.Count();
1666 InMemoryDataSource::HasArcIn(nsIRDFNode
*aNode
, nsIRDFResource
*aArc
, bool *result
)
1668 Assertion
* ass
= GetReverseArcs(aNode
);
1670 nsIRDFResource
* elbow
= ass
->u
.as
.mProperty
;
1671 if (elbow
== aArc
) {
1675 ass
= ass
->u
.as
.mInvNext
;
1682 InMemoryDataSource::HasArcOut(nsIRDFResource
*aSource
, nsIRDFResource
*aArc
, bool *result
)
1684 Assertion
* ass
= GetForwardArcs(aSource
);
1685 if (ass
&& ass
->mHashEntry
) {
1686 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(ass
->u
.hash
.mPropertyHash
,
1687 aArc
, PL_DHASH_LOOKUP
);
1688 Assertion
* val
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1689 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1698 nsIRDFResource
* elbow
= ass
->u
.as
.mProperty
;
1699 if (elbow
== aArc
) {
1710 InMemoryDataSource::ArcLabelsIn(nsIRDFNode
* aTarget
, nsISimpleEnumerator
** aResult
)
1712 NS_PRECONDITION(aTarget
!= nullptr, "null ptr");
1714 return NS_ERROR_NULL_POINTER
;
1716 InMemoryArcsEnumeratorImpl
* result
=
1717 InMemoryArcsEnumeratorImpl::Create(this, nullptr, aTarget
);
1720 return NS_ERROR_OUT_OF_MEMORY
;
1729 InMemoryDataSource::ArcLabelsOut(nsIRDFResource
* aSource
, nsISimpleEnumerator
** aResult
)
1731 NS_PRECONDITION(aSource
!= nullptr, "null ptr");
1733 return NS_ERROR_NULL_POINTER
;
1735 InMemoryArcsEnumeratorImpl
* result
=
1736 InMemoryArcsEnumeratorImpl::Create(this, aSource
, nullptr);
1739 return NS_ERROR_OUT_OF_MEMORY
;
1748 InMemoryDataSource::ResourceEnumerator(PLDHashTable
* aTable
,
1749 PLDHashEntryHdr
* aHdr
,
1750 PRUint32 aNumber
, void* aArg
)
1752 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
1753 nsISupportsArray
* resources
= static_cast<nsISupportsArray
*>(aArg
);
1755 resources
->AppendElement(entry
->mNode
);
1756 return PL_DHASH_NEXT
;
1761 InMemoryDataSource::GetAllResources(nsISimpleEnumerator
** aResult
)
1765 nsCOMPtr
<nsISupportsArray
> values
;
1766 rv
= NS_NewISupportsArray(getter_AddRefs(values
));
1767 if (NS_FAILED(rv
)) return rv
;
1769 // Enumerate all of our entries into an nsISupportsArray.
1770 PL_DHashTableEnumerate(&mForwardArcs
, ResourceEnumerator
, values
.get());
1772 return NS_NewArrayEnumerator(aResult
, values
);
1776 InMemoryDataSource::GetAllCmds(nsIRDFResource
* source
,
1777 nsISimpleEnumerator
/*<nsIRDFResource>*/** commands
)
1779 return(NS_NewEmptyEnumerator(commands
));
1783 InMemoryDataSource::IsCommandEnabled(nsISupportsArray
/*<nsIRDFResource>*/* aSources
,
1784 nsIRDFResource
* aCommand
,
1785 nsISupportsArray
/*<nsIRDFResource>*/* aArguments
,
1793 InMemoryDataSource::DoCommand(nsISupportsArray
/*<nsIRDFResource>*/* aSources
,
1794 nsIRDFResource
* aCommand
,
1795 nsISupportsArray
/*<nsIRDFResource>*/* aArguments
)
1801 InMemoryDataSource::BeginUpdateBatch()
1803 for (PRInt32 i
= PRInt32(mNumObservers
) - 1; mPropagateChanges
&& i
>= 0; --i
) {
1804 nsIRDFObserver
* obs
= mObservers
[i
];
1805 obs
->OnBeginUpdateBatch(this);
1811 InMemoryDataSource::EndUpdateBatch()
1813 for (PRInt32 i
= PRInt32(mNumObservers
) - 1; mPropagateChanges
&& i
>= 0; --i
) {
1814 nsIRDFObserver
* obs
= mObservers
[i
];
1815 obs
->OnEndUpdateBatch(this);
1822 ////////////////////////////////////////////////////////////////////////
1823 // nsIRDFInMemoryDataSource methods
1826 InMemoryDataSource::EnsureFastContainment(nsIRDFResource
* aSource
)
1828 Assertion
*as
= GetForwardArcs(aSource
);
1829 bool haveHash
= (as
) ? as
->mHashEntry
: false;
1831 // if its already a hash, then nothing to do
1832 if (haveHash
) return(NS_OK
);
1834 // convert aSource in forward hash into a hash
1835 Assertion
*hashAssertion
= Assertion::Create(mAllocator
, aSource
);
1836 NS_ASSERTION(hashAssertion
, "unable to Assertion::Create");
1837 if (!hashAssertion
) return(NS_ERROR_OUT_OF_MEMORY
);
1839 // Add the datasource's owning reference.
1840 hashAssertion
->AddRef();
1842 register Assertion
*first
= GetForwardArcs(aSource
);
1843 SetForwardArcs(aSource
, hashAssertion
);
1845 // mutate references of existing forward assertions into this hash
1846 PLDHashTable
*table
= hashAssertion
->u
.hash
.mPropertyHash
;
1849 nextRef
= first
->mNext
;
1850 nsIRDFResource
*prop
= first
->u
.as
.mProperty
;
1852 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(table
,
1853 prop
, PL_DHASH_LOOKUP
);
1854 Assertion
* val
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1855 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1858 first
->mNext
= val
->mNext
;
1862 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(table
,
1863 prop
, PL_DHASH_ADD
);
1865 Entry
* entry
= reinterpret_cast<Entry
*>(hdr
);
1866 entry
->mNode
= prop
;
1867 entry
->mAssertions
= first
;
1868 first
->mNext
= nullptr;
1877 ////////////////////////////////////////////////////////////////////////
1878 // nsIRDFPropagatableDataSource methods
1880 InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges
)
1882 *aPropagateChanges
= mPropagateChanges
;
1887 InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges
)
1889 mPropagateChanges
= aPropagateChanges
;
1894 ////////////////////////////////////////////////////////////////////////
1895 // nsIRDFPurgeableDataSource methods
1898 InMemoryDataSource::Mark(nsIRDFResource
* aSource
,
1899 nsIRDFResource
* aProperty
,
1900 nsIRDFNode
* aTarget
,
1904 NS_PRECONDITION(aSource
!= nullptr, "null ptr");
1906 return NS_ERROR_NULL_POINTER
;
1908 NS_PRECONDITION(aProperty
!= nullptr, "null ptr");
1910 return NS_ERROR_NULL_POINTER
;
1912 NS_PRECONDITION(aTarget
!= nullptr, "null ptr");
1914 return NS_ERROR_NULL_POINTER
;
1916 Assertion
*as
= GetForwardArcs(aSource
);
1917 if (as
&& as
->mHashEntry
) {
1918 PLDHashEntryHdr
* hdr
= PL_DHashTableOperate(as
->u
.hash
.mPropertyHash
,
1919 aProperty
, PL_DHASH_LOOKUP
);
1920 Assertion
* val
= PL_DHASH_ENTRY_IS_BUSY(hdr
)
1921 ? reinterpret_cast<Entry
*>(hdr
)->mAssertions
1924 if ((val
->u
.as
.mTarget
== aTarget
) &&
1925 (aTruthValue
== (val
->u
.as
.mTruthValue
))) {
1927 // found it! so mark it.
1932 LogOperation("MARK", aSource
, aProperty
, aTarget
, aTruthValue
);
1940 else for (; as
!= nullptr; as
= as
->mNext
) {
1941 // check target first as its most unique
1942 if (aTarget
!= as
->u
.as
.mTarget
)
1945 if (aProperty
!= as
->u
.as
.mProperty
)
1948 if (aTruthValue
!= (as
->u
.as
.mTruthValue
))
1951 // found it! so mark it.
1956 LogOperation("MARK", aSource
, aProperty
, aTarget
, aTruthValue
);
1962 // If we get here, we couldn't find the assertion
1969 Assertion
* mUnassertList
;
1970 PLDHashTable
* mReverseArcs
;
1971 nsFixedSizeAllocator
* mAllocator
;
1975 InMemoryDataSource::Sweep()
1977 SweepInfo info
= { nullptr, &mReverseArcs
, &mAllocator
};
1979 // Remove all the assertions, but don't notify anyone.
1980 PL_DHashTableEnumerate(&mForwardArcs
, SweepForwardArcsEntries
, &info
);
1982 // Now do the notification.
1983 Assertion
* as
= info
.mUnassertList
;
1986 LogOperation("SWEEP", as
->mSource
, as
->u
.as
.mProperty
, as
->u
.as
.mTarget
, as
->u
.as
.mTruthValue
);
1988 if (!(as
->mHashEntry
))
1990 for (PRInt32 i
= PRInt32(mNumObservers
) - 1; mPropagateChanges
&& i
>= 0; --i
) {
1991 nsIRDFObserver
* obs
= mObservers
[i
];
1992 // XXXbz other loops over mObservers null-check |obs| here!
1993 obs
->OnUnassert(this, as
->mSource
, as
->u
.as
.mProperty
, as
->u
.as
.mTarget
);
1994 // XXX ignore return value?
1998 Assertion
* doomed
= as
;
2001 // Unlink, and release the datasource's reference
2002 doomed
->mNext
= doomed
->u
.as
.mInvNext
= nullptr;
2003 doomed
->Release(mAllocator
);
2011 InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable
* aTable
,
2012 PLDHashEntryHdr
* aHdr
,
2013 PRUint32 aNumber
, void* aArg
)
2015 PLDHashOperator result
= PL_DHASH_NEXT
;
2016 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
2017 SweepInfo
* info
= static_cast<SweepInfo
*>(aArg
);
2019 Assertion
* as
= entry
->mAssertions
;
2020 if (as
&& (as
->mHashEntry
))
2022 // Stuff in sub-hashes must be swept recursively (max depth: 1)
2023 PL_DHashTableEnumerate(as
->u
.hash
.mPropertyHash
,
2024 SweepForwardArcsEntries
, info
);
2026 // If the sub-hash is now empty, clean it up.
2027 if (!as
->u
.hash
.mPropertyHash
->entryCount
) {
2028 Assertion::Destroy(*info
->mAllocator
, as
);
2029 result
= PL_DHASH_REMOVE
;
2035 Assertion
* prev
= nullptr;
2037 if (as
->IsMarked()) {
2043 // remove from the list of assertions in the datasource
2044 Assertion
* next
= as
->mNext
;
2049 // it's the first one. update the hashtable entry.
2050 entry
->mAssertions
= next
;
2053 // remove from the reverse arcs
2054 PLDHashEntryHdr
* hdr
=
2055 PL_DHashTableOperate(info
->mReverseArcs
, as
->u
.as
.mTarget
, PL_DHASH_LOOKUP
);
2056 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr
), "no assertion in reverse arcs");
2058 Entry
* rentry
= reinterpret_cast<Entry
*>(hdr
);
2059 Assertion
* ras
= rentry
->mAssertions
;
2060 Assertion
* rprev
= nullptr;
2064 rprev
->u
.as
.mInvNext
= ras
->u
.as
.mInvNext
;
2067 // it's the first one. update the hashtable entry.
2068 rentry
->mAssertions
= ras
->u
.as
.mInvNext
;
2070 as
->u
.as
.mInvNext
= nullptr; // for my sanity.
2074 ras
= ras
->u
.as
.mInvNext
;
2077 // Wow, it was the _only_ one. Unhash it.
2078 if (! rentry
->mAssertions
)
2080 PL_DHashTableRawRemove(info
->mReverseArcs
, hdr
);
2083 // add to the list of assertions to unassert
2084 as
->mNext
= info
->mUnassertList
;
2085 info
->mUnassertList
= as
;
2087 // Advance to the next assertion
2092 // if no more assertions exist for this resource, then unhash it.
2093 if (! entry
->mAssertions
)
2094 result
= PL_DHASH_REMOVE
;
2099 ////////////////////////////////////////////////////////////////////////
2100 // rdfIDataSource methods
2102 class VisitorClosure
2105 VisitorClosure(rdfITripleVisitor
* aVisitor
) :
2109 rdfITripleVisitor
* mVisitor
;
2114 SubjectEnumerator(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
2115 PRUint32 aNumber
, void* aArg
) {
2116 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
2117 VisitorClosure
* closure
= static_cast<VisitorClosure
*>(aArg
);
2120 nsCOMPtr
<nsIRDFNode
> subject
= do_QueryInterface(entry
->mNode
, &rv
);
2121 NS_ENSURE_SUCCESS(rv
, PL_DHASH_NEXT
);
2123 closure
->mRv
= closure
->mVisitor
->Visit(subject
, nullptr, nullptr, true);
2124 if (NS_FAILED(closure
->mRv
) || closure
->mRv
== NS_RDF_STOP_VISIT
)
2125 return PL_DHASH_STOP
;
2127 return PL_DHASH_NEXT
;
2131 InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor
*aVisitor
)
2133 // Lock datasource against writes
2136 // Enumerate all of our entries into an nsISupportsArray.
2137 VisitorClosure
cls(aVisitor
);
2138 PL_DHashTableEnumerate(&mForwardArcs
, SubjectEnumerator
, &cls
);
2140 // Unlock datasource
2146 class TriplesInnerClosure
2149 TriplesInnerClosure(nsIRDFNode
* aSubject
, VisitorClosure
* aClosure
) :
2150 mSubject(aSubject
), mOuter(aClosure
) {}
2151 nsIRDFNode
* mSubject
;
2152 VisitorClosure
* mOuter
;
2156 TriplesInnerEnumerator(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
2157 PRUint32 aNumber
, void* aArg
) {
2158 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
2159 Assertion
* assertion
= entry
->mAssertions
;
2160 TriplesInnerClosure
* closure
=
2161 static_cast<TriplesInnerClosure
*>(aArg
);
2163 NS_ASSERTION(!assertion
->mHashEntry
, "shouldn't have to hashes");
2164 VisitorClosure
* cls
= closure
->mOuter
;
2165 cls
->mRv
= cls
->mVisitor
->Visit(closure
->mSubject
,
2166 assertion
->u
.as
.mProperty
,
2167 assertion
->u
.as
.mTarget
,
2168 assertion
->u
.as
.mTruthValue
);
2169 if (NS_FAILED(cls
->mRv
) || cls
->mRv
== NS_RDF_STOP_VISIT
) {
2170 return PL_DHASH_STOP
;
2172 assertion
= assertion
->mNext
;
2174 return PL_DHASH_NEXT
;
2177 TriplesEnumerator(PLDHashTable
* aTable
, PLDHashEntryHdr
* aHdr
,
2178 PRUint32 aNumber
, void* aArg
) {
2179 Entry
* entry
= reinterpret_cast<Entry
*>(aHdr
);
2180 VisitorClosure
* closure
= static_cast<VisitorClosure
*>(aArg
);
2183 nsCOMPtr
<nsIRDFNode
> subject
= do_QueryInterface(entry
->mNode
, &rv
);
2184 NS_ENSURE_SUCCESS(rv
, PL_DHASH_NEXT
);
2186 if (entry
->mAssertions
->mHashEntry
) {
2187 TriplesInnerClosure
cls(subject
, closure
);
2188 PL_DHashTableEnumerate(entry
->mAssertions
->u
.hash
.mPropertyHash
,
2189 TriplesInnerEnumerator
, &cls
);
2190 if (NS_FAILED(closure
->mRv
)) {
2191 return PL_DHASH_STOP
;
2193 return PL_DHASH_NEXT
;
2195 Assertion
* assertion
= entry
->mAssertions
;
2197 NS_ASSERTION(!assertion
->mHashEntry
, "shouldn't have to hashes");
2198 closure
->mRv
= closure
->mVisitor
->Visit(subject
,
2199 assertion
->u
.as
.mProperty
,
2200 assertion
->u
.as
.mTarget
,
2201 assertion
->u
.as
.mTruthValue
);
2202 if (NS_FAILED(closure
->mRv
) || closure
->mRv
== NS_RDF_STOP_VISIT
) {
2203 return PL_DHASH_STOP
;
2205 assertion
= assertion
->mNext
;
2207 return PL_DHASH_NEXT
;
2210 InMemoryDataSource::VisitAllTriples(rdfITripleVisitor
*aVisitor
)
2212 // Lock datasource against writes
2215 // Enumerate all of our entries into an nsISupportsArray.
2216 VisitorClosure
cls(aVisitor
);
2217 PL_DHashTableEnumerate(&mForwardArcs
, TriplesEnumerator
, &cls
);
2219 // Unlock datasource
2225 ////////////////////////////////////////////////////////////////////////