Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
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/.
6 *
7 *
8 * This Original Code has been modified by IBM Corporation.
9 * Modifications made by IBM described herein are
10 * Copyright (c) International Business Machines
11 * Corporation, 2000
12 *
13 * Modifications to Mozilla code or documentation
14 * identified per MPL Section 3.3
15 *
16 * Date Modified by Description of modification
17 * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
18 * use in OS2
19 */
21 /*
23 Implementation for an in-memory RDF data store.
25 TO DO
27 1) Instrument this code to gather space and time performance
28 characteristics.
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).
37 */
39 #include "nsAgg.h"
40 #include "nsCOMPtr.h"
41 #include "nscore.h"
42 #include "nsArrayEnumerator.h"
43 #include "nsIOutputStream.h"
44 #include "nsIRDFDataSource.h"
45 #include "nsIRDFLiteral.h"
46 #include "nsIRDFNode.h"
47 #include "nsIRDFObserver.h"
48 #include "nsIRDFInMemoryDataSource.h"
49 #include "nsIRDFPropagatableDataSource.h"
50 #include "nsIRDFPurgeableDataSource.h"
51 #include "nsIRDFService.h"
52 #include "nsIServiceManager.h"
53 #include "nsISupportsArray.h"
54 #include "nsCOMArray.h"
55 #include "nsEnumeratorUtils.h"
56 #include "nsTArray.h"
57 #include "nsCRT.h"
58 #include "nsRDFCID.h"
59 #include "nsRDFBaseDataSources.h"
60 #include "nsString.h"
61 #include "nsReadableUtils.h"
62 #include "nsXPIDLString.h"
63 #include "rdfutil.h"
64 #include "pldhash.h"
65 #include "plstr.h"
66 #include "prlog.h"
67 #include "rdf.h"
69 #include "rdfIDataSource.h"
70 #include "rdfITripleVisitor.h"
72 // This struct is used as the slot value in the forward and reverse
73 // arcs hash tables.
74 //
75 // Assertion objects are reference counted, because each Assertion's
76 // ownership is shared between the datasource and any enumerators that
77 // are currently iterating over the datasource.
78 //
79 class Assertion
80 {
81 public:
82 static PLDHashOperator
83 DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
84 uint32_t aNumber, void* aArg);
86 Assertion(nsIRDFResource* aSource, // normal assertion
87 nsIRDFResource* aProperty,
88 nsIRDFNode* aTarget,
89 bool aTruthValue);
90 Assertion(nsIRDFResource* aSource); // PLDHashTable assertion variant
92 ~Assertion();
94 void AddRef() {
95 if (mRefCnt == UINT16_MAX) {
96 NS_WARNING("refcount overflow, leaking Assertion");
97 return;
98 }
99 ++mRefCnt;
100 }
102 void Release() {
103 if (mRefCnt == UINT16_MAX) {
104 NS_WARNING("refcount overflow, leaking Assertion");
105 return;
106 }
107 if (--mRefCnt == 0)
108 delete this;
109 }
111 // For nsIRDFPurgeableDataSource
112 inline void Mark() { u.as.mMarked = true; }
113 inline bool IsMarked() { return u.as.mMarked; }
114 inline void Unmark() { u.as.mMarked = false; }
116 // public for now, because I'm too lazy to go thru and clean this up.
118 // These are shared between hash/as (see the union below)
119 nsIRDFResource* mSource;
120 Assertion* mNext;
122 union
123 {
124 struct hash
125 {
126 PLDHashTable* mPropertyHash;
127 } hash;
128 struct as
129 {
130 nsIRDFResource* mProperty;
131 nsIRDFNode* mTarget;
132 Assertion* mInvNext;
133 // make sure bool are final elements
134 bool mTruthValue;
135 bool mMarked;
136 } as;
137 } u;
139 // also shared between hash/as (see the union above)
140 // but placed after union definition to ensure that
141 // all 32-bit entries are long aligned
142 uint16_t mRefCnt;
143 bool mHashEntry;
144 };
147 struct Entry {
148 PLDHashEntryHdr mHdr;
149 nsIRDFNode* mNode;
150 Assertion* mAssertions;
151 };
154 Assertion::Assertion(nsIRDFResource* aSource)
155 : mSource(aSource),
156 mNext(nullptr),
157 mRefCnt(0),
158 mHashEntry(true)
159 {
160 MOZ_COUNT_CTOR(RDF_Assertion);
162 NS_ADDREF(mSource);
164 u.hash.mPropertyHash = PL_NewDHashTable(PL_DHashGetStubOps(),
165 nullptr, sizeof(Entry), PL_DHASH_MIN_SIZE);
166 }
168 Assertion::Assertion(nsIRDFResource* aSource,
169 nsIRDFResource* aProperty,
170 nsIRDFNode* aTarget,
171 bool aTruthValue)
172 : mSource(aSource),
173 mNext(nullptr),
174 mRefCnt(0),
175 mHashEntry(false)
176 {
177 MOZ_COUNT_CTOR(RDF_Assertion);
179 u.as.mProperty = aProperty;
180 u.as.mTarget = aTarget;
182 NS_ADDREF(mSource);
183 NS_ADDREF(u.as.mProperty);
184 NS_ADDREF(u.as.mTarget);
186 u.as.mInvNext = nullptr;
187 u.as.mTruthValue = aTruthValue;
188 u.as.mMarked = false;
189 }
191 Assertion::~Assertion()
192 {
193 if (mHashEntry && u.hash.mPropertyHash) {
194 PL_DHashTableEnumerate(u.hash.mPropertyHash, DeletePropertyHashEntry,
195 nullptr);
196 PL_DHashTableDestroy(u.hash.mPropertyHash);
197 u.hash.mPropertyHash = nullptr;
198 }
200 MOZ_COUNT_DTOR(RDF_Assertion);
201 #ifdef DEBUG_REFS
202 --gInstanceCount;
203 fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
204 #endif
206 NS_RELEASE(mSource);
207 if (!mHashEntry)
208 {
209 NS_RELEASE(u.as.mProperty);
210 NS_RELEASE(u.as.mTarget);
211 }
212 }
214 PLDHashOperator
215 Assertion::DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
216 uint32_t aNumber, void* aArg)
217 {
218 Entry* entry = reinterpret_cast<Entry*>(aHdr);
220 Assertion* as = entry->mAssertions;
221 while (as) {
222 Assertion* doomed = as;
223 as = as->mNext;
225 // Unlink, and release the datasource's reference.
226 doomed->mNext = doomed->u.as.mInvNext = nullptr;
227 doomed->Release();
228 }
229 return PL_DHASH_NEXT;
230 }
234 ////////////////////////////////////////////////////////////////////////
235 // InMemoryDataSource
236 class InMemoryArcsEnumeratorImpl;
237 class InMemoryAssertionEnumeratorImpl;
238 class InMemoryResourceEnumeratorImpl;
240 class InMemoryDataSource : public nsIRDFDataSource,
241 public nsIRDFInMemoryDataSource,
242 public nsIRDFPropagatableDataSource,
243 public nsIRDFPurgeableDataSource,
244 public rdfIDataSource
245 {
246 protected:
247 // These hash tables are keyed on pointers to nsIRDFResource
248 // objects (the nsIRDFService ensures that there is only ever one
249 // nsIRDFResource object per unique URI). The value of an entry is
250 // an Assertion struct, which is a linked list of (subject
251 // predicate object) triples.
252 PLDHashTable mForwardArcs;
253 PLDHashTable mReverseArcs;
255 nsCOMArray<nsIRDFObserver> mObservers;
256 uint32_t mNumObservers;
258 // VisitFoo needs to block writes, [Un]Assert only allowed
259 // during mReadCount == 0
260 uint32_t mReadCount;
262 static PLDHashOperator
263 DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
264 uint32_t aNumber, void* aArg);
266 static PLDHashOperator
267 ResourceEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
268 uint32_t aNumber, void* aArg);
270 friend class InMemoryArcsEnumeratorImpl;
271 friend class InMemoryAssertionEnumeratorImpl;
272 friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
274 // Thread-safe writer implementation methods.
275 nsresult
276 LockedAssert(nsIRDFResource* source,
277 nsIRDFResource* property,
278 nsIRDFNode* target,
279 bool tv);
281 nsresult
282 LockedUnassert(nsIRDFResource* source,
283 nsIRDFResource* property,
284 nsIRDFNode* target);
286 InMemoryDataSource(nsISupports* aOuter);
287 virtual ~InMemoryDataSource();
288 nsresult Init();
290 friend nsresult
291 NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
293 public:
294 NS_DECL_CYCLE_COLLECTING_AGGREGATED
295 NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
297 // nsIRDFDataSource methods
298 NS_DECL_NSIRDFDATASOURCE
300 // nsIRDFInMemoryDataSource methods
301 NS_DECL_NSIRDFINMEMORYDATASOURCE
303 // nsIRDFPropagatableDataSource methods
304 NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
306 // nsIRDFPurgeableDataSource methods
307 NS_DECL_NSIRDFPURGEABLEDATASOURCE
309 // rdfIDataSource methods
310 NS_DECL_RDFIDATASOURCE
312 protected:
313 static PLDHashOperator
314 SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
315 uint32_t aNumber, void* aArg);
317 public:
318 // Implementation methods
319 Assertion*
320 GetForwardArcs(nsIRDFResource* u) {
321 PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u, PL_DHASH_LOOKUP);
322 return PL_DHASH_ENTRY_IS_BUSY(hdr)
323 ? reinterpret_cast<Entry*>(hdr)->mAssertions
324 : nullptr; }
326 Assertion*
327 GetReverseArcs(nsIRDFNode* v) {
328 PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v, PL_DHASH_LOOKUP);
329 return PL_DHASH_ENTRY_IS_BUSY(hdr)
330 ? reinterpret_cast<Entry*>(hdr)->mAssertions
331 : nullptr; }
333 void
334 SetForwardArcs(nsIRDFResource* u, Assertion* as) {
335 PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u,
336 as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
337 if (as && hdr) {
338 Entry* entry = reinterpret_cast<Entry*>(hdr);
339 entry->mNode = u;
340 entry->mAssertions = as;
341 } }
343 void
344 SetReverseArcs(nsIRDFNode* v, Assertion* as) {
345 PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v,
346 as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
347 if (as && hdr) {
348 Entry* entry = reinterpret_cast<Entry*>(hdr);
349 entry->mNode = v;
350 entry->mAssertions = as;
351 } }
353 #ifdef PR_LOGGING
354 void
355 LogOperation(const char* aOperation,
356 nsIRDFResource* asource,
357 nsIRDFResource* aProperty,
358 nsIRDFNode* aTarget,
359 bool aTruthValue = true);
360 #endif
362 bool mPropagateChanges;
364 private:
365 #ifdef PR_LOGGING
366 static PRLogModuleInfo* gLog;
367 #endif
368 };
370 #ifdef PR_LOGGING
371 PRLogModuleInfo* InMemoryDataSource::gLog;
372 #endif
374 //----------------------------------------------------------------------
375 //
376 // InMemoryAssertionEnumeratorImpl
377 //
379 /**
380 * InMemoryAssertionEnumeratorImpl
381 */
382 class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
383 {
384 private:
385 InMemoryDataSource* mDataSource;
386 nsIRDFResource* mSource;
387 nsIRDFResource* mProperty;
388 nsIRDFNode* mTarget;
389 nsIRDFNode* mValue;
390 bool mTruthValue;
391 Assertion* mNextAssertion;
392 nsCOMPtr<nsISupportsArray> mHashArcs;
394 public:
395 InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
396 nsIRDFResource* aSource,
397 nsIRDFResource* aProperty,
398 nsIRDFNode* aTarget,
399 bool aTruthValue);
401 virtual ~InMemoryAssertionEnumeratorImpl();
403 // nsISupports interface
404 NS_DECL_ISUPPORTS
406 // nsISimpleEnumerator interface
407 NS_DECL_NSISIMPLEENUMERATOR
408 };
410 ////////////////////////////////////////////////////////////////////////
413 InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
414 InMemoryDataSource* aDataSource,
415 nsIRDFResource* aSource,
416 nsIRDFResource* aProperty,
417 nsIRDFNode* aTarget,
418 bool aTruthValue)
419 : mDataSource(aDataSource),
420 mSource(aSource),
421 mProperty(aProperty),
422 mTarget(aTarget),
423 mValue(nullptr),
424 mTruthValue(aTruthValue),
425 mNextAssertion(nullptr)
426 {
427 NS_ADDREF(mDataSource);
428 NS_IF_ADDREF(mSource);
429 NS_ADDREF(mProperty);
430 NS_IF_ADDREF(mTarget);
432 if (mSource) {
433 mNextAssertion = mDataSource->GetForwardArcs(mSource);
435 if (mNextAssertion && mNextAssertion->mHashEntry) {
436 // its our magical HASH_ENTRY forward hash for assertions
437 PLDHashEntryHdr* hdr = PL_DHashTableOperate(mNextAssertion->u.hash.mPropertyHash,
438 aProperty, PL_DHASH_LOOKUP);
439 mNextAssertion = PL_DHASH_ENTRY_IS_BUSY(hdr)
440 ? reinterpret_cast<Entry*>(hdr)->mAssertions
441 : nullptr;
442 }
443 }
444 else {
445 mNextAssertion = mDataSource->GetReverseArcs(mTarget);
446 }
448 // Add an owning reference from the enumerator
449 if (mNextAssertion)
450 mNextAssertion->AddRef();
451 }
453 InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
454 {
455 #ifdef DEBUG_REFS
456 --gInstanceCount;
457 fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
458 #endif
460 if (mNextAssertion)
461 mNextAssertion->Release();
463 NS_IF_RELEASE(mDataSource);
464 NS_IF_RELEASE(mSource);
465 NS_IF_RELEASE(mProperty);
466 NS_IF_RELEASE(mTarget);
467 NS_IF_RELEASE(mValue);
468 }
470 NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
471 NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl)
472 NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
474 NS_IMETHODIMP
475 InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
476 {
477 if (mValue) {
478 *aResult = true;
479 return NS_OK;
480 }
482 while (mNextAssertion) {
483 bool foundIt = false;
484 if ((mProperty == mNextAssertion->u.as.mProperty) &&
485 (mTruthValue == mNextAssertion->u.as.mTruthValue)) {
486 if (mSource) {
487 mValue = mNextAssertion->u.as.mTarget;
488 NS_ADDREF(mValue);
489 }
490 else {
491 mValue = mNextAssertion->mSource;
492 NS_ADDREF(mValue);
493 }
494 foundIt = true;
495 }
497 // Remember the last assertion we were holding on to
498 Assertion* as = mNextAssertion;
500 // iterate
501 mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
503 // grab an owning reference from the enumerator to the next assertion
504 if (mNextAssertion)
505 mNextAssertion->AddRef();
507 // ...and release the reference from the enumerator to the old one.
508 as->Release();
510 if (foundIt) {
511 *aResult = true;
512 return NS_OK;
513 }
514 }
516 *aResult = false;
517 return NS_OK;
518 }
521 NS_IMETHODIMP
522 InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
523 {
524 nsresult rv;
526 bool hasMore;
527 rv = HasMoreElements(&hasMore);
528 if (NS_FAILED(rv)) return rv;
530 if (! hasMore)
531 return NS_ERROR_UNEXPECTED;
533 // Don't AddRef: we "transfer" ownership to the caller
534 *aResult = mValue;
535 mValue = nullptr;
537 return NS_OK;
538 }
540 ////////////////////////////////////////////////////////////////////////
541 //
543 /**
544 * This class is a little bit bizarre in that it implements both the
545 * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
546 * Because the structure of the in-memory graph is pretty flexible, it's
547 * fairly easy to parameterize this class. The only funky thing to watch
548 * out for is the multiple inheritance clashes.
549 */
551 class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
552 {
553 private:
554 InMemoryDataSource* mDataSource;
555 nsIRDFResource* mSource;
556 nsIRDFNode* mTarget;
557 nsAutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned;
558 nsIRDFResource* mCurrent;
559 Assertion* mAssertion;
560 nsCOMPtr<nsISupportsArray> mHashArcs;
562 static PLDHashOperator
563 ArcEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
564 uint32_t aNumber, void* aArg);
566 public:
567 InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
568 nsIRDFResource* aSource,
569 nsIRDFNode* aTarget);
571 virtual ~InMemoryArcsEnumeratorImpl();
573 // nsISupports interface
574 NS_DECL_ISUPPORTS
576 // nsISimpleEnumerator interface
577 NS_DECL_NSISIMPLEENUMERATOR
578 };
581 PLDHashOperator
582 InMemoryArcsEnumeratorImpl::ArcEnumerator(PLDHashTable* aTable,
583 PLDHashEntryHdr* aHdr,
584 uint32_t aNumber, void* aArg)
585 {
586 Entry* entry = reinterpret_cast<Entry*>(aHdr);
587 nsISupportsArray* resources = static_cast<nsISupportsArray*>(aArg);
589 resources->AppendElement(entry->mNode);
590 return PL_DHASH_NEXT;
591 }
594 InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
595 nsIRDFResource* aSource,
596 nsIRDFNode* aTarget)
597 : mDataSource(aDataSource),
598 mSource(aSource),
599 mTarget(aTarget),
600 mCurrent(nullptr)
601 {
602 NS_ADDREF(mDataSource);
603 NS_IF_ADDREF(mSource);
604 NS_IF_ADDREF(mTarget);
606 if (mSource) {
607 // cast okay because it's a closed system
608 mAssertion = mDataSource->GetForwardArcs(mSource);
610 if (mAssertion && mAssertion->mHashEntry) {
611 // its our magical HASH_ENTRY forward hash for assertions
612 nsresult rv = NS_NewISupportsArray(getter_AddRefs(mHashArcs));
613 if (NS_SUCCEEDED(rv)) {
614 PL_DHashTableEnumerate(mAssertion->u.hash.mPropertyHash,
615 ArcEnumerator, mHashArcs.get());
616 }
617 mAssertion = nullptr;
618 }
619 }
620 else {
621 mAssertion = mDataSource->GetReverseArcs(mTarget);
622 }
623 }
625 InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
626 {
627 #ifdef DEBUG_REFS
628 --gInstanceCount;
629 fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
630 #endif
632 NS_RELEASE(mDataSource);
633 NS_IF_RELEASE(mSource);
634 NS_IF_RELEASE(mTarget);
635 NS_IF_RELEASE(mCurrent);
636 }
638 NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
639 NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl)
640 NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
642 NS_IMETHODIMP
643 InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult)
644 {
645 NS_PRECONDITION(aResult != nullptr, "null ptr");
646 if (! aResult)
647 return NS_ERROR_NULL_POINTER;
649 if (mCurrent) {
650 *aResult = true;
651 return NS_OK;
652 }
654 if (mHashArcs) {
655 uint32_t itemCount;
656 nsresult rv;
657 if (NS_FAILED(rv = mHashArcs->Count(&itemCount))) return(rv);
658 if (itemCount > 0) {
659 --itemCount;
660 nsCOMPtr<nsIRDFResource> tmp = do_QueryElementAt(mHashArcs, itemCount);
661 tmp.forget(&mCurrent);
662 mHashArcs->RemoveElementAt(itemCount);
663 *aResult = true;
664 return NS_OK;
665 }
666 }
667 else
668 while (mAssertion) {
669 nsIRDFResource* next = mAssertion->u.as.mProperty;
671 // "next" is the property arc we are tentatively going to return
672 // in a subsequent GetNext() call. It is important to do two
673 // things, however, before that can happen:
674 // 1) Make sure it's not an arc we've already returned.
675 // 2) Make sure that |mAssertion| is not left pointing to
676 // another assertion that has the same property as this one.
677 // The first is a practical concern; the second a defense against
678 // an obscure crash and other erratic behavior. To ensure the
679 // second condition, skip down the chain until we find the next
680 // assertion with a property that doesn't match the current one.
681 // (All these assertions would be skipped via mAlreadyReturned
682 // checks anyways; this is even a bit faster.)
684 do {
685 mAssertion = (mSource ? mAssertion->mNext :
686 mAssertion->u.as.mInvNext);
687 }
688 while (mAssertion && (next == mAssertion->u.as.mProperty));
690 bool alreadyReturned = false;
691 for (int32_t i = mAlreadyReturned.Length() - 1; i >= 0; --i) {
692 if (mAlreadyReturned[i] == next) {
693 alreadyReturned = true;
694 break;
695 }
696 }
698 if (! alreadyReturned) {
699 mCurrent = next;
700 NS_ADDREF(mCurrent);
701 *aResult = true;
702 return NS_OK;
703 }
704 }
706 *aResult = false;
707 return NS_OK;
708 }
711 NS_IMETHODIMP
712 InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
713 {
714 nsresult rv;
716 bool hasMore;
717 rv = HasMoreElements(&hasMore);
718 if (NS_FAILED(rv)) return rv;
720 if (! hasMore)
721 return NS_ERROR_UNEXPECTED;
723 // Add this to the set of things we've already returned so that we
724 // can ensure uniqueness
725 mAlreadyReturned.AppendElement(mCurrent);
727 // Don't AddRef: we "transfer" ownership to the caller
728 *aResult = mCurrent;
729 mCurrent = nullptr;
731 return NS_OK;
732 }
735 ////////////////////////////////////////////////////////////////////////
736 // InMemoryDataSource
738 nsresult
739 NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
740 {
741 NS_PRECONDITION(aResult != nullptr, "null ptr");
742 if (! aResult)
743 return NS_ERROR_NULL_POINTER;
744 *aResult = nullptr;
746 if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
747 NS_ERROR("aggregation requires nsISupports");
748 return NS_ERROR_ILLEGAL_VALUE;
749 }
751 InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
752 if (! datasource)
753 return NS_ERROR_OUT_OF_MEMORY;
754 NS_ADDREF(datasource);
756 nsresult rv = datasource->Init();
757 if (NS_SUCCEEDED(rv)) {
758 datasource->fAggregated.AddRef();
759 rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
760 datasource->fAggregated.Release();
761 }
763 NS_RELEASE(datasource);
764 return rv;
765 }
768 InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
769 : mNumObservers(0), mReadCount(0)
770 {
771 NS_INIT_AGGREGATED(aOuter);
773 mForwardArcs.ops = nullptr;
774 mReverseArcs.ops = nullptr;
775 mPropagateChanges = true;
776 MOZ_COUNT_CTOR(InMemoryDataSource);
777 }
780 nsresult
781 InMemoryDataSource::Init()
782 {
783 PL_DHashTableInit(&mForwardArcs,
784 PL_DHashGetStubOps(),
785 nullptr,
786 sizeof(Entry),
787 PL_DHASH_MIN_SIZE);
789 PL_DHashTableInit(&mReverseArcs,
790 PL_DHashGetStubOps(),
791 nullptr,
792 sizeof(Entry),
793 PL_DHASH_MIN_SIZE);
795 #ifdef PR_LOGGING
796 if (! gLog)
797 gLog = PR_NewLogModule("InMemoryDataSource");
798 #endif
800 return NS_OK;
801 }
804 InMemoryDataSource::~InMemoryDataSource()
805 {
806 #ifdef DEBUG_REFS
807 --gInstanceCount;
808 fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
809 #endif
811 if (mForwardArcs.ops) {
812 // This'll release all of the Assertion objects that are
813 // associated with this data source. We only need to do this
814 // for the forward arcs, because the reverse arcs table
815 // indexes the exact same set of resources.
816 PL_DHashTableEnumerate(&mForwardArcs, DeleteForwardArcsEntry, nullptr);
817 PL_DHashTableFinish(&mForwardArcs);
818 }
819 if (mReverseArcs.ops)
820 PL_DHashTableFinish(&mReverseArcs);
822 PR_LOG(gLog, PR_LOG_NOTICE,
823 ("InMemoryDataSource(%p): destroyed.", this));
825 MOZ_COUNT_DTOR(InMemoryDataSource);
826 }
828 PLDHashOperator
829 InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
830 uint32_t aNumber, void* aArg)
831 {
832 Entry* entry = reinterpret_cast<Entry*>(aHdr);
834 Assertion* as = entry->mAssertions;
835 while (as) {
836 Assertion* doomed = as;
837 as = as->mNext;
839 // Unlink, and release the datasource's reference.
840 doomed->mNext = doomed->u.as.mInvNext = nullptr;
841 doomed->Release();
842 }
843 return PL_DHASH_NEXT;
844 }
847 ////////////////////////////////////////////////////////////////////////
849 NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
851 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource)
852 NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
853 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
854 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
855 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
856 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
858 NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
859 NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
860 NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource)
861 NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
862 NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource)
863 NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource)
864 NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource)
865 NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
866 NS_INTERFACE_MAP_END
868 ////////////////////////////////////////////////////////////////////////
871 #ifdef PR_LOGGING
872 void
873 InMemoryDataSource::LogOperation(const char* aOperation,
874 nsIRDFResource* aSource,
875 nsIRDFResource* aProperty,
876 nsIRDFNode* aTarget,
877 bool aTruthValue)
878 {
879 if (! PR_LOG_TEST(gLog, PR_LOG_NOTICE))
880 return;
882 nsXPIDLCString uri;
883 aSource->GetValue(getter_Copies(uri));
884 PR_LogPrint
885 ("InMemoryDataSource(%p): %s", this, aOperation);
887 PR_LogPrint
888 (" [(%p)%s]--", aSource, (const char*) uri);
890 aProperty->GetValue(getter_Copies(uri));
892 char tv = (aTruthValue ? '-' : '!');
893 PR_LogPrint
894 (" --%c[(%p)%s]--", tv, aProperty, (const char*) uri);
896 nsCOMPtr<nsIRDFResource> resource;
897 nsCOMPtr<nsIRDFLiteral> literal;
899 if ((resource = do_QueryInterface(aTarget)) != nullptr) {
900 resource->GetValue(getter_Copies(uri));
901 PR_LogPrint
902 (" -->[(%p)%s]", aTarget, (const char*) uri);
903 }
904 else if ((literal = do_QueryInterface(aTarget)) != nullptr) {
905 nsXPIDLString value;
906 literal->GetValue(getter_Copies(value));
907 nsAutoString valueStr(value);
908 char* valueCStr = ToNewCString(valueStr);
910 PR_LogPrint
911 (" -->(\"%s\")\n", valueCStr);
913 NS_Free(valueCStr);
914 }
915 else {
916 PR_LogPrint
917 (" -->(unknown-type)\n");
918 }
919 }
920 #endif
923 NS_IMETHODIMP
924 InMemoryDataSource::GetURI(char* *uri)
925 {
926 NS_PRECONDITION(uri != nullptr, "null ptr");
927 if (! uri)
928 return NS_ERROR_NULL_POINTER;
930 *uri = nullptr;
931 return NS_OK;
932 }
934 NS_IMETHODIMP
935 InMemoryDataSource::GetSource(nsIRDFResource* property,
936 nsIRDFNode* target,
937 bool tv,
938 nsIRDFResource** source)
939 {
940 NS_PRECONDITION(source != nullptr, "null ptr");
941 if (! source)
942 return NS_ERROR_NULL_POINTER;
944 NS_PRECONDITION(property != nullptr, "null ptr");
945 if (! property)
946 return NS_ERROR_NULL_POINTER;
948 NS_PRECONDITION(target != nullptr, "null ptr");
949 if (! target)
950 return NS_ERROR_NULL_POINTER;
952 for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) {
953 if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) {
954 *source = as->mSource;
955 NS_ADDREF(*source);
956 return NS_OK;
957 }
958 }
959 *source = nullptr;
960 return NS_RDF_NO_VALUE;
961 }
963 NS_IMETHODIMP
964 InMemoryDataSource::GetTarget(nsIRDFResource* source,
965 nsIRDFResource* property,
966 bool tv,
967 nsIRDFNode** target)
968 {
969 NS_PRECONDITION(source != nullptr, "null ptr");
970 if (! source)
971 return NS_ERROR_NULL_POINTER;
973 NS_PRECONDITION(property != nullptr, "null ptr");
974 if (! property)
975 return NS_ERROR_NULL_POINTER;
977 NS_PRECONDITION(target != nullptr, "null ptr");
978 if (! target)
979 return NS_ERROR_NULL_POINTER;
981 Assertion *as = GetForwardArcs(source);
982 if (as && as->mHashEntry) {
983 PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
984 Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
985 ? reinterpret_cast<Entry*>(hdr)->mAssertions
986 : nullptr;
987 while (val) {
988 if (tv == val->u.as.mTruthValue) {
989 *target = val->u.as.mTarget;
990 NS_IF_ADDREF(*target);
991 return NS_OK;
992 }
993 val = val->mNext;
994 }
995 }
996 else
997 for (; as != nullptr; as = as->mNext) {
998 if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) {
999 *target = as->u.as.mTarget;
1000 NS_ADDREF(*target);
1001 return NS_OK;
1002 }
1003 }
1005 // If we get here, then there was no target with for the specified
1006 // property & truth value.
1007 *target = nullptr;
1008 return NS_RDF_NO_VALUE;
1009 }
1011 NS_IMETHODIMP
1012 InMemoryDataSource::HasAssertion(nsIRDFResource* source,
1013 nsIRDFResource* property,
1014 nsIRDFNode* target,
1015 bool tv,
1016 bool* hasAssertion)
1017 {
1018 if (! source)
1019 return NS_ERROR_NULL_POINTER;
1021 if (! property)
1022 return NS_ERROR_NULL_POINTER;
1024 if (! target)
1025 return NS_ERROR_NULL_POINTER;
1027 Assertion *as = GetForwardArcs(source);
1028 if (as && as->mHashEntry) {
1029 PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
1030 Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
1031 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1032 : nullptr;
1033 while (val) {
1034 if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) {
1035 *hasAssertion = true;
1036 return NS_OK;
1037 }
1038 val = val->mNext;
1039 }
1040 }
1041 else
1042 for (; as != nullptr; as = as->mNext) {
1043 // check target first as its most unique
1044 if (target != as->u.as.mTarget)
1045 continue;
1047 if (property != as->u.as.mProperty)
1048 continue;
1050 if (tv != (as->u.as.mTruthValue))
1051 continue;
1053 // found it!
1054 *hasAssertion = true;
1055 return NS_OK;
1056 }
1058 // If we get here, we couldn't find the assertion
1059 *hasAssertion = false;
1060 return NS_OK;
1061 }
1063 NS_IMETHODIMP
1064 InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
1065 nsIRDFNode* aTarget,
1066 bool aTruthValue,
1067 nsISimpleEnumerator** aResult)
1068 {
1069 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1070 if (! aProperty)
1071 return NS_ERROR_NULL_POINTER;
1073 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1074 if (! aTarget)
1075 return NS_ERROR_NULL_POINTER;
1077 NS_PRECONDITION(aResult != nullptr, "null ptr");
1078 if (! aResult)
1079 return NS_ERROR_NULL_POINTER;
1081 InMemoryAssertionEnumeratorImpl* result =
1082 new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty,
1083 aTarget, aTruthValue);
1085 if (! result)
1086 return NS_ERROR_OUT_OF_MEMORY;
1088 NS_ADDREF(result);
1089 *aResult = result;
1091 return NS_OK;
1092 }
1094 NS_IMETHODIMP
1095 InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
1096 nsIRDFResource* aProperty,
1097 bool aTruthValue,
1098 nsISimpleEnumerator** aResult)
1099 {
1100 NS_PRECONDITION(aSource != nullptr, "null ptr");
1101 if (! aSource)
1102 return NS_ERROR_NULL_POINTER;
1104 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1105 if (! aProperty)
1106 return NS_ERROR_NULL_POINTER;
1108 NS_PRECONDITION(aResult != nullptr, "null ptr");
1109 if (! aResult)
1110 return NS_ERROR_NULL_POINTER;
1112 InMemoryAssertionEnumeratorImpl* result =
1113 new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty,
1114 nullptr, aTruthValue);
1116 if (! result)
1117 return NS_ERROR_OUT_OF_MEMORY;
1119 NS_ADDREF(result);
1120 *aResult = result;
1122 return NS_OK;
1123 }
1126 nsresult
1127 InMemoryDataSource::LockedAssert(nsIRDFResource* aSource,
1128 nsIRDFResource* aProperty,
1129 nsIRDFNode* aTarget,
1130 bool aTruthValue)
1131 {
1132 #ifdef PR_LOGGING
1133 LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue);
1134 #endif
1136 Assertion* next = GetForwardArcs(aSource);
1137 Assertion* prev = next;
1138 Assertion* as = nullptr;
1140 bool haveHash = (next) ? next->mHashEntry : false;
1141 if (haveHash) {
1142 PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, aProperty, PL_DHASH_LOOKUP);
1143 Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
1144 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1145 : nullptr;
1146 while (val) {
1147 if (val->u.as.mTarget == aTarget) {
1148 // Wow, we already had the assertion. Make sure that the
1149 // truth values are correct and bail.
1150 val->u.as.mTruthValue = aTruthValue;
1151 return NS_OK;
1152 }
1153 val = val->mNext;
1154 }
1155 }
1156 else
1157 {
1158 while (next) {
1159 // check target first as its most unique
1160 if (aTarget == next->u.as.mTarget) {
1161 if (aProperty == next->u.as.mProperty) {
1162 // Wow, we already had the assertion. Make sure that the
1163 // truth values are correct and bail.
1164 next->u.as.mTruthValue = aTruthValue;
1165 return NS_OK;
1166 }
1167 }
1169 prev = next;
1170 next = next->mNext;
1171 }
1172 }
1174 as = new Assertion(aSource, aProperty, aTarget, aTruthValue);
1175 if (! as)
1176 return NS_ERROR_OUT_OF_MEMORY;
1178 // Add the datasource's owning reference.
1179 as->AddRef();
1181 if (haveHash)
1182 {
1183 PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
1184 aProperty, PL_DHASH_LOOKUP);
1185 Assertion *asRef = PL_DHASH_ENTRY_IS_BUSY(hdr)
1186 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1187 : nullptr;
1188 if (asRef)
1189 {
1190 as->mNext = asRef->mNext;
1191 asRef->mNext = as;
1192 }
1193 else
1194 {
1195 hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
1196 aProperty, PL_DHASH_ADD);
1197 if (hdr)
1198 {
1199 Entry* entry = reinterpret_cast<Entry*>(hdr);
1200 entry->mNode = aProperty;
1201 entry->mAssertions = as;
1202 }
1203 }
1204 }
1205 else
1206 {
1207 // Link it in to the "forward arcs" table
1208 if (!prev) {
1209 SetForwardArcs(aSource, as);
1210 } else {
1211 prev->mNext = as;
1212 }
1213 }
1215 // Link it in to the "reverse arcs" table
1217 next = GetReverseArcs(aTarget);
1218 as->u.as.mInvNext = next;
1219 next = as;
1220 SetReverseArcs(aTarget, next);
1222 return NS_OK;
1223 }
1225 NS_IMETHODIMP
1226 InMemoryDataSource::Assert(nsIRDFResource* aSource,
1227 nsIRDFResource* aProperty,
1228 nsIRDFNode* aTarget,
1229 bool aTruthValue)
1230 {
1231 NS_PRECONDITION(aSource != nullptr, "null ptr");
1232 if (! aSource)
1233 return NS_ERROR_NULL_POINTER;
1235 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1236 if (! aProperty)
1237 return NS_ERROR_NULL_POINTER;
1239 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1240 if (! aTarget)
1241 return NS_ERROR_NULL_POINTER;
1243 if (mReadCount) {
1244 NS_WARNING("Writing to InMemoryDataSource during read\n");
1245 return NS_RDF_ASSERTION_REJECTED;
1246 }
1248 nsresult rv;
1249 rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
1250 if (NS_FAILED(rv)) return rv;
1252 // notify observers
1253 for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
1254 nsIRDFObserver* obs = mObservers[i];
1256 // XXX this should never happen, but it does, and we can't figure out why.
1257 NS_ASSERTION(obs, "observer array corrupted!");
1258 if (! obs)
1259 continue;
1261 obs->OnAssert(this, aSource, aProperty, aTarget);
1262 // XXX ignore return value?
1263 }
1265 return NS_RDF_ASSERTION_ACCEPTED;
1266 }
1269 nsresult
1270 InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
1271 nsIRDFResource* aProperty,
1272 nsIRDFNode* aTarget)
1273 {
1274 #ifdef PR_LOGGING
1275 LogOperation("UNASSERT", aSource, aProperty, aTarget);
1276 #endif
1278 Assertion* next = GetForwardArcs(aSource);
1279 Assertion* prev = next;
1280 Assertion* root = next;
1281 Assertion* as = nullptr;
1283 bool haveHash = (next) ? next->mHashEntry : false;
1284 if (haveHash) {
1285 PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
1286 aProperty, PL_DHASH_LOOKUP);
1287 prev = next = PL_DHASH_ENTRY_IS_BUSY(hdr)
1288 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1289 : nullptr;
1290 bool first = true;
1291 while (next) {
1292 if (aTarget == next->u.as.mTarget) {
1293 break;
1294 }
1295 first = false;
1296 prev = next;
1297 next = next->mNext;
1298 }
1299 // We don't even have the assertion, so just bail.
1300 if (!next)
1301 return NS_OK;
1303 as = next;
1305 if (first) {
1306 PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr);
1308 if (next && next->mNext) {
1309 PLDHashEntryHdr* hdr = PL_DHashTableOperate(root->u.hash.mPropertyHash,
1310 aProperty, PL_DHASH_ADD);
1311 if (hdr) {
1312 Entry* entry = reinterpret_cast<Entry*>(hdr);
1313 entry->mNode = aProperty;
1314 entry->mAssertions = next->mNext;
1315 }
1316 }
1317 else {
1318 // If this second-level hash empties out, clean it up.
1319 if (!root->u.hash.mPropertyHash->entryCount) {
1320 delete root;
1321 SetForwardArcs(aSource, nullptr);
1322 }
1323 }
1324 }
1325 else {
1326 prev->mNext = next->mNext;
1327 }
1328 }
1329 else
1330 {
1331 while (next) {
1332 // check target first as its most unique
1333 if (aTarget == next->u.as.mTarget) {
1334 if (aProperty == next->u.as.mProperty) {
1335 if (prev == next) {
1336 SetForwardArcs(aSource, next->mNext);
1337 } else {
1338 prev->mNext = next->mNext;
1339 }
1340 as = next;
1341 break;
1342 }
1343 }
1345 prev = next;
1346 next = next->mNext;
1347 }
1348 }
1349 // We don't even have the assertion, so just bail.
1350 if (!as)
1351 return NS_OK;
1353 #ifdef DEBUG
1354 bool foundReverseArc = false;
1355 #endif
1357 next = prev = GetReverseArcs(aTarget);
1358 while (next) {
1359 if (next == as) {
1360 if (prev == next) {
1361 SetReverseArcs(aTarget, next->u.as.mInvNext);
1362 } else {
1363 prev->u.as.mInvNext = next->u.as.mInvNext;
1364 }
1365 #ifdef DEBUG
1366 foundReverseArc = true;
1367 #endif
1368 break;
1369 }
1370 prev = next;
1371 next = next->u.as.mInvNext;
1372 }
1374 #ifdef DEBUG
1375 NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
1376 #endif
1378 // Unlink, and release the datasource's reference
1379 as->mNext = as->u.as.mInvNext = nullptr;
1380 as->Release();
1382 return NS_OK;
1383 }
1385 NS_IMETHODIMP
1386 InMemoryDataSource::Unassert(nsIRDFResource* aSource,
1387 nsIRDFResource* aProperty,
1388 nsIRDFNode* aTarget)
1389 {
1390 NS_PRECONDITION(aSource != nullptr, "null ptr");
1391 if (! aSource)
1392 return NS_ERROR_NULL_POINTER;
1394 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1395 if (! aProperty)
1396 return NS_ERROR_NULL_POINTER;
1398 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1399 if (! aTarget)
1400 return NS_ERROR_NULL_POINTER;
1402 if (mReadCount) {
1403 NS_WARNING("Writing to InMemoryDataSource during read\n");
1404 return NS_RDF_ASSERTION_REJECTED;
1405 }
1407 nsresult rv;
1409 rv = LockedUnassert(aSource, aProperty, aTarget);
1410 if (NS_FAILED(rv)) return rv;
1412 // Notify the world
1413 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1414 nsIRDFObserver* obs = mObservers[i];
1416 // XXX this should never happen, but it does, and we can't figure out why.
1417 NS_ASSERTION(obs, "observer array corrupted!");
1418 if (! obs)
1419 continue;
1421 obs->OnUnassert(this, aSource, aProperty, aTarget);
1422 // XXX ignore return value?
1423 }
1425 return NS_RDF_ASSERTION_ACCEPTED;
1426 }
1429 NS_IMETHODIMP
1430 InMemoryDataSource::Change(nsIRDFResource* aSource,
1431 nsIRDFResource* aProperty,
1432 nsIRDFNode* aOldTarget,
1433 nsIRDFNode* aNewTarget)
1434 {
1435 NS_PRECONDITION(aSource != nullptr, "null ptr");
1436 if (! aSource)
1437 return NS_ERROR_NULL_POINTER;
1439 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1440 if (! aProperty)
1441 return NS_ERROR_NULL_POINTER;
1443 NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
1444 if (! aOldTarget)
1445 return NS_ERROR_NULL_POINTER;
1447 NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
1448 if (! aNewTarget)
1449 return NS_ERROR_NULL_POINTER;
1451 if (mReadCount) {
1452 NS_WARNING("Writing to InMemoryDataSource during read\n");
1453 return NS_RDF_ASSERTION_REJECTED;
1454 }
1456 nsresult rv;
1458 // XXX We can implement LockedChange() if we decide that this
1459 // is a performance bottleneck.
1461 rv = LockedUnassert(aSource, aProperty, aOldTarget);
1462 if (NS_FAILED(rv)) return rv;
1464 rv = LockedAssert(aSource, aProperty, aNewTarget, true);
1465 if (NS_FAILED(rv)) return rv;
1467 // Notify the world
1468 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1469 nsIRDFObserver* obs = mObservers[i];
1471 // XXX this should never happen, but it does, and we can't figure out why.
1472 NS_ASSERTION(obs, "observer array corrupted!");
1473 if (! obs)
1474 continue;
1476 obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
1477 // XXX ignore return value?
1478 }
1480 return NS_RDF_ASSERTION_ACCEPTED;
1481 }
1484 NS_IMETHODIMP
1485 InMemoryDataSource::Move(nsIRDFResource* aOldSource,
1486 nsIRDFResource* aNewSource,
1487 nsIRDFResource* aProperty,
1488 nsIRDFNode* aTarget)
1489 {
1490 NS_PRECONDITION(aOldSource != nullptr, "null ptr");
1491 if (! aOldSource)
1492 return NS_ERROR_NULL_POINTER;
1494 NS_PRECONDITION(aNewSource != nullptr, "null ptr");
1495 if (! aNewSource)
1496 return NS_ERROR_NULL_POINTER;
1498 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1499 if (! aProperty)
1500 return NS_ERROR_NULL_POINTER;
1502 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1503 if (! aTarget)
1504 return NS_ERROR_NULL_POINTER;
1506 if (mReadCount) {
1507 NS_WARNING("Writing to InMemoryDataSource during read\n");
1508 return NS_RDF_ASSERTION_REJECTED;
1509 }
1511 nsresult rv;
1513 // XXX We can implement LockedMove() if we decide that this
1514 // is a performance bottleneck.
1516 rv = LockedUnassert(aOldSource, aProperty, aTarget);
1517 if (NS_FAILED(rv)) return rv;
1519 rv = LockedAssert(aNewSource, aProperty, aTarget, true);
1520 if (NS_FAILED(rv)) return rv;
1522 // Notify the world
1523 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1524 nsIRDFObserver* obs = mObservers[i];
1526 // XXX this should never happen, but it does, and we can't figure out why.
1527 NS_ASSERTION(obs, "observer array corrupted!");
1528 if (! obs)
1529 continue;
1531 obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
1532 // XXX ignore return value?
1533 }
1535 return NS_RDF_ASSERTION_ACCEPTED;
1536 }
1539 NS_IMETHODIMP
1540 InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver)
1541 {
1542 NS_PRECONDITION(aObserver != nullptr, "null ptr");
1543 if (! aObserver)
1544 return NS_ERROR_NULL_POINTER;
1546 mObservers.AppendObject(aObserver);
1547 mNumObservers = mObservers.Count();
1549 return NS_OK;
1550 }
1552 NS_IMETHODIMP
1553 InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver)
1554 {
1555 NS_PRECONDITION(aObserver != nullptr, "null ptr");
1556 if (! aObserver)
1557 return NS_ERROR_NULL_POINTER;
1559 mObservers.RemoveObject(aObserver);
1560 // note: use Count() instead of just decrementing
1561 // in case aObserver wasn't in list, for example
1562 mNumObservers = mObservers.Count();
1564 return NS_OK;
1565 }
1567 NS_IMETHODIMP
1568 InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
1569 {
1570 Assertion* ass = GetReverseArcs(aNode);
1571 while (ass) {
1572 nsIRDFResource* elbow = ass->u.as.mProperty;
1573 if (elbow == aArc) {
1574 *result = true;
1575 return NS_OK;
1576 }
1577 ass = ass->u.as.mInvNext;
1578 }
1579 *result = false;
1580 return NS_OK;
1581 }
1583 NS_IMETHODIMP
1584 InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
1585 {
1586 Assertion* ass = GetForwardArcs(aSource);
1587 if (ass && ass->mHashEntry) {
1588 PLDHashEntryHdr* hdr = PL_DHashTableOperate(ass->u.hash.mPropertyHash,
1589 aArc, PL_DHASH_LOOKUP);
1590 Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
1591 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1592 : nullptr;
1593 if (val) {
1594 *result = true;
1595 return NS_OK;
1596 }
1597 ass = ass->mNext;
1598 }
1599 while (ass) {
1600 nsIRDFResource* elbow = ass->u.as.mProperty;
1601 if (elbow == aArc) {
1602 *result = true;
1603 return NS_OK;
1604 }
1605 ass = ass->mNext;
1606 }
1607 *result = false;
1608 return NS_OK;
1609 }
1611 NS_IMETHODIMP
1612 InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
1613 {
1614 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1615 if (! aTarget)
1616 return NS_ERROR_NULL_POINTER;
1618 InMemoryArcsEnumeratorImpl* result =
1619 new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget);
1621 if (! result)
1622 return NS_ERROR_OUT_OF_MEMORY;
1624 NS_ADDREF(result);
1625 *aResult = result;
1627 return NS_OK;
1628 }
1630 NS_IMETHODIMP
1631 InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
1632 {
1633 NS_PRECONDITION(aSource != nullptr, "null ptr");
1634 if (! aSource)
1635 return NS_ERROR_NULL_POINTER;
1637 InMemoryArcsEnumeratorImpl* result =
1638 new InMemoryArcsEnumeratorImpl(this, aSource, nullptr);
1640 if (! result)
1641 return NS_ERROR_OUT_OF_MEMORY;
1643 NS_ADDREF(result);
1644 *aResult = result;
1646 return NS_OK;
1647 }
1649 PLDHashOperator
1650 InMemoryDataSource::ResourceEnumerator(PLDHashTable* aTable,
1651 PLDHashEntryHdr* aHdr,
1652 uint32_t aNumber, void* aArg)
1653 {
1654 Entry* entry = reinterpret_cast<Entry*>(aHdr);
1655 static_cast<nsCOMArray<nsIRDFNode>*>(aArg)->AppendObject(entry->mNode);
1656 return PL_DHASH_NEXT;
1657 }
1660 NS_IMETHODIMP
1661 InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
1662 {
1663 nsCOMArray<nsIRDFNode> nodes;
1664 nodes.SetCapacity(mForwardArcs.entryCount);
1666 // Enumerate all of our entries into an nsCOMArray
1667 PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, &nodes);
1669 return NS_NewArrayEnumerator(aResult, nodes);
1670 }
1672 NS_IMETHODIMP
1673 InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
1674 nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
1675 {
1676 return(NS_NewEmptyEnumerator(commands));
1677 }
1679 NS_IMETHODIMP
1680 InMemoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1681 nsIRDFResource* aCommand,
1682 nsISupportsArray/*<nsIRDFResource>*/* aArguments,
1683 bool* aResult)
1684 {
1685 *aResult = false;
1686 return NS_OK;
1687 }
1689 NS_IMETHODIMP
1690 InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1691 nsIRDFResource* aCommand,
1692 nsISupportsArray/*<nsIRDFResource>*/* aArguments)
1693 {
1694 return NS_OK;
1695 }
1697 NS_IMETHODIMP
1698 InMemoryDataSource::BeginUpdateBatch()
1699 {
1700 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1701 nsIRDFObserver* obs = mObservers[i];
1702 obs->OnBeginUpdateBatch(this);
1703 }
1704 return NS_OK;
1705 }
1707 NS_IMETHODIMP
1708 InMemoryDataSource::EndUpdateBatch()
1709 {
1710 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1711 nsIRDFObserver* obs = mObservers[i];
1712 obs->OnEndUpdateBatch(this);
1713 }
1714 return NS_OK;
1715 }
1719 ////////////////////////////////////////////////////////////////////////
1720 // nsIRDFInMemoryDataSource methods
1722 NS_IMETHODIMP
1723 InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
1724 {
1725 Assertion *as = GetForwardArcs(aSource);
1726 bool haveHash = (as) ? as->mHashEntry : false;
1728 // if its already a hash, then nothing to do
1729 if (haveHash) return(NS_OK);
1731 // convert aSource in forward hash into a hash
1732 Assertion *hashAssertion = new Assertion(aSource);
1733 NS_ASSERTION(hashAssertion, "unable to create Assertion");
1734 if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY);
1736 // Add the datasource's owning reference.
1737 hashAssertion->AddRef();
1739 Assertion *first = GetForwardArcs(aSource);
1740 SetForwardArcs(aSource, hashAssertion);
1742 // mutate references of existing forward assertions into this hash
1743 PLDHashTable *table = hashAssertion->u.hash.mPropertyHash;
1744 Assertion *nextRef;
1745 while(first) {
1746 nextRef = first->mNext;
1747 nsIRDFResource *prop = first->u.as.mProperty;
1749 PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
1750 prop, PL_DHASH_LOOKUP);
1751 Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
1752 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1753 : nullptr;
1754 if (val) {
1755 first->mNext = val->mNext;
1756 val->mNext = first;
1757 }
1758 else {
1759 PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
1760 prop, PL_DHASH_ADD);
1761 if (hdr) {
1762 Entry* entry = reinterpret_cast<Entry*>(hdr);
1763 entry->mNode = prop;
1764 entry->mAssertions = first;
1765 first->mNext = nullptr;
1766 }
1767 }
1768 first = nextRef;
1769 }
1770 return(NS_OK);
1771 }
1774 ////////////////////////////////////////////////////////////////////////
1775 // nsIRDFPropagatableDataSource methods
1776 NS_IMETHODIMP
1777 InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
1778 {
1779 *aPropagateChanges = mPropagateChanges;
1780 return NS_OK;
1781 }
1783 NS_IMETHODIMP
1784 InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
1785 {
1786 mPropagateChanges = aPropagateChanges;
1787 return NS_OK;
1788 }
1791 ////////////////////////////////////////////////////////////////////////
1792 // nsIRDFPurgeableDataSource methods
1794 NS_IMETHODIMP
1795 InMemoryDataSource::Mark(nsIRDFResource* aSource,
1796 nsIRDFResource* aProperty,
1797 nsIRDFNode* aTarget,
1798 bool aTruthValue,
1799 bool* aDidMark)
1800 {
1801 NS_PRECONDITION(aSource != nullptr, "null ptr");
1802 if (! aSource)
1803 return NS_ERROR_NULL_POINTER;
1805 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1806 if (! aProperty)
1807 return NS_ERROR_NULL_POINTER;
1809 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1810 if (! aTarget)
1811 return NS_ERROR_NULL_POINTER;
1813 Assertion *as = GetForwardArcs(aSource);
1814 if (as && as->mHashEntry) {
1815 PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash,
1816 aProperty, PL_DHASH_LOOKUP);
1817 Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
1818 ? reinterpret_cast<Entry*>(hdr)->mAssertions
1819 : nullptr;
1820 while (val) {
1821 if ((val->u.as.mTarget == aTarget) &&
1822 (aTruthValue == (val->u.as.mTruthValue))) {
1824 // found it! so mark it.
1825 as->Mark();
1826 *aDidMark = true;
1828 #ifdef PR_LOGGING
1829 LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
1830 #endif
1832 return NS_OK;
1833 }
1834 val = val->mNext;
1835 }
1836 }
1837 else for (; as != nullptr; as = as->mNext) {
1838 // check target first as its most unique
1839 if (aTarget != as->u.as.mTarget)
1840 continue;
1842 if (aProperty != as->u.as.mProperty)
1843 continue;
1845 if (aTruthValue != (as->u.as.mTruthValue))
1846 continue;
1848 // found it! so mark it.
1849 as->Mark();
1850 *aDidMark = true;
1852 #ifdef PR_LOGGING
1853 LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
1854 #endif
1856 return NS_OK;
1857 }
1859 // If we get here, we couldn't find the assertion
1860 *aDidMark = false;
1861 return NS_OK;
1862 }
1865 struct SweepInfo {
1866 Assertion* mUnassertList;
1867 PLDHashTable* mReverseArcs;
1868 };
1870 NS_IMETHODIMP
1871 InMemoryDataSource::Sweep()
1872 {
1873 SweepInfo info = { nullptr, &mReverseArcs };
1875 // Remove all the assertions, but don't notify anyone.
1876 PL_DHashTableEnumerate(&mForwardArcs, SweepForwardArcsEntries, &info);
1878 // Now do the notification.
1879 Assertion* as = info.mUnassertList;
1880 while (as) {
1881 #ifdef PR_LOGGING
1882 LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue);
1883 #endif
1884 if (!(as->mHashEntry))
1885 {
1886 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1887 nsIRDFObserver* obs = mObservers[i];
1888 // XXXbz other loops over mObservers null-check |obs| here!
1889 obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);
1890 // XXX ignore return value?
1891 }
1892 }
1894 Assertion* doomed = as;
1895 as = as->mNext;
1897 // Unlink, and release the datasource's reference
1898 doomed->mNext = doomed->u.as.mInvNext = nullptr;
1899 doomed->Release();
1900 }
1902 return NS_OK;
1903 }
1906 PLDHashOperator
1907 InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
1908 PLDHashEntryHdr* aHdr,
1909 uint32_t aNumber, void* aArg)
1910 {
1911 PLDHashOperator result = PL_DHASH_NEXT;
1912 Entry* entry = reinterpret_cast<Entry*>(aHdr);
1913 SweepInfo* info = static_cast<SweepInfo*>(aArg);
1915 Assertion* as = entry->mAssertions;
1916 if (as && (as->mHashEntry))
1917 {
1918 // Stuff in sub-hashes must be swept recursively (max depth: 1)
1919 PL_DHashTableEnumerate(as->u.hash.mPropertyHash,
1920 SweepForwardArcsEntries, info);
1922 // If the sub-hash is now empty, clean it up.
1923 if (!as->u.hash.mPropertyHash->entryCount) {
1924 delete as;
1925 result = PL_DHASH_REMOVE;
1926 }
1928 return result;
1929 }
1931 Assertion* prev = nullptr;
1932 while (as) {
1933 if (as->IsMarked()) {
1934 prev = as;
1935 as->Unmark();
1936 as = as->mNext;
1937 }
1938 else {
1939 // remove from the list of assertions in the datasource
1940 Assertion* next = as->mNext;
1941 if (prev) {
1942 prev->mNext = next;
1943 }
1944 else {
1945 // it's the first one. update the hashtable entry.
1946 entry->mAssertions = next;
1947 }
1949 // remove from the reverse arcs
1950 PLDHashEntryHdr* hdr =
1951 PL_DHashTableOperate(info->mReverseArcs, as->u.as.mTarget, PL_DHASH_LOOKUP);
1952 NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr), "no assertion in reverse arcs");
1954 Entry* rentry = reinterpret_cast<Entry*>(hdr);
1955 Assertion* ras = rentry->mAssertions;
1956 Assertion* rprev = nullptr;
1957 while (ras) {
1958 if (ras == as) {
1959 if (rprev) {
1960 rprev->u.as.mInvNext = ras->u.as.mInvNext;
1961 }
1962 else {
1963 // it's the first one. update the hashtable entry.
1964 rentry->mAssertions = ras->u.as.mInvNext;
1965 }
1966 as->u.as.mInvNext = nullptr; // for my sanity.
1967 break;
1968 }
1969 rprev = ras;
1970 ras = ras->u.as.mInvNext;
1971 }
1973 // Wow, it was the _only_ one. Unhash it.
1974 if (! rentry->mAssertions)
1975 {
1976 PL_DHashTableRawRemove(info->mReverseArcs, hdr);
1977 }
1979 // add to the list of assertions to unassert
1980 as->mNext = info->mUnassertList;
1981 info->mUnassertList = as;
1983 // Advance to the next assertion
1984 as = next;
1985 }
1986 }
1988 // if no more assertions exist for this resource, then unhash it.
1989 if (! entry->mAssertions)
1990 result = PL_DHASH_REMOVE;
1992 return result;
1993 }
1995 ////////////////////////////////////////////////////////////////////////
1996 // rdfIDataSource methods
1998 class VisitorClosure
1999 {
2000 public:
2001 VisitorClosure(rdfITripleVisitor* aVisitor) :
2002 mVisitor(aVisitor),
2003 mRv(NS_OK)
2004 {}
2005 rdfITripleVisitor* mVisitor;
2006 nsresult mRv;
2007 };
2009 PLDHashOperator
2010 SubjectEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
2011 uint32_t aNumber, void* aArg) {
2012 Entry* entry = reinterpret_cast<Entry*>(aHdr);
2013 VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
2015 nsresult rv;
2016 nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
2017 NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
2019 closure->mRv = closure->mVisitor->Visit(subject, nullptr, nullptr, true);
2020 if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT)
2021 return PL_DHASH_STOP;
2023 return PL_DHASH_NEXT;
2024 }
2026 NS_IMETHODIMP
2027 InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
2028 {
2029 // Lock datasource against writes
2030 ++mReadCount;
2032 // Enumerate all of our entries into an nsISupportsArray.
2033 VisitorClosure cls(aVisitor);
2034 PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls);
2036 // Unlock datasource
2037 --mReadCount;
2039 return cls.mRv;
2040 }
2042 class TriplesInnerClosure
2043 {
2044 public:
2045 TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) :
2046 mSubject(aSubject), mOuter(aClosure) {}
2047 nsIRDFNode* mSubject;
2048 VisitorClosure* mOuter;
2049 };
2051 PLDHashOperator
2052 TriplesInnerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
2053 uint32_t aNumber, void* aArg) {
2054 Entry* entry = reinterpret_cast<Entry*>(aHdr);
2055 Assertion* assertion = entry->mAssertions;
2056 TriplesInnerClosure* closure =
2057 static_cast<TriplesInnerClosure*>(aArg);
2058 while (assertion) {
2059 NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
2060 VisitorClosure* cls = closure->mOuter;
2061 cls->mRv = cls->mVisitor->Visit(closure->mSubject,
2062 assertion->u.as.mProperty,
2063 assertion->u.as.mTarget,
2064 assertion->u.as.mTruthValue);
2065 if (NS_FAILED(cls->mRv) || cls->mRv == NS_RDF_STOP_VISIT) {
2066 return PL_DHASH_STOP;
2067 }
2068 assertion = assertion->mNext;
2069 }
2070 return PL_DHASH_NEXT;
2071 }
2072 PLDHashOperator
2073 TriplesEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
2074 uint32_t aNumber, void* aArg) {
2075 Entry* entry = reinterpret_cast<Entry*>(aHdr);
2076 VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
2078 nsresult rv;
2079 nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
2080 NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
2082 if (entry->mAssertions->mHashEntry) {
2083 TriplesInnerClosure cls(subject, closure);
2084 PL_DHashTableEnumerate(entry->mAssertions->u.hash.mPropertyHash,
2085 TriplesInnerEnumerator, &cls);
2086 if (NS_FAILED(closure->mRv)) {
2087 return PL_DHASH_STOP;
2088 }
2089 return PL_DHASH_NEXT;
2090 }
2091 Assertion* assertion = entry->mAssertions;
2092 while (assertion) {
2093 NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
2094 closure->mRv = closure->mVisitor->Visit(subject,
2095 assertion->u.as.mProperty,
2096 assertion->u.as.mTarget,
2097 assertion->u.as.mTruthValue);
2098 if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) {
2099 return PL_DHASH_STOP;
2100 }
2101 assertion = assertion->mNext;
2102 }
2103 return PL_DHASH_NEXT;
2104 }
2105 NS_IMETHODIMP
2106 InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor)
2107 {
2108 // Lock datasource against writes
2109 ++mReadCount;
2111 // Enumerate all of our entries into an nsISupportsArray.
2112 VisitorClosure cls(aVisitor);
2113 PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls);
2115 // Unlock datasource
2116 --mReadCount;
2118 return cls.mRv;
2119 }
2121 ////////////////////////////////////////////////////////////////////////