rdf/base/src/nsInMemoryDataSource.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:1d054ef27b74
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 */
20
21 /*
22
23 Implementation for an in-memory RDF data store.
24
25 TO DO
26
27 1) Instrument this code to gather space and time performance
28 characteristics.
29
30 2) Optimize lookups for datasources which have a small number
31 of properties + fanning out to a large number of targets.
32
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).
36
37 */
38
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"
68
69 #include "rdfIDataSource.h"
70 #include "rdfITripleVisitor.h"
71
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);
85
86 Assertion(nsIRDFResource* aSource, // normal assertion
87 nsIRDFResource* aProperty,
88 nsIRDFNode* aTarget,
89 bool aTruthValue);
90 Assertion(nsIRDFResource* aSource); // PLDHashTable assertion variant
91
92 ~Assertion();
93
94 void AddRef() {
95 if (mRefCnt == UINT16_MAX) {
96 NS_WARNING("refcount overflow, leaking Assertion");
97 return;
98 }
99 ++mRefCnt;
100 }
101
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 }
110
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; }
115
116 // public for now, because I'm too lazy to go thru and clean this up.
117
118 // These are shared between hash/as (see the union below)
119 nsIRDFResource* mSource;
120 Assertion* mNext;
121
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;
138
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 };
145
146
147 struct Entry {
148 PLDHashEntryHdr mHdr;
149 nsIRDFNode* mNode;
150 Assertion* mAssertions;
151 };
152
153
154 Assertion::Assertion(nsIRDFResource* aSource)
155 : mSource(aSource),
156 mNext(nullptr),
157 mRefCnt(0),
158 mHashEntry(true)
159 {
160 MOZ_COUNT_CTOR(RDF_Assertion);
161
162 NS_ADDREF(mSource);
163
164 u.hash.mPropertyHash = PL_NewDHashTable(PL_DHashGetStubOps(),
165 nullptr, sizeof(Entry), PL_DHASH_MIN_SIZE);
166 }
167
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);
178
179 u.as.mProperty = aProperty;
180 u.as.mTarget = aTarget;
181
182 NS_ADDREF(mSource);
183 NS_ADDREF(u.as.mProperty);
184 NS_ADDREF(u.as.mTarget);
185
186 u.as.mInvNext = nullptr;
187 u.as.mTruthValue = aTruthValue;
188 u.as.mMarked = false;
189 }
190
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 }
199
200 MOZ_COUNT_DTOR(RDF_Assertion);
201 #ifdef DEBUG_REFS
202 --gInstanceCount;
203 fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
204 #endif
205
206 NS_RELEASE(mSource);
207 if (!mHashEntry)
208 {
209 NS_RELEASE(u.as.mProperty);
210 NS_RELEASE(u.as.mTarget);
211 }
212 }
213
214 PLDHashOperator
215 Assertion::DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
216 uint32_t aNumber, void* aArg)
217 {
218 Entry* entry = reinterpret_cast<Entry*>(aHdr);
219
220 Assertion* as = entry->mAssertions;
221 while (as) {
222 Assertion* doomed = as;
223 as = as->mNext;
224
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 }
231
232
233
234 ////////////////////////////////////////////////////////////////////////
235 // InMemoryDataSource
236 class InMemoryArcsEnumeratorImpl;
237 class InMemoryAssertionEnumeratorImpl;
238 class InMemoryResourceEnumeratorImpl;
239
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;
254
255 nsCOMArray<nsIRDFObserver> mObservers;
256 uint32_t mNumObservers;
257
258 // VisitFoo needs to block writes, [Un]Assert only allowed
259 // during mReadCount == 0
260 uint32_t mReadCount;
261
262 static PLDHashOperator
263 DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
264 uint32_t aNumber, void* aArg);
265
266 static PLDHashOperator
267 ResourceEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
268 uint32_t aNumber, void* aArg);
269
270 friend class InMemoryArcsEnumeratorImpl;
271 friend class InMemoryAssertionEnumeratorImpl;
272 friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
273
274 // Thread-safe writer implementation methods.
275 nsresult
276 LockedAssert(nsIRDFResource* source,
277 nsIRDFResource* property,
278 nsIRDFNode* target,
279 bool tv);
280
281 nsresult
282 LockedUnassert(nsIRDFResource* source,
283 nsIRDFResource* property,
284 nsIRDFNode* target);
285
286 InMemoryDataSource(nsISupports* aOuter);
287 virtual ~InMemoryDataSource();
288 nsresult Init();
289
290 friend nsresult
291 NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
292
293 public:
294 NS_DECL_CYCLE_COLLECTING_AGGREGATED
295 NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
296
297 // nsIRDFDataSource methods
298 NS_DECL_NSIRDFDATASOURCE
299
300 // nsIRDFInMemoryDataSource methods
301 NS_DECL_NSIRDFINMEMORYDATASOURCE
302
303 // nsIRDFPropagatableDataSource methods
304 NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
305
306 // nsIRDFPurgeableDataSource methods
307 NS_DECL_NSIRDFPURGEABLEDATASOURCE
308
309 // rdfIDataSource methods
310 NS_DECL_RDFIDATASOURCE
311
312 protected:
313 static PLDHashOperator
314 SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
315 uint32_t aNumber, void* aArg);
316
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; }
325
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; }
332
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 } }
342
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 } }
352
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
361
362 bool mPropagateChanges;
363
364 private:
365 #ifdef PR_LOGGING
366 static PRLogModuleInfo* gLog;
367 #endif
368 };
369
370 #ifdef PR_LOGGING
371 PRLogModuleInfo* InMemoryDataSource::gLog;
372 #endif
373
374 //----------------------------------------------------------------------
375 //
376 // InMemoryAssertionEnumeratorImpl
377 //
378
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;
393
394 public:
395 InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
396 nsIRDFResource* aSource,
397 nsIRDFResource* aProperty,
398 nsIRDFNode* aTarget,
399 bool aTruthValue);
400
401 virtual ~InMemoryAssertionEnumeratorImpl();
402
403 // nsISupports interface
404 NS_DECL_ISUPPORTS
405
406 // nsISimpleEnumerator interface
407 NS_DECL_NSISIMPLEENUMERATOR
408 };
409
410 ////////////////////////////////////////////////////////////////////////
411
412
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);
431
432 if (mSource) {
433 mNextAssertion = mDataSource->GetForwardArcs(mSource);
434
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 }
447
448 // Add an owning reference from the enumerator
449 if (mNextAssertion)
450 mNextAssertion->AddRef();
451 }
452
453 InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
454 {
455 #ifdef DEBUG_REFS
456 --gInstanceCount;
457 fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
458 #endif
459
460 if (mNextAssertion)
461 mNextAssertion->Release();
462
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 }
469
470 NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
471 NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl)
472 NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
473
474 NS_IMETHODIMP
475 InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
476 {
477 if (mValue) {
478 *aResult = true;
479 return NS_OK;
480 }
481
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 }
496
497 // Remember the last assertion we were holding on to
498 Assertion* as = mNextAssertion;
499
500 // iterate
501 mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
502
503 // grab an owning reference from the enumerator to the next assertion
504 if (mNextAssertion)
505 mNextAssertion->AddRef();
506
507 // ...and release the reference from the enumerator to the old one.
508 as->Release();
509
510 if (foundIt) {
511 *aResult = true;
512 return NS_OK;
513 }
514 }
515
516 *aResult = false;
517 return NS_OK;
518 }
519
520
521 NS_IMETHODIMP
522 InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
523 {
524 nsresult rv;
525
526 bool hasMore;
527 rv = HasMoreElements(&hasMore);
528 if (NS_FAILED(rv)) return rv;
529
530 if (! hasMore)
531 return NS_ERROR_UNEXPECTED;
532
533 // Don't AddRef: we "transfer" ownership to the caller
534 *aResult = mValue;
535 mValue = nullptr;
536
537 return NS_OK;
538 }
539
540 ////////////////////////////////////////////////////////////////////////
541 //
542
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 */
550
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;
561
562 static PLDHashOperator
563 ArcEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
564 uint32_t aNumber, void* aArg);
565
566 public:
567 InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
568 nsIRDFResource* aSource,
569 nsIRDFNode* aTarget);
570
571 virtual ~InMemoryArcsEnumeratorImpl();
572
573 // nsISupports interface
574 NS_DECL_ISUPPORTS
575
576 // nsISimpleEnumerator interface
577 NS_DECL_NSISIMPLEENUMERATOR
578 };
579
580
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);
588
589 resources->AppendElement(entry->mNode);
590 return PL_DHASH_NEXT;
591 }
592
593
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);
605
606 if (mSource) {
607 // cast okay because it's a closed system
608 mAssertion = mDataSource->GetForwardArcs(mSource);
609
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 }
624
625 InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
626 {
627 #ifdef DEBUG_REFS
628 --gInstanceCount;
629 fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
630 #endif
631
632 NS_RELEASE(mDataSource);
633 NS_IF_RELEASE(mSource);
634 NS_IF_RELEASE(mTarget);
635 NS_IF_RELEASE(mCurrent);
636 }
637
638 NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
639 NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl)
640 NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
641
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;
648
649 if (mCurrent) {
650 *aResult = true;
651 return NS_OK;
652 }
653
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;
670
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.)
683
684 do {
685 mAssertion = (mSource ? mAssertion->mNext :
686 mAssertion->u.as.mInvNext);
687 }
688 while (mAssertion && (next == mAssertion->u.as.mProperty));
689
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 }
697
698 if (! alreadyReturned) {
699 mCurrent = next;
700 NS_ADDREF(mCurrent);
701 *aResult = true;
702 return NS_OK;
703 }
704 }
705
706 *aResult = false;
707 return NS_OK;
708 }
709
710
711 NS_IMETHODIMP
712 InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
713 {
714 nsresult rv;
715
716 bool hasMore;
717 rv = HasMoreElements(&hasMore);
718 if (NS_FAILED(rv)) return rv;
719
720 if (! hasMore)
721 return NS_ERROR_UNEXPECTED;
722
723 // Add this to the set of things we've already returned so that we
724 // can ensure uniqueness
725 mAlreadyReturned.AppendElement(mCurrent);
726
727 // Don't AddRef: we "transfer" ownership to the caller
728 *aResult = mCurrent;
729 mCurrent = nullptr;
730
731 return NS_OK;
732 }
733
734
735 ////////////////////////////////////////////////////////////////////////
736 // InMemoryDataSource
737
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;
745
746 if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
747 NS_ERROR("aggregation requires nsISupports");
748 return NS_ERROR_ILLEGAL_VALUE;
749 }
750
751 InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
752 if (! datasource)
753 return NS_ERROR_OUT_OF_MEMORY;
754 NS_ADDREF(datasource);
755
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 }
762
763 NS_RELEASE(datasource);
764 return rv;
765 }
766
767
768 InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
769 : mNumObservers(0), mReadCount(0)
770 {
771 NS_INIT_AGGREGATED(aOuter);
772
773 mForwardArcs.ops = nullptr;
774 mReverseArcs.ops = nullptr;
775 mPropagateChanges = true;
776 MOZ_COUNT_CTOR(InMemoryDataSource);
777 }
778
779
780 nsresult
781 InMemoryDataSource::Init()
782 {
783 PL_DHashTableInit(&mForwardArcs,
784 PL_DHashGetStubOps(),
785 nullptr,
786 sizeof(Entry),
787 PL_DHASH_MIN_SIZE);
788
789 PL_DHashTableInit(&mReverseArcs,
790 PL_DHashGetStubOps(),
791 nullptr,
792 sizeof(Entry),
793 PL_DHASH_MIN_SIZE);
794
795 #ifdef PR_LOGGING
796 if (! gLog)
797 gLog = PR_NewLogModule("InMemoryDataSource");
798 #endif
799
800 return NS_OK;
801 }
802
803
804 InMemoryDataSource::~InMemoryDataSource()
805 {
806 #ifdef DEBUG_REFS
807 --gInstanceCount;
808 fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
809 #endif
810
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);
821
822 PR_LOG(gLog, PR_LOG_NOTICE,
823 ("InMemoryDataSource(%p): destroyed.", this));
824
825 MOZ_COUNT_DTOR(InMemoryDataSource);
826 }
827
828 PLDHashOperator
829 InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
830 uint32_t aNumber, void* aArg)
831 {
832 Entry* entry = reinterpret_cast<Entry*>(aHdr);
833
834 Assertion* as = entry->mAssertions;
835 while (as) {
836 Assertion* doomed = as;
837 as = as->mNext;
838
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 }
845
846
847 ////////////////////////////////////////////////////////////////////////
848
849 NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
850
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
857
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
867
868 ////////////////////////////////////////////////////////////////////////
869
870
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;
881
882 nsXPIDLCString uri;
883 aSource->GetValue(getter_Copies(uri));
884 PR_LogPrint
885 ("InMemoryDataSource(%p): %s", this, aOperation);
886
887 PR_LogPrint
888 (" [(%p)%s]--", aSource, (const char*) uri);
889
890 aProperty->GetValue(getter_Copies(uri));
891
892 char tv = (aTruthValue ? '-' : '!');
893 PR_LogPrint
894 (" --%c[(%p)%s]--", tv, aProperty, (const char*) uri);
895
896 nsCOMPtr<nsIRDFResource> resource;
897 nsCOMPtr<nsIRDFLiteral> literal;
898
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);
909
910 PR_LogPrint
911 (" -->(\"%s\")\n", valueCStr);
912
913 NS_Free(valueCStr);
914 }
915 else {
916 PR_LogPrint
917 (" -->(unknown-type)\n");
918 }
919 }
920 #endif
921
922
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;
929
930 *uri = nullptr;
931 return NS_OK;
932 }
933
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;
943
944 NS_PRECONDITION(property != nullptr, "null ptr");
945 if (! property)
946 return NS_ERROR_NULL_POINTER;
947
948 NS_PRECONDITION(target != nullptr, "null ptr");
949 if (! target)
950 return NS_ERROR_NULL_POINTER;
951
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 }
962
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;
972
973 NS_PRECONDITION(property != nullptr, "null ptr");
974 if (! property)
975 return NS_ERROR_NULL_POINTER;
976
977 NS_PRECONDITION(target != nullptr, "null ptr");
978 if (! target)
979 return NS_ERROR_NULL_POINTER;
980
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 }
1004
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 }
1010
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;
1020
1021 if (! property)
1022 return NS_ERROR_NULL_POINTER;
1023
1024 if (! target)
1025 return NS_ERROR_NULL_POINTER;
1026
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;
1046
1047 if (property != as->u.as.mProperty)
1048 continue;
1049
1050 if (tv != (as->u.as.mTruthValue))
1051 continue;
1052
1053 // found it!
1054 *hasAssertion = true;
1055 return NS_OK;
1056 }
1057
1058 // If we get here, we couldn't find the assertion
1059 *hasAssertion = false;
1060 return NS_OK;
1061 }
1062
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;
1072
1073 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1074 if (! aTarget)
1075 return NS_ERROR_NULL_POINTER;
1076
1077 NS_PRECONDITION(aResult != nullptr, "null ptr");
1078 if (! aResult)
1079 return NS_ERROR_NULL_POINTER;
1080
1081 InMemoryAssertionEnumeratorImpl* result =
1082 new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty,
1083 aTarget, aTruthValue);
1084
1085 if (! result)
1086 return NS_ERROR_OUT_OF_MEMORY;
1087
1088 NS_ADDREF(result);
1089 *aResult = result;
1090
1091 return NS_OK;
1092 }
1093
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;
1103
1104 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1105 if (! aProperty)
1106 return NS_ERROR_NULL_POINTER;
1107
1108 NS_PRECONDITION(aResult != nullptr, "null ptr");
1109 if (! aResult)
1110 return NS_ERROR_NULL_POINTER;
1111
1112 InMemoryAssertionEnumeratorImpl* result =
1113 new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty,
1114 nullptr, aTruthValue);
1115
1116 if (! result)
1117 return NS_ERROR_OUT_OF_MEMORY;
1118
1119 NS_ADDREF(result);
1120 *aResult = result;
1121
1122 return NS_OK;
1123 }
1124
1125
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
1135
1136 Assertion* next = GetForwardArcs(aSource);
1137 Assertion* prev = next;
1138 Assertion* as = nullptr;
1139
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 }
1168
1169 prev = next;
1170 next = next->mNext;
1171 }
1172 }
1173
1174 as = new Assertion(aSource, aProperty, aTarget, aTruthValue);
1175 if (! as)
1176 return NS_ERROR_OUT_OF_MEMORY;
1177
1178 // Add the datasource's owning reference.
1179 as->AddRef();
1180
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 }
1214
1215 // Link it in to the "reverse arcs" table
1216
1217 next = GetReverseArcs(aTarget);
1218 as->u.as.mInvNext = next;
1219 next = as;
1220 SetReverseArcs(aTarget, next);
1221
1222 return NS_OK;
1223 }
1224
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;
1234
1235 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1236 if (! aProperty)
1237 return NS_ERROR_NULL_POINTER;
1238
1239 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1240 if (! aTarget)
1241 return NS_ERROR_NULL_POINTER;
1242
1243 if (mReadCount) {
1244 NS_WARNING("Writing to InMemoryDataSource during read\n");
1245 return NS_RDF_ASSERTION_REJECTED;
1246 }
1247
1248 nsresult rv;
1249 rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
1250 if (NS_FAILED(rv)) return rv;
1251
1252 // notify observers
1253 for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
1254 nsIRDFObserver* obs = mObservers[i];
1255
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;
1260
1261 obs->OnAssert(this, aSource, aProperty, aTarget);
1262 // XXX ignore return value?
1263 }
1264
1265 return NS_RDF_ASSERTION_ACCEPTED;
1266 }
1267
1268
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
1277
1278 Assertion* next = GetForwardArcs(aSource);
1279 Assertion* prev = next;
1280 Assertion* root = next;
1281 Assertion* as = nullptr;
1282
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;
1302
1303 as = next;
1304
1305 if (first) {
1306 PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr);
1307
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 }
1344
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;
1352
1353 #ifdef DEBUG
1354 bool foundReverseArc = false;
1355 #endif
1356
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 }
1373
1374 #ifdef DEBUG
1375 NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
1376 #endif
1377
1378 // Unlink, and release the datasource's reference
1379 as->mNext = as->u.as.mInvNext = nullptr;
1380 as->Release();
1381
1382 return NS_OK;
1383 }
1384
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;
1393
1394 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1395 if (! aProperty)
1396 return NS_ERROR_NULL_POINTER;
1397
1398 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1399 if (! aTarget)
1400 return NS_ERROR_NULL_POINTER;
1401
1402 if (mReadCount) {
1403 NS_WARNING("Writing to InMemoryDataSource during read\n");
1404 return NS_RDF_ASSERTION_REJECTED;
1405 }
1406
1407 nsresult rv;
1408
1409 rv = LockedUnassert(aSource, aProperty, aTarget);
1410 if (NS_FAILED(rv)) return rv;
1411
1412 // Notify the world
1413 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1414 nsIRDFObserver* obs = mObservers[i];
1415
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;
1420
1421 obs->OnUnassert(this, aSource, aProperty, aTarget);
1422 // XXX ignore return value?
1423 }
1424
1425 return NS_RDF_ASSERTION_ACCEPTED;
1426 }
1427
1428
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;
1438
1439 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1440 if (! aProperty)
1441 return NS_ERROR_NULL_POINTER;
1442
1443 NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
1444 if (! aOldTarget)
1445 return NS_ERROR_NULL_POINTER;
1446
1447 NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
1448 if (! aNewTarget)
1449 return NS_ERROR_NULL_POINTER;
1450
1451 if (mReadCount) {
1452 NS_WARNING("Writing to InMemoryDataSource during read\n");
1453 return NS_RDF_ASSERTION_REJECTED;
1454 }
1455
1456 nsresult rv;
1457
1458 // XXX We can implement LockedChange() if we decide that this
1459 // is a performance bottleneck.
1460
1461 rv = LockedUnassert(aSource, aProperty, aOldTarget);
1462 if (NS_FAILED(rv)) return rv;
1463
1464 rv = LockedAssert(aSource, aProperty, aNewTarget, true);
1465 if (NS_FAILED(rv)) return rv;
1466
1467 // Notify the world
1468 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1469 nsIRDFObserver* obs = mObservers[i];
1470
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;
1475
1476 obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
1477 // XXX ignore return value?
1478 }
1479
1480 return NS_RDF_ASSERTION_ACCEPTED;
1481 }
1482
1483
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;
1493
1494 NS_PRECONDITION(aNewSource != nullptr, "null ptr");
1495 if (! aNewSource)
1496 return NS_ERROR_NULL_POINTER;
1497
1498 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1499 if (! aProperty)
1500 return NS_ERROR_NULL_POINTER;
1501
1502 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1503 if (! aTarget)
1504 return NS_ERROR_NULL_POINTER;
1505
1506 if (mReadCount) {
1507 NS_WARNING("Writing to InMemoryDataSource during read\n");
1508 return NS_RDF_ASSERTION_REJECTED;
1509 }
1510
1511 nsresult rv;
1512
1513 // XXX We can implement LockedMove() if we decide that this
1514 // is a performance bottleneck.
1515
1516 rv = LockedUnassert(aOldSource, aProperty, aTarget);
1517 if (NS_FAILED(rv)) return rv;
1518
1519 rv = LockedAssert(aNewSource, aProperty, aTarget, true);
1520 if (NS_FAILED(rv)) return rv;
1521
1522 // Notify the world
1523 for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1524 nsIRDFObserver* obs = mObservers[i];
1525
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;
1530
1531 obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
1532 // XXX ignore return value?
1533 }
1534
1535 return NS_RDF_ASSERTION_ACCEPTED;
1536 }
1537
1538
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;
1545
1546 mObservers.AppendObject(aObserver);
1547 mNumObservers = mObservers.Count();
1548
1549 return NS_OK;
1550 }
1551
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;
1558
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();
1563
1564 return NS_OK;
1565 }
1566
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 }
1582
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 }
1610
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;
1617
1618 InMemoryArcsEnumeratorImpl* result =
1619 new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget);
1620
1621 if (! result)
1622 return NS_ERROR_OUT_OF_MEMORY;
1623
1624 NS_ADDREF(result);
1625 *aResult = result;
1626
1627 return NS_OK;
1628 }
1629
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;
1636
1637 InMemoryArcsEnumeratorImpl* result =
1638 new InMemoryArcsEnumeratorImpl(this, aSource, nullptr);
1639
1640 if (! result)
1641 return NS_ERROR_OUT_OF_MEMORY;
1642
1643 NS_ADDREF(result);
1644 *aResult = result;
1645
1646 return NS_OK;
1647 }
1648
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 }
1658
1659
1660 NS_IMETHODIMP
1661 InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
1662 {
1663 nsCOMArray<nsIRDFNode> nodes;
1664 nodes.SetCapacity(mForwardArcs.entryCount);
1665
1666 // Enumerate all of our entries into an nsCOMArray
1667 PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, &nodes);
1668
1669 return NS_NewArrayEnumerator(aResult, nodes);
1670 }
1671
1672 NS_IMETHODIMP
1673 InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
1674 nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
1675 {
1676 return(NS_NewEmptyEnumerator(commands));
1677 }
1678
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 }
1688
1689 NS_IMETHODIMP
1690 InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
1691 nsIRDFResource* aCommand,
1692 nsISupportsArray/*<nsIRDFResource>*/* aArguments)
1693 {
1694 return NS_OK;
1695 }
1696
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 }
1706
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 }
1716
1717
1718
1719 ////////////////////////////////////////////////////////////////////////
1720 // nsIRDFInMemoryDataSource methods
1721
1722 NS_IMETHODIMP
1723 InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
1724 {
1725 Assertion *as = GetForwardArcs(aSource);
1726 bool haveHash = (as) ? as->mHashEntry : false;
1727
1728 // if its already a hash, then nothing to do
1729 if (haveHash) return(NS_OK);
1730
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);
1735
1736 // Add the datasource's owning reference.
1737 hashAssertion->AddRef();
1738
1739 Assertion *first = GetForwardArcs(aSource);
1740 SetForwardArcs(aSource, hashAssertion);
1741
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;
1748
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 }
1772
1773
1774 ////////////////////////////////////////////////////////////////////////
1775 // nsIRDFPropagatableDataSource methods
1776 NS_IMETHODIMP
1777 InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
1778 {
1779 *aPropagateChanges = mPropagateChanges;
1780 return NS_OK;
1781 }
1782
1783 NS_IMETHODIMP
1784 InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
1785 {
1786 mPropagateChanges = aPropagateChanges;
1787 return NS_OK;
1788 }
1789
1790
1791 ////////////////////////////////////////////////////////////////////////
1792 // nsIRDFPurgeableDataSource methods
1793
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;
1804
1805 NS_PRECONDITION(aProperty != nullptr, "null ptr");
1806 if (! aProperty)
1807 return NS_ERROR_NULL_POINTER;
1808
1809 NS_PRECONDITION(aTarget != nullptr, "null ptr");
1810 if (! aTarget)
1811 return NS_ERROR_NULL_POINTER;
1812
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))) {
1823
1824 // found it! so mark it.
1825 as->Mark();
1826 *aDidMark = true;
1827
1828 #ifdef PR_LOGGING
1829 LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
1830 #endif
1831
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;
1841
1842 if (aProperty != as->u.as.mProperty)
1843 continue;
1844
1845 if (aTruthValue != (as->u.as.mTruthValue))
1846 continue;
1847
1848 // found it! so mark it.
1849 as->Mark();
1850 *aDidMark = true;
1851
1852 #ifdef PR_LOGGING
1853 LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
1854 #endif
1855
1856 return NS_OK;
1857 }
1858
1859 // If we get here, we couldn't find the assertion
1860 *aDidMark = false;
1861 return NS_OK;
1862 }
1863
1864
1865 struct SweepInfo {
1866 Assertion* mUnassertList;
1867 PLDHashTable* mReverseArcs;
1868 };
1869
1870 NS_IMETHODIMP
1871 InMemoryDataSource::Sweep()
1872 {
1873 SweepInfo info = { nullptr, &mReverseArcs };
1874
1875 // Remove all the assertions, but don't notify anyone.
1876 PL_DHashTableEnumerate(&mForwardArcs, SweepForwardArcsEntries, &info);
1877
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 }
1893
1894 Assertion* doomed = as;
1895 as = as->mNext;
1896
1897 // Unlink, and release the datasource's reference
1898 doomed->mNext = doomed->u.as.mInvNext = nullptr;
1899 doomed->Release();
1900 }
1901
1902 return NS_OK;
1903 }
1904
1905
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);
1914
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);
1921
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 }
1927
1928 return result;
1929 }
1930
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 }
1948
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");
1953
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 }
1972
1973 // Wow, it was the _only_ one. Unhash it.
1974 if (! rentry->mAssertions)
1975 {
1976 PL_DHashTableRawRemove(info->mReverseArcs, hdr);
1977 }
1978
1979 // add to the list of assertions to unassert
1980 as->mNext = info->mUnassertList;
1981 info->mUnassertList = as;
1982
1983 // Advance to the next assertion
1984 as = next;
1985 }
1986 }
1987
1988 // if no more assertions exist for this resource, then unhash it.
1989 if (! entry->mAssertions)
1990 result = PL_DHASH_REMOVE;
1991
1992 return result;
1993 }
1994
1995 ////////////////////////////////////////////////////////////////////////
1996 // rdfIDataSource methods
1997
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 };
2008
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);
2014
2015 nsresult rv;
2016 nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
2017 NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
2018
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;
2022
2023 return PL_DHASH_NEXT;
2024 }
2025
2026 NS_IMETHODIMP
2027 InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
2028 {
2029 // Lock datasource against writes
2030 ++mReadCount;
2031
2032 // Enumerate all of our entries into an nsISupportsArray.
2033 VisitorClosure cls(aVisitor);
2034 PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls);
2035
2036 // Unlock datasource
2037 --mReadCount;
2038
2039 return cls.mRv;
2040 }
2041
2042 class TriplesInnerClosure
2043 {
2044 public:
2045 TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) :
2046 mSubject(aSubject), mOuter(aClosure) {}
2047 nsIRDFNode* mSubject;
2048 VisitorClosure* mOuter;
2049 };
2050
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);
2077
2078 nsresult rv;
2079 nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
2080 NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
2081
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;
2110
2111 // Enumerate all of our entries into an nsISupportsArray.
2112 VisitorClosure cls(aVisitor);
2113 PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls);
2114
2115 // Unlock datasource
2116 --mReadCount;
2117
2118 return cls.mRv;
2119 }
2120
2121 ////////////////////////////////////////////////////////////////////////
2122

mercurial