Line data Source code
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 "nsCOMArray.h"
54 : #include "nsEnumeratorUtils.h"
55 : #include "nsTArray.h"
56 : #include "nsCRT.h"
57 : #include "nsRDFCID.h"
58 : #include "nsRDFBaseDataSources.h"
59 : #include "nsString.h"
60 : #include "nsReadableUtils.h"
61 : #include "nsXPIDLString.h"
62 : #include "rdfutil.h"
63 : #include "PLDHashTable.h"
64 : #include "plstr.h"
65 : #include "mozilla/Logging.h"
66 : #include "rdf.h"
67 :
68 : #include "rdfIDataSource.h"
69 : #include "rdfITripleVisitor.h"
70 :
71 : using mozilla::LogLevel;
72 :
73 : // This struct is used as the slot value in the forward and reverse
74 : // arcs hash tables.
75 : //
76 : // Assertion objects are reference counted, because each Assertion's
77 : // ownership is shared between the datasource and any enumerators that
78 : // are currently iterating over the datasource.
79 : //
80 : class Assertion
81 : {
82 : public:
83 : Assertion(nsIRDFResource* aSource, // normal assertion
84 : nsIRDFResource* aProperty,
85 : nsIRDFNode* aTarget,
86 : bool aTruthValue);
87 : explicit Assertion(nsIRDFResource* aSource); // PLDHashTable assertion variant
88 :
89 : private:
90 : ~Assertion();
91 :
92 : public:
93 9 : void AddRef() {
94 9 : if (mRefCnt == UINT16_MAX) {
95 0 : NS_WARNING("refcount overflow, leaking Assertion");
96 0 : return;
97 : }
98 9 : ++mRefCnt;
99 : }
100 :
101 1 : void Release() {
102 1 : if (mRefCnt == UINT16_MAX) {
103 0 : NS_WARNING("refcount overflow, leaking Assertion");
104 0 : return;
105 : }
106 1 : if (--mRefCnt == 0)
107 1 : delete this;
108 : }
109 :
110 : // For nsIRDFPurgeableDataSource
111 0 : inline void Mark() { u.as.mMarked = true; }
112 0 : inline bool IsMarked() { return u.as.mMarked; }
113 0 : inline void Unmark() { u.as.mMarked = false; }
114 :
115 : // public for now, because I'm too lazy to go thru and clean this up.
116 :
117 : // These are shared between hash/as (see the union below)
118 : nsIRDFResource* mSource;
119 : Assertion* mNext;
120 :
121 : union
122 : {
123 : struct hash
124 : {
125 : PLDHashTable* mPropertyHash;
126 : } hash;
127 : struct as
128 : {
129 : nsIRDFResource* mProperty;
130 : nsIRDFNode* mTarget;
131 : Assertion* mInvNext;
132 : // make sure bool are final elements
133 : bool mTruthValue;
134 : bool mMarked;
135 : } as;
136 : } u;
137 :
138 : // also shared between hash/as (see the union above)
139 : // but placed after union definition to ensure that
140 : // all 32-bit entries are long aligned
141 : uint16_t mRefCnt;
142 : bool mHashEntry;
143 : };
144 :
145 :
146 : struct Entry : PLDHashEntryHdr {
147 : nsIRDFNode* mNode;
148 : Assertion* mAssertions;
149 : };
150 :
151 :
152 0 : Assertion::Assertion(nsIRDFResource* aSource)
153 : : mSource(aSource),
154 : mNext(nullptr),
155 : mRefCnt(0),
156 0 : mHashEntry(true)
157 : {
158 0 : MOZ_COUNT_CTOR(Assertion);
159 :
160 0 : NS_ADDREF(mSource);
161 :
162 0 : u.hash.mPropertyHash =
163 0 : new PLDHashTable(PLDHashTable::StubOps(), sizeof(Entry));
164 0 : }
165 :
166 9 : Assertion::Assertion(nsIRDFResource* aSource,
167 : nsIRDFResource* aProperty,
168 : nsIRDFNode* aTarget,
169 9 : bool aTruthValue)
170 : : mSource(aSource),
171 : mNext(nullptr),
172 : mRefCnt(0),
173 9 : mHashEntry(false)
174 : {
175 9 : MOZ_COUNT_CTOR(Assertion);
176 :
177 9 : u.as.mProperty = aProperty;
178 9 : u.as.mTarget = aTarget;
179 :
180 9 : NS_ADDREF(mSource);
181 9 : NS_ADDREF(u.as.mProperty);
182 9 : NS_ADDREF(u.as.mTarget);
183 :
184 9 : u.as.mInvNext = nullptr;
185 9 : u.as.mTruthValue = aTruthValue;
186 9 : u.as.mMarked = false;
187 9 : }
188 :
189 2 : Assertion::~Assertion()
190 : {
191 1 : if (mHashEntry && u.hash.mPropertyHash) {
192 0 : for (auto i = u.hash.mPropertyHash->Iter(); !i.Done(); i.Next()) {
193 0 : auto entry = static_cast<Entry*>(i.Get());
194 0 : Assertion* as = entry->mAssertions;
195 0 : while (as) {
196 0 : Assertion* doomed = as;
197 0 : as = as->mNext;
198 :
199 : // Unlink, and release the datasource's reference.
200 0 : doomed->mNext = doomed->u.as.mInvNext = nullptr;
201 0 : doomed->Release();
202 : }
203 : }
204 0 : delete u.hash.mPropertyHash;
205 0 : u.hash.mPropertyHash = nullptr;
206 : }
207 :
208 1 : MOZ_COUNT_DTOR(Assertion);
209 : #ifdef DEBUG_REFS
210 : --gInstanceCount;
211 : fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
212 : #endif
213 :
214 1 : NS_RELEASE(mSource);
215 1 : if (!mHashEntry)
216 : {
217 1 : NS_RELEASE(u.as.mProperty);
218 1 : NS_RELEASE(u.as.mTarget);
219 : }
220 1 : }
221 :
222 : ////////////////////////////////////////////////////////////////////////
223 : // InMemoryDataSource
224 : class InMemoryArcsEnumeratorImpl;
225 : class InMemoryAssertionEnumeratorImpl;
226 : class InMemoryResourceEnumeratorImpl;
227 :
228 : class InMemoryDataSource : public nsIRDFDataSource,
229 : public nsIRDFInMemoryDataSource,
230 : public nsIRDFPropagatableDataSource,
231 : public nsIRDFPurgeableDataSource,
232 : public rdfIDataSource
233 : {
234 : protected:
235 : // These hash tables are keyed on pointers to nsIRDFResource
236 : // objects (the nsIRDFService ensures that there is only ever one
237 : // nsIRDFResource object per unique URI). The value of an entry is
238 : // an Assertion struct, which is a linked list of (subject
239 : // predicate object) triples.
240 : PLDHashTable mForwardArcs;
241 : PLDHashTable mReverseArcs;
242 :
243 : nsCOMArray<nsIRDFObserver> mObservers;
244 : uint32_t mNumObservers;
245 :
246 : // VisitFoo needs to block writes, [Un]Assert only allowed
247 : // during mReadCount == 0
248 : uint32_t mReadCount;
249 :
250 : friend class InMemoryArcsEnumeratorImpl;
251 : friend class InMemoryAssertionEnumeratorImpl;
252 : friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
253 :
254 : // Thread-safe writer implementation methods.
255 : nsresult
256 : LockedAssert(nsIRDFResource* source,
257 : nsIRDFResource* property,
258 : nsIRDFNode* target,
259 : bool tv);
260 :
261 : nsresult
262 : LockedUnassert(nsIRDFResource* source,
263 : nsIRDFResource* property,
264 : nsIRDFNode* target);
265 :
266 : explicit InMemoryDataSource(nsISupports* aOuter);
267 : virtual ~InMemoryDataSource();
268 :
269 : friend nsresult
270 : NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
271 :
272 : public:
273 3 : NS_DECL_CYCLE_COLLECTING_AGGREGATED
274 24 : NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
275 :
276 : // nsIRDFDataSource methods
277 : NS_DECL_NSIRDFDATASOURCE
278 :
279 : // nsIRDFInMemoryDataSource methods
280 : NS_DECL_NSIRDFINMEMORYDATASOURCE
281 :
282 : // nsIRDFPropagatableDataSource methods
283 : NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
284 :
285 : // nsIRDFPurgeableDataSource methods
286 : NS_DECL_NSIRDFPURGEABLEDATASOURCE
287 :
288 : // rdfIDataSource methods
289 : NS_DECL_RDFIDATASOURCE
290 :
291 : protected:
292 : struct SweepInfo {
293 : Assertion* mUnassertList;
294 : PLDHashTable* mReverseArcs;
295 : };
296 :
297 : static void
298 : SweepForwardArcsEntries(PLDHashTable* aTable, SweepInfo* aArg);
299 :
300 : public:
301 : // Implementation methods
302 : Assertion*
303 24 : GetForwardArcs(nsIRDFResource* u) {
304 24 : PLDHashEntryHdr* hdr = mForwardArcs.Search(u);
305 24 : return hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
306 : }
307 :
308 : Assertion*
309 10 : GetReverseArcs(nsIRDFNode* v) {
310 10 : PLDHashEntryHdr* hdr = mReverseArcs.Search(v);
311 10 : return hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
312 : }
313 :
314 : void
315 4 : SetForwardArcs(nsIRDFResource* u, Assertion* as) {
316 4 : if (as) {
317 : auto entry =
318 4 : static_cast<Entry*>(mForwardArcs.Add(u, mozilla::fallible));
319 4 : if (entry) {
320 4 : entry->mNode = u;
321 4 : entry->mAssertions = as;
322 : }
323 : }
324 : else {
325 0 : mForwardArcs.Remove(u);
326 : }
327 4 : }
328 :
329 : void
330 10 : SetReverseArcs(nsIRDFNode* v, Assertion* as) {
331 10 : if (as) {
332 : auto entry =
333 9 : static_cast<Entry*>(mReverseArcs.Add(v, mozilla::fallible));
334 9 : if (entry) {
335 9 : entry->mNode = v;
336 9 : entry->mAssertions = as;
337 : }
338 : }
339 : else {
340 1 : mReverseArcs.Remove(v);
341 : }
342 10 : }
343 :
344 : void
345 : LogOperation(const char* aOperation,
346 : nsIRDFResource* asource,
347 : nsIRDFResource* aProperty,
348 : nsIRDFNode* aTarget,
349 : bool aTruthValue = true);
350 :
351 : bool mPropagateChanges;
352 :
353 : private:
354 : static mozilla::LazyLogModule gLog;
355 : };
356 :
357 : mozilla::LazyLogModule InMemoryDataSource::gLog("InMemoryDataSource");
358 :
359 : //----------------------------------------------------------------------
360 : //
361 : // InMemoryAssertionEnumeratorImpl
362 : //
363 :
364 : /**
365 : * InMemoryAssertionEnumeratorImpl
366 : */
367 : class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
368 : {
369 : private:
370 : InMemoryDataSource* mDataSource;
371 : nsIRDFResource* mSource;
372 : nsIRDFResource* mProperty;
373 : nsIRDFNode* mTarget;
374 : nsIRDFNode* mValue;
375 : bool mTruthValue;
376 : Assertion* mNextAssertion;
377 :
378 : virtual ~InMemoryAssertionEnumeratorImpl();
379 :
380 : public:
381 : InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
382 : nsIRDFResource* aSource,
383 : nsIRDFResource* aProperty,
384 : nsIRDFNode* aTarget,
385 : bool aTruthValue);
386 :
387 : // nsISupports interface
388 : NS_DECL_ISUPPORTS
389 :
390 : // nsISimpleEnumerator interface
391 : NS_DECL_NSISIMPLEENUMERATOR
392 : };
393 :
394 : ////////////////////////////////////////////////////////////////////////
395 :
396 :
397 0 : InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
398 : InMemoryDataSource* aDataSource,
399 : nsIRDFResource* aSource,
400 : nsIRDFResource* aProperty,
401 : nsIRDFNode* aTarget,
402 0 : bool aTruthValue)
403 : : mDataSource(aDataSource),
404 : mSource(aSource),
405 : mProperty(aProperty),
406 : mTarget(aTarget),
407 : mValue(nullptr),
408 : mTruthValue(aTruthValue),
409 0 : mNextAssertion(nullptr)
410 : {
411 0 : NS_ADDREF(mDataSource);
412 0 : NS_IF_ADDREF(mSource);
413 0 : NS_ADDREF(mProperty);
414 0 : NS_IF_ADDREF(mTarget);
415 :
416 0 : if (mSource) {
417 0 : mNextAssertion = mDataSource->GetForwardArcs(mSource);
418 :
419 0 : if (mNextAssertion && mNextAssertion->mHashEntry) {
420 : // its our magical HASH_ENTRY forward hash for assertions
421 : PLDHashEntryHdr* hdr =
422 0 : mNextAssertion->u.hash.mPropertyHash->Search(aProperty);
423 0 : mNextAssertion =
424 0 : hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
425 : }
426 : }
427 : else {
428 0 : mNextAssertion = mDataSource->GetReverseArcs(mTarget);
429 : }
430 :
431 : // Add an owning reference from the enumerator
432 0 : if (mNextAssertion)
433 0 : mNextAssertion->AddRef();
434 0 : }
435 :
436 0 : InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
437 : {
438 : #ifdef DEBUG_REFS
439 : --gInstanceCount;
440 : fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
441 : #endif
442 :
443 0 : if (mNextAssertion)
444 0 : mNextAssertion->Release();
445 :
446 0 : NS_IF_RELEASE(mDataSource);
447 0 : NS_IF_RELEASE(mSource);
448 0 : NS_IF_RELEASE(mProperty);
449 0 : NS_IF_RELEASE(mTarget);
450 0 : NS_IF_RELEASE(mValue);
451 0 : }
452 :
453 0 : NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
454 0 : NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl)
455 0 : NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
456 :
457 : NS_IMETHODIMP
458 0 : InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
459 : {
460 0 : if (mValue) {
461 0 : *aResult = true;
462 0 : return NS_OK;
463 : }
464 :
465 0 : while (mNextAssertion) {
466 0 : bool foundIt = false;
467 0 : if ((mProperty == mNextAssertion->u.as.mProperty) &&
468 0 : (mTruthValue == mNextAssertion->u.as.mTruthValue)) {
469 0 : if (mSource) {
470 0 : mValue = mNextAssertion->u.as.mTarget;
471 0 : NS_ADDREF(mValue);
472 : }
473 : else {
474 0 : mValue = mNextAssertion->mSource;
475 0 : NS_ADDREF(mValue);
476 : }
477 0 : foundIt = true;
478 : }
479 :
480 : // Remember the last assertion we were holding on to
481 0 : Assertion* as = mNextAssertion;
482 :
483 : // iterate
484 0 : mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
485 :
486 : // grab an owning reference from the enumerator to the next assertion
487 0 : if (mNextAssertion)
488 0 : mNextAssertion->AddRef();
489 :
490 : // ...and release the reference from the enumerator to the old one.
491 0 : as->Release();
492 :
493 0 : if (foundIt) {
494 0 : *aResult = true;
495 0 : return NS_OK;
496 : }
497 : }
498 :
499 0 : *aResult = false;
500 0 : return NS_OK;
501 : }
502 :
503 :
504 : NS_IMETHODIMP
505 0 : InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
506 : {
507 : nsresult rv;
508 :
509 : bool hasMore;
510 0 : rv = HasMoreElements(&hasMore);
511 0 : if (NS_FAILED(rv)) return rv;
512 :
513 0 : if (! hasMore)
514 0 : return NS_ERROR_UNEXPECTED;
515 :
516 : // Don't AddRef: we "transfer" ownership to the caller
517 0 : *aResult = mValue;
518 0 : mValue = nullptr;
519 :
520 0 : return NS_OK;
521 : }
522 :
523 : ////////////////////////////////////////////////////////////////////////
524 : //
525 :
526 : /**
527 : * This class is a little bit bizarre in that it implements both the
528 : * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
529 : * Because the structure of the in-memory graph is pretty flexible, it's
530 : * fairly easy to parameterize this class. The only funky thing to watch
531 : * out for is the multiple inheritance clashes.
532 : */
533 :
534 : class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
535 : {
536 : private:
537 : InMemoryDataSource* mDataSource;
538 : nsIRDFResource* mSource;
539 : nsIRDFNode* mTarget;
540 : AutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned;
541 : nsIRDFResource* mCurrent;
542 : Assertion* mAssertion;
543 : nsCOMArray<nsIRDFNode>* mHashArcs;
544 :
545 : virtual ~InMemoryArcsEnumeratorImpl();
546 :
547 : public:
548 : InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
549 : nsIRDFResource* aSource,
550 : nsIRDFNode* aTarget);
551 :
552 : // nsISupports interface
553 : NS_DECL_ISUPPORTS
554 :
555 : // nsISimpleEnumerator interface
556 : NS_DECL_NSISIMPLEENUMERATOR
557 : };
558 :
559 :
560 0 : InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
561 : nsIRDFResource* aSource,
562 0 : nsIRDFNode* aTarget)
563 : : mDataSource(aDataSource),
564 : mSource(aSource),
565 : mTarget(aTarget),
566 : mCurrent(nullptr),
567 0 : mHashArcs(nullptr)
568 : {
569 0 : NS_ADDREF(mDataSource);
570 0 : NS_IF_ADDREF(mSource);
571 0 : NS_IF_ADDREF(mTarget);
572 :
573 0 : if (mSource) {
574 : // cast okay because it's a closed system
575 0 : mAssertion = mDataSource->GetForwardArcs(mSource);
576 :
577 0 : if (mAssertion && mAssertion->mHashEntry) {
578 : // its our magical HASH_ENTRY forward hash for assertions
579 0 : mHashArcs = new nsCOMArray<nsIRDFNode>();
580 0 : for (auto i = mAssertion->u.hash.mPropertyHash->Iter();
581 0 : !i.Done();
582 0 : i.Next()) {
583 0 : auto entry = static_cast<Entry*>(i.Get());
584 0 : mHashArcs->AppendElement(entry->mNode);
585 : }
586 0 : mAssertion = nullptr;
587 : }
588 : }
589 : else {
590 0 : mAssertion = mDataSource->GetReverseArcs(mTarget);
591 : }
592 0 : }
593 :
594 0 : InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
595 : {
596 : #ifdef DEBUG_REFS
597 : --gInstanceCount;
598 : fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
599 : #endif
600 :
601 0 : NS_RELEASE(mDataSource);
602 0 : NS_IF_RELEASE(mSource);
603 0 : NS_IF_RELEASE(mTarget);
604 0 : NS_IF_RELEASE(mCurrent);
605 0 : delete mHashArcs;
606 0 : }
607 :
608 0 : NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
609 0 : NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl)
610 0 : NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
611 :
612 : NS_IMETHODIMP
613 0 : InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult)
614 : {
615 0 : NS_PRECONDITION(aResult != nullptr, "null ptr");
616 0 : if (! aResult)
617 0 : return NS_ERROR_NULL_POINTER;
618 :
619 0 : if (mCurrent) {
620 0 : *aResult = true;
621 0 : return NS_OK;
622 : }
623 :
624 0 : if (mHashArcs) {
625 0 : if (!mHashArcs->IsEmpty()) {
626 0 : const uint32_t last = mHashArcs->Length() - 1;
627 0 : nsCOMPtr<nsIRDFResource> tmp(do_QueryInterface(mHashArcs->ObjectAt(last)));
628 0 : tmp.forget(&mCurrent);
629 0 : mHashArcs->RemoveElementAt(last);
630 0 : *aResult = true;
631 0 : return NS_OK;
632 : }
633 : }
634 : else
635 0 : while (mAssertion) {
636 0 : nsIRDFResource* next = mAssertion->u.as.mProperty;
637 :
638 : // "next" is the property arc we are tentatively going to return
639 : // in a subsequent GetNext() call. It is important to do two
640 : // things, however, before that can happen:
641 : // 1) Make sure it's not an arc we've already returned.
642 : // 2) Make sure that |mAssertion| is not left pointing to
643 : // another assertion that has the same property as this one.
644 : // The first is a practical concern; the second a defense against
645 : // an obscure crash and other erratic behavior. To ensure the
646 : // second condition, skip down the chain until we find the next
647 : // assertion with a property that doesn't match the current one.
648 : // (All these assertions would be skipped via mAlreadyReturned
649 : // checks anyways; this is even a bit faster.)
650 :
651 0 : do {
652 0 : mAssertion = (mSource ? mAssertion->mNext :
653 0 : mAssertion->u.as.mInvNext);
654 : }
655 0 : while (mAssertion && (next == mAssertion->u.as.mProperty));
656 :
657 0 : bool alreadyReturned = false;
658 0 : for (int32_t i = mAlreadyReturned.Length() - 1; i >= 0; --i) {
659 0 : if (mAlreadyReturned[i] == next) {
660 0 : alreadyReturned = true;
661 0 : break;
662 : }
663 : }
664 :
665 0 : if (! alreadyReturned) {
666 0 : mCurrent = next;
667 0 : NS_ADDREF(mCurrent);
668 0 : *aResult = true;
669 0 : return NS_OK;
670 : }
671 : }
672 :
673 0 : *aResult = false;
674 0 : return NS_OK;
675 : }
676 :
677 :
678 : NS_IMETHODIMP
679 0 : InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
680 : {
681 : nsresult rv;
682 :
683 : bool hasMore;
684 0 : rv = HasMoreElements(&hasMore);
685 0 : if (NS_FAILED(rv)) return rv;
686 :
687 0 : if (! hasMore)
688 0 : return NS_ERROR_UNEXPECTED;
689 :
690 : // Add this to the set of things we've already returned so that we
691 : // can ensure uniqueness
692 0 : mAlreadyReturned.AppendElement(mCurrent);
693 :
694 : // Don't AddRef: we "transfer" ownership to the caller
695 0 : *aResult = mCurrent;
696 0 : mCurrent = nullptr;
697 :
698 0 : return NS_OK;
699 : }
700 :
701 :
702 : ////////////////////////////////////////////////////////////////////////
703 : // InMemoryDataSource
704 :
705 : nsresult
706 3 : NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
707 : {
708 3 : NS_PRECONDITION(aResult != nullptr, "null ptr");
709 3 : if (! aResult)
710 0 : return NS_ERROR_NULL_POINTER;
711 3 : *aResult = nullptr;
712 :
713 3 : if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
714 0 : NS_ERROR("aggregation requires nsISupports");
715 0 : return NS_ERROR_ILLEGAL_VALUE;
716 : }
717 :
718 3 : InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
719 3 : NS_ADDREF(datasource);
720 :
721 3 : datasource->fAggregated.AddRef();
722 3 : nsresult rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
723 3 : datasource->fAggregated.Release();
724 :
725 3 : NS_RELEASE(datasource);
726 3 : return rv;
727 : }
728 :
729 :
730 3 : InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
731 : : mForwardArcs(PLDHashTable::StubOps(), sizeof(Entry))
732 : , mReverseArcs(PLDHashTable::StubOps(), sizeof(Entry))
733 : , mNumObservers(0)
734 3 : , mReadCount(0)
735 : {
736 3 : NS_INIT_AGGREGATED(aOuter);
737 :
738 3 : mPropagateChanges = true;
739 3 : }
740 :
741 :
742 0 : InMemoryDataSource::~InMemoryDataSource()
743 : {
744 : #ifdef DEBUG_REFS
745 : --gInstanceCount;
746 : fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
747 : #endif
748 :
749 0 : if (mForwardArcs.EntryCount() > 0) {
750 : // This'll release all of the Assertion objects that are
751 : // associated with this data source. We only need to do this
752 : // for the forward arcs, because the reverse arcs table
753 : // indexes the exact same set of resources.
754 0 : for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
755 0 : auto entry = static_cast<Entry*>(iter.Get());
756 0 : Assertion* as = entry->mAssertions;
757 0 : while (as) {
758 0 : Assertion* doomed = as;
759 0 : as = as->mNext;
760 :
761 : // Unlink, and release the datasource's reference.
762 0 : doomed->mNext = doomed->u.as.mInvNext = nullptr;
763 0 : doomed->Release();
764 : }
765 : }
766 : }
767 :
768 0 : MOZ_LOG(gLog, LogLevel::Debug,
769 : ("InMemoryDataSource(%p): destroyed.", this));
770 0 : }
771 :
772 :
773 : ////////////////////////////////////////////////////////////////////////
774 :
775 : NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
776 :
777 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource)
778 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
779 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
780 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
781 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
782 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
783 :
784 45 : NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
785 9 : NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
786 9 : NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource)
787 6 : NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
788 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource)
789 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource)
790 0 : NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource)
791 0 : NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
792 0 : NS_INTERFACE_MAP_END
793 :
794 : ////////////////////////////////////////////////////////////////////////
795 :
796 :
797 : void
798 10 : InMemoryDataSource::LogOperation(const char* aOperation,
799 : nsIRDFResource* aSource,
800 : nsIRDFResource* aProperty,
801 : nsIRDFNode* aTarget,
802 : bool aTruthValue)
803 : {
804 10 : if (! MOZ_LOG_TEST(gLog, LogLevel::Debug))
805 10 : return;
806 :
807 0 : nsXPIDLCString uri;
808 0 : aSource->GetValue(getter_Copies(uri));
809 0 : MOZ_LOG(gLog, LogLevel::Debug,
810 : ("InMemoryDataSource(%p): %s", this, aOperation));
811 :
812 0 : MOZ_LOG(gLog, LogLevel::Debug,
813 : (" [(%p)%s]--", aSource, (const char*) uri));
814 :
815 0 : aProperty->GetValue(getter_Copies(uri));
816 :
817 0 : char tv = (aTruthValue ? '-' : '!');
818 0 : MOZ_LOG(gLog, LogLevel::Debug,
819 : (" --%c[(%p)%s]--", tv, aProperty, (const char*) uri));
820 :
821 0 : nsCOMPtr<nsIRDFResource> resource;
822 0 : nsCOMPtr<nsIRDFLiteral> literal;
823 :
824 0 : if ((resource = do_QueryInterface(aTarget)) != nullptr) {
825 0 : resource->GetValue(getter_Copies(uri));
826 0 : MOZ_LOG(gLog, LogLevel::Debug,
827 : (" -->[(%p)%s]", aTarget, (const char*) uri));
828 : }
829 0 : else if ((literal = do_QueryInterface(aTarget)) != nullptr) {
830 0 : nsXPIDLString value;
831 0 : literal->GetValue(getter_Copies(value));
832 0 : nsAutoString valueStr(value);
833 0 : char* valueCStr = ToNewCString(valueStr);
834 :
835 0 : MOZ_LOG(gLog, LogLevel::Debug,
836 : (" -->(\"%s\")\n", valueCStr));
837 :
838 0 : free(valueCStr);
839 : }
840 : else {
841 0 : MOZ_LOG(gLog, LogLevel::Debug,
842 : (" -->(unknown-type)\n"));
843 : }
844 : }
845 :
846 :
847 : NS_IMETHODIMP
848 0 : InMemoryDataSource::GetURI(char* *uri)
849 : {
850 0 : NS_PRECONDITION(uri != nullptr, "null ptr");
851 0 : if (! uri)
852 0 : return NS_ERROR_NULL_POINTER;
853 :
854 0 : *uri = nullptr;
855 0 : return NS_OK;
856 : }
857 :
858 : NS_IMETHODIMP
859 0 : InMemoryDataSource::GetSource(nsIRDFResource* property,
860 : nsIRDFNode* target,
861 : bool tv,
862 : nsIRDFResource** source)
863 : {
864 0 : NS_PRECONDITION(source != nullptr, "null ptr");
865 0 : if (! source)
866 0 : return NS_ERROR_NULL_POINTER;
867 :
868 0 : NS_PRECONDITION(property != nullptr, "null ptr");
869 0 : if (! property)
870 0 : return NS_ERROR_NULL_POINTER;
871 :
872 0 : NS_PRECONDITION(target != nullptr, "null ptr");
873 0 : if (! target)
874 0 : return NS_ERROR_NULL_POINTER;
875 :
876 0 : for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) {
877 0 : if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) {
878 0 : *source = as->mSource;
879 0 : NS_ADDREF(*source);
880 0 : return NS_OK;
881 : }
882 : }
883 0 : *source = nullptr;
884 0 : return NS_RDF_NO_VALUE;
885 : }
886 :
887 : NS_IMETHODIMP
888 2 : InMemoryDataSource::GetTarget(nsIRDFResource* source,
889 : nsIRDFResource* property,
890 : bool tv,
891 : nsIRDFNode** target)
892 : {
893 2 : NS_PRECONDITION(source != nullptr, "null ptr");
894 2 : if (! source)
895 0 : return NS_ERROR_NULL_POINTER;
896 :
897 2 : NS_PRECONDITION(property != nullptr, "null ptr");
898 2 : if (! property)
899 0 : return NS_ERROR_NULL_POINTER;
900 :
901 2 : NS_PRECONDITION(target != nullptr, "null ptr");
902 2 : if (! target)
903 0 : return NS_ERROR_NULL_POINTER;
904 :
905 2 : Assertion *as = GetForwardArcs(source);
906 2 : if (as && as->mHashEntry) {
907 0 : PLDHashEntryHdr* hdr = as->u.hash.mPropertyHash->Search(property);
908 0 : Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
909 0 : while (val) {
910 0 : if (tv == val->u.as.mTruthValue) {
911 0 : *target = val->u.as.mTarget;
912 0 : NS_IF_ADDREF(*target);
913 0 : return NS_OK;
914 : }
915 0 : val = val->mNext;
916 0 : }
917 : }
918 : else
919 4 : for (; as != nullptr; as = as->mNext) {
920 2 : if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) {
921 1 : *target = as->u.as.mTarget;
922 1 : NS_ADDREF(*target);
923 1 : return NS_OK;
924 : }
925 : }
926 :
927 : // If we get here, then there was no target with for the specified
928 : // property & truth value.
929 1 : *target = nullptr;
930 1 : return NS_RDF_NO_VALUE;
931 : }
932 :
933 : NS_IMETHODIMP
934 12 : InMemoryDataSource::HasAssertion(nsIRDFResource* source,
935 : nsIRDFResource* property,
936 : nsIRDFNode* target,
937 : bool tv,
938 : bool* hasAssertion)
939 : {
940 12 : if (! source)
941 0 : return NS_ERROR_NULL_POINTER;
942 :
943 12 : if (! property)
944 0 : return NS_ERROR_NULL_POINTER;
945 :
946 12 : if (! target)
947 0 : return NS_ERROR_NULL_POINTER;
948 :
949 12 : Assertion *as = GetForwardArcs(source);
950 12 : if (as && as->mHashEntry) {
951 0 : PLDHashEntryHdr* hdr = as->u.hash.mPropertyHash->Search(property);
952 0 : Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
953 0 : while (val) {
954 0 : if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) {
955 0 : *hasAssertion = true;
956 0 : return NS_OK;
957 : }
958 0 : val = val->mNext;
959 0 : }
960 : }
961 : else
962 12 : for (; as != nullptr; as = as->mNext) {
963 : // check target first as its most unique
964 3 : if (target != as->u.as.mTarget)
965 0 : continue;
966 :
967 3 : if (property != as->u.as.mProperty)
968 0 : continue;
969 :
970 3 : if (tv != (as->u.as.mTruthValue))
971 0 : continue;
972 :
973 : // found it!
974 3 : *hasAssertion = true;
975 3 : return NS_OK;
976 : }
977 :
978 : // If we get here, we couldn't find the assertion
979 9 : *hasAssertion = false;
980 9 : return NS_OK;
981 : }
982 :
983 : NS_IMETHODIMP
984 0 : InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
985 : nsIRDFNode* aTarget,
986 : bool aTruthValue,
987 : nsISimpleEnumerator** aResult)
988 : {
989 0 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
990 0 : if (! aProperty)
991 0 : return NS_ERROR_NULL_POINTER;
992 :
993 0 : NS_PRECONDITION(aTarget != nullptr, "null ptr");
994 0 : if (! aTarget)
995 0 : return NS_ERROR_NULL_POINTER;
996 :
997 0 : NS_PRECONDITION(aResult != nullptr, "null ptr");
998 0 : if (! aResult)
999 0 : return NS_ERROR_NULL_POINTER;
1000 :
1001 : InMemoryAssertionEnumeratorImpl* result =
1002 : new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty,
1003 0 : aTarget, aTruthValue);
1004 :
1005 0 : if (! result)
1006 0 : return NS_ERROR_OUT_OF_MEMORY;
1007 :
1008 0 : NS_ADDREF(result);
1009 0 : *aResult = result;
1010 :
1011 0 : return NS_OK;
1012 : }
1013 :
1014 : NS_IMETHODIMP
1015 0 : InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
1016 : nsIRDFResource* aProperty,
1017 : bool aTruthValue,
1018 : nsISimpleEnumerator** aResult)
1019 : {
1020 0 : NS_PRECONDITION(aSource != nullptr, "null ptr");
1021 0 : if (! aSource)
1022 0 : return NS_ERROR_NULL_POINTER;
1023 :
1024 0 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
1025 0 : if (! aProperty)
1026 0 : return NS_ERROR_NULL_POINTER;
1027 :
1028 0 : NS_PRECONDITION(aResult != nullptr, "null ptr");
1029 0 : if (! aResult)
1030 0 : return NS_ERROR_NULL_POINTER;
1031 :
1032 : InMemoryAssertionEnumeratorImpl* result =
1033 : new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty,
1034 0 : nullptr, aTruthValue);
1035 :
1036 0 : if (! result)
1037 0 : return NS_ERROR_OUT_OF_MEMORY;
1038 :
1039 0 : NS_ADDREF(result);
1040 0 : *aResult = result;
1041 :
1042 0 : return NS_OK;
1043 : }
1044 :
1045 :
1046 : nsresult
1047 9 : InMemoryDataSource::LockedAssert(nsIRDFResource* aSource,
1048 : nsIRDFResource* aProperty,
1049 : nsIRDFNode* aTarget,
1050 : bool aTruthValue)
1051 : {
1052 9 : LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue);
1053 :
1054 9 : Assertion* next = GetForwardArcs(aSource);
1055 9 : Assertion* prev = next;
1056 9 : Assertion* as = nullptr;
1057 :
1058 9 : bool haveHash = (next) ? next->mHashEntry : false;
1059 9 : if (haveHash) {
1060 0 : PLDHashEntryHdr* hdr = next->u.hash.mPropertyHash->Search(aProperty);
1061 0 : Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
1062 0 : while (val) {
1063 0 : if (val->u.as.mTarget == aTarget) {
1064 : // Wow, we already had the assertion. Make sure that the
1065 : // truth values are correct and bail.
1066 0 : val->u.as.mTruthValue = aTruthValue;
1067 0 : return NS_OK;
1068 : }
1069 0 : val = val->mNext;
1070 : }
1071 : }
1072 : else
1073 : {
1074 21 : while (next) {
1075 : // check target first as its most unique
1076 6 : if (aTarget == next->u.as.mTarget) {
1077 0 : if (aProperty == next->u.as.mProperty) {
1078 : // Wow, we already had the assertion. Make sure that the
1079 : // truth values are correct and bail.
1080 0 : next->u.as.mTruthValue = aTruthValue;
1081 0 : return NS_OK;
1082 : }
1083 : }
1084 :
1085 6 : prev = next;
1086 6 : next = next->mNext;
1087 : }
1088 : }
1089 :
1090 9 : as = new Assertion(aSource, aProperty, aTarget, aTruthValue);
1091 9 : if (! as)
1092 0 : return NS_ERROR_OUT_OF_MEMORY;
1093 :
1094 : // Add the datasource's owning reference.
1095 9 : as->AddRef();
1096 :
1097 9 : if (haveHash)
1098 : {
1099 0 : PLDHashEntryHdr* hdr = next->u.hash.mPropertyHash->Search(aProperty);
1100 : Assertion *asRef =
1101 0 : hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
1102 0 : if (asRef)
1103 : {
1104 0 : as->mNext = asRef->mNext;
1105 0 : asRef->mNext = as;
1106 : }
1107 : else
1108 : {
1109 0 : hdr = next->u.hash.mPropertyHash->Add(aProperty, mozilla::fallible);
1110 0 : if (hdr)
1111 : {
1112 0 : Entry* entry = static_cast<Entry*>(hdr);
1113 0 : entry->mNode = aProperty;
1114 0 : entry->mAssertions = as;
1115 : }
1116 : }
1117 : }
1118 : else
1119 : {
1120 : // Link it in to the "forward arcs" table
1121 9 : if (!prev) {
1122 4 : SetForwardArcs(aSource, as);
1123 : } else {
1124 5 : prev->mNext = as;
1125 : }
1126 : }
1127 :
1128 : // Link it in to the "reverse arcs" table
1129 :
1130 9 : next = GetReverseArcs(aTarget);
1131 9 : as->u.as.mInvNext = next;
1132 9 : next = as;
1133 9 : SetReverseArcs(aTarget, next);
1134 :
1135 9 : return NS_OK;
1136 : }
1137 :
1138 : NS_IMETHODIMP
1139 9 : InMemoryDataSource::Assert(nsIRDFResource* aSource,
1140 : nsIRDFResource* aProperty,
1141 : nsIRDFNode* aTarget,
1142 : bool aTruthValue)
1143 : {
1144 9 : NS_PRECONDITION(aSource != nullptr, "null ptr");
1145 9 : if (! aSource)
1146 0 : return NS_ERROR_NULL_POINTER;
1147 :
1148 9 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
1149 9 : if (! aProperty)
1150 0 : return NS_ERROR_NULL_POINTER;
1151 :
1152 9 : NS_PRECONDITION(aTarget != nullptr, "null ptr");
1153 9 : if (! aTarget)
1154 0 : return NS_ERROR_NULL_POINTER;
1155 :
1156 9 : if (mReadCount) {
1157 0 : NS_WARNING("Writing to InMemoryDataSource during read\n");
1158 0 : return NS_RDF_ASSERTION_REJECTED;
1159 : }
1160 :
1161 : nsresult rv;
1162 9 : rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
1163 9 : if (NS_FAILED(rv)) return rv;
1164 :
1165 : // notify observers
1166 9 : for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
1167 0 : nsIRDFObserver* obs = mObservers[i];
1168 :
1169 : // XXX this should never happen, but it does, and we can't figure out why.
1170 0 : NS_ASSERTION(obs, "observer array corrupted!");
1171 0 : if (! obs)
1172 0 : continue;
1173 :
1174 0 : obs->OnAssert(this, aSource, aProperty, aTarget);
1175 : // XXX ignore return value?
1176 : }
1177 :
1178 9 : return NS_RDF_ASSERTION_ACCEPTED;
1179 : }
1180 :
1181 :
1182 : nsresult
1183 1 : InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
1184 : nsIRDFResource* aProperty,
1185 : nsIRDFNode* aTarget)
1186 : {
1187 1 : LogOperation("UNASSERT", aSource, aProperty, aTarget);
1188 :
1189 1 : Assertion* next = GetForwardArcs(aSource);
1190 1 : Assertion* prev = next;
1191 1 : Assertion* root = next;
1192 1 : Assertion* as = nullptr;
1193 :
1194 1 : bool haveHash = (next) ? next->mHashEntry : false;
1195 1 : if (haveHash) {
1196 0 : PLDHashEntryHdr* hdr = next->u.hash.mPropertyHash->Search(aProperty);
1197 0 : prev = next = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
1198 0 : bool first = true;
1199 0 : while (next) {
1200 0 : if (aTarget == next->u.as.mTarget) {
1201 0 : break;
1202 : }
1203 0 : first = false;
1204 0 : prev = next;
1205 0 : next = next->mNext;
1206 : }
1207 : // We don't even have the assertion, so just bail.
1208 0 : if (!next)
1209 0 : return NS_OK;
1210 :
1211 0 : as = next;
1212 :
1213 0 : if (first) {
1214 0 : root->u.hash.mPropertyHash->RawRemove(hdr);
1215 :
1216 0 : if (next && next->mNext) {
1217 : PLDHashEntryHdr* hdr =
1218 0 : root->u.hash.mPropertyHash->Add(aProperty,
1219 0 : mozilla::fallible);
1220 0 : if (hdr) {
1221 0 : Entry* entry = static_cast<Entry*>(hdr);
1222 0 : entry->mNode = aProperty;
1223 0 : entry->mAssertions = next->mNext;
1224 0 : }
1225 : }
1226 : else {
1227 : // If this second-level hash empties out, clean it up.
1228 0 : if (!root->u.hash.mPropertyHash->EntryCount()) {
1229 0 : root->Release();
1230 0 : SetForwardArcs(aSource, nullptr);
1231 : }
1232 : }
1233 : }
1234 : else {
1235 0 : prev->mNext = next->mNext;
1236 : }
1237 : }
1238 : else
1239 : {
1240 3 : while (next) {
1241 : // check target first as its most unique
1242 2 : if (aTarget == next->u.as.mTarget) {
1243 1 : if (aProperty == next->u.as.mProperty) {
1244 1 : if (prev == next) {
1245 0 : SetForwardArcs(aSource, next->mNext);
1246 : } else {
1247 1 : prev->mNext = next->mNext;
1248 : }
1249 1 : as = next;
1250 1 : break;
1251 : }
1252 : }
1253 :
1254 1 : prev = next;
1255 1 : next = next->mNext;
1256 : }
1257 : }
1258 : // We don't even have the assertion, so just bail.
1259 1 : if (!as)
1260 0 : return NS_OK;
1261 :
1262 : #ifdef DEBUG
1263 1 : bool foundReverseArc = false;
1264 : #endif
1265 :
1266 1 : next = prev = GetReverseArcs(aTarget);
1267 1 : while (next) {
1268 1 : if (next == as) {
1269 1 : if (prev == next) {
1270 1 : SetReverseArcs(aTarget, next->u.as.mInvNext);
1271 : } else {
1272 0 : prev->u.as.mInvNext = next->u.as.mInvNext;
1273 : }
1274 : #ifdef DEBUG
1275 1 : foundReverseArc = true;
1276 : #endif
1277 1 : break;
1278 : }
1279 0 : prev = next;
1280 0 : next = next->u.as.mInvNext;
1281 : }
1282 :
1283 : #ifdef DEBUG
1284 1 : NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
1285 : #endif
1286 :
1287 : // Unlink, and release the datasource's reference
1288 1 : as->mNext = as->u.as.mInvNext = nullptr;
1289 1 : as->Release();
1290 :
1291 1 : return NS_OK;
1292 : }
1293 :
1294 : NS_IMETHODIMP
1295 1 : InMemoryDataSource::Unassert(nsIRDFResource* aSource,
1296 : nsIRDFResource* aProperty,
1297 : nsIRDFNode* aTarget)
1298 : {
1299 1 : NS_PRECONDITION(aSource != nullptr, "null ptr");
1300 1 : if (! aSource)
1301 0 : return NS_ERROR_NULL_POINTER;
1302 :
1303 1 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
1304 1 : if (! aProperty)
1305 0 : return NS_ERROR_NULL_POINTER;
1306 :
1307 1 : NS_PRECONDITION(aTarget != nullptr, "null ptr");
1308 1 : if (! aTarget)
1309 0 : return NS_ERROR_NULL_POINTER;
1310 :
1311 1 : if (mReadCount) {
1312 0 : NS_WARNING("Writing to InMemoryDataSource during read\n");
1313 0 : return NS_RDF_ASSERTION_REJECTED;
1314 : }
1315 :
1316 : nsresult rv;
1317 :
1318 1 : rv = LockedUnassert(aSource, aProperty, aTarget);
1319 1 : if (NS_FAILED(rv)) return rv;
1320 :
1321 : // Notify the world
1322 1 : for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1323 0 : nsIRDFObserver* obs = mObservers[i];
1324 :
1325 : // XXX this should never happen, but it does, and we can't figure out why.
1326 0 : NS_ASSERTION(obs, "observer array corrupted!");
1327 0 : if (! obs)
1328 0 : continue;
1329 :
1330 0 : obs->OnUnassert(this, aSource, aProperty, aTarget);
1331 : // XXX ignore return value?
1332 : }
1333 :
1334 1 : return NS_RDF_ASSERTION_ACCEPTED;
1335 : }
1336 :
1337 :
1338 : NS_IMETHODIMP
1339 0 : InMemoryDataSource::Change(nsIRDFResource* aSource,
1340 : nsIRDFResource* aProperty,
1341 : nsIRDFNode* aOldTarget,
1342 : nsIRDFNode* aNewTarget)
1343 : {
1344 0 : NS_PRECONDITION(aSource != nullptr, "null ptr");
1345 0 : if (! aSource)
1346 0 : return NS_ERROR_NULL_POINTER;
1347 :
1348 0 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
1349 0 : if (! aProperty)
1350 0 : return NS_ERROR_NULL_POINTER;
1351 :
1352 0 : NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
1353 0 : if (! aOldTarget)
1354 0 : return NS_ERROR_NULL_POINTER;
1355 :
1356 0 : NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
1357 0 : if (! aNewTarget)
1358 0 : return NS_ERROR_NULL_POINTER;
1359 :
1360 0 : if (mReadCount) {
1361 0 : NS_WARNING("Writing to InMemoryDataSource during read\n");
1362 0 : return NS_RDF_ASSERTION_REJECTED;
1363 : }
1364 :
1365 : nsresult rv;
1366 :
1367 : // XXX We can implement LockedChange() if we decide that this
1368 : // is a performance bottleneck.
1369 :
1370 0 : rv = LockedUnassert(aSource, aProperty, aOldTarget);
1371 0 : if (NS_FAILED(rv)) return rv;
1372 :
1373 0 : rv = LockedAssert(aSource, aProperty, aNewTarget, true);
1374 0 : if (NS_FAILED(rv)) return rv;
1375 :
1376 : // Notify the world
1377 0 : for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1378 0 : nsIRDFObserver* obs = mObservers[i];
1379 :
1380 : // XXX this should never happen, but it does, and we can't figure out why.
1381 0 : NS_ASSERTION(obs, "observer array corrupted!");
1382 0 : if (! obs)
1383 0 : continue;
1384 :
1385 0 : obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
1386 : // XXX ignore return value?
1387 : }
1388 :
1389 0 : return NS_RDF_ASSERTION_ACCEPTED;
1390 : }
1391 :
1392 :
1393 : NS_IMETHODIMP
1394 0 : InMemoryDataSource::Move(nsIRDFResource* aOldSource,
1395 : nsIRDFResource* aNewSource,
1396 : nsIRDFResource* aProperty,
1397 : nsIRDFNode* aTarget)
1398 : {
1399 0 : NS_PRECONDITION(aOldSource != nullptr, "null ptr");
1400 0 : if (! aOldSource)
1401 0 : return NS_ERROR_NULL_POINTER;
1402 :
1403 0 : NS_PRECONDITION(aNewSource != nullptr, "null ptr");
1404 0 : if (! aNewSource)
1405 0 : return NS_ERROR_NULL_POINTER;
1406 :
1407 0 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
1408 0 : if (! aProperty)
1409 0 : return NS_ERROR_NULL_POINTER;
1410 :
1411 0 : NS_PRECONDITION(aTarget != nullptr, "null ptr");
1412 0 : if (! aTarget)
1413 0 : return NS_ERROR_NULL_POINTER;
1414 :
1415 0 : if (mReadCount) {
1416 0 : NS_WARNING("Writing to InMemoryDataSource during read\n");
1417 0 : return NS_RDF_ASSERTION_REJECTED;
1418 : }
1419 :
1420 : nsresult rv;
1421 :
1422 : // XXX We can implement LockedMove() if we decide that this
1423 : // is a performance bottleneck.
1424 :
1425 0 : rv = LockedUnassert(aOldSource, aProperty, aTarget);
1426 0 : if (NS_FAILED(rv)) return rv;
1427 :
1428 0 : rv = LockedAssert(aNewSource, aProperty, aTarget, true);
1429 0 : if (NS_FAILED(rv)) return rv;
1430 :
1431 : // Notify the world
1432 0 : for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1433 0 : nsIRDFObserver* obs = mObservers[i];
1434 :
1435 : // XXX this should never happen, but it does, and we can't figure out why.
1436 0 : NS_ASSERTION(obs, "observer array corrupted!");
1437 0 : if (! obs)
1438 0 : continue;
1439 :
1440 0 : obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
1441 : // XXX ignore return value?
1442 : }
1443 :
1444 0 : return NS_RDF_ASSERTION_ACCEPTED;
1445 : }
1446 :
1447 :
1448 : NS_IMETHODIMP
1449 0 : InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver)
1450 : {
1451 0 : NS_PRECONDITION(aObserver != nullptr, "null ptr");
1452 0 : if (! aObserver)
1453 0 : return NS_ERROR_NULL_POINTER;
1454 :
1455 0 : mObservers.AppendObject(aObserver);
1456 0 : mNumObservers = mObservers.Count();
1457 :
1458 0 : return NS_OK;
1459 : }
1460 :
1461 : NS_IMETHODIMP
1462 0 : InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver)
1463 : {
1464 0 : NS_PRECONDITION(aObserver != nullptr, "null ptr");
1465 0 : if (! aObserver)
1466 0 : return NS_ERROR_NULL_POINTER;
1467 :
1468 0 : mObservers.RemoveObject(aObserver);
1469 : // note: use Count() instead of just decrementing
1470 : // in case aObserver wasn't in list, for example
1471 0 : mNumObservers = mObservers.Count();
1472 :
1473 0 : return NS_OK;
1474 : }
1475 :
1476 : NS_IMETHODIMP
1477 0 : InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
1478 : {
1479 0 : Assertion* ass = GetReverseArcs(aNode);
1480 0 : while (ass) {
1481 0 : nsIRDFResource* elbow = ass->u.as.mProperty;
1482 0 : if (elbow == aArc) {
1483 0 : *result = true;
1484 0 : return NS_OK;
1485 : }
1486 0 : ass = ass->u.as.mInvNext;
1487 : }
1488 0 : *result = false;
1489 0 : return NS_OK;
1490 : }
1491 :
1492 : NS_IMETHODIMP
1493 0 : InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
1494 : {
1495 0 : Assertion* ass = GetForwardArcs(aSource);
1496 0 : if (ass && ass->mHashEntry) {
1497 0 : PLDHashEntryHdr* hdr = ass->u.hash.mPropertyHash->Search(aArc);
1498 0 : Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
1499 0 : if (val) {
1500 0 : *result = true;
1501 0 : return NS_OK;
1502 : }
1503 0 : ass = ass->mNext;
1504 : }
1505 0 : while (ass) {
1506 0 : nsIRDFResource* elbow = ass->u.as.mProperty;
1507 0 : if (elbow == aArc) {
1508 0 : *result = true;
1509 0 : return NS_OK;
1510 : }
1511 0 : ass = ass->mNext;
1512 : }
1513 0 : *result = false;
1514 0 : return NS_OK;
1515 : }
1516 :
1517 : NS_IMETHODIMP
1518 0 : InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
1519 : {
1520 0 : NS_PRECONDITION(aTarget != nullptr, "null ptr");
1521 0 : if (! aTarget)
1522 0 : return NS_ERROR_NULL_POINTER;
1523 :
1524 : InMemoryArcsEnumeratorImpl* result =
1525 0 : new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget);
1526 :
1527 0 : if (! result)
1528 0 : return NS_ERROR_OUT_OF_MEMORY;
1529 :
1530 0 : NS_ADDREF(result);
1531 0 : *aResult = result;
1532 :
1533 0 : return NS_OK;
1534 : }
1535 :
1536 : NS_IMETHODIMP
1537 0 : InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
1538 : {
1539 0 : NS_PRECONDITION(aSource != nullptr, "null ptr");
1540 0 : if (! aSource)
1541 0 : return NS_ERROR_NULL_POINTER;
1542 :
1543 : InMemoryArcsEnumeratorImpl* result =
1544 0 : new InMemoryArcsEnumeratorImpl(this, aSource, nullptr);
1545 :
1546 0 : if (! result)
1547 0 : return NS_ERROR_OUT_OF_MEMORY;
1548 :
1549 0 : NS_ADDREF(result);
1550 0 : *aResult = result;
1551 :
1552 0 : return NS_OK;
1553 : }
1554 :
1555 :
1556 : NS_IMETHODIMP
1557 0 : InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
1558 : {
1559 0 : nsCOMArray<nsIRDFNode> nodes;
1560 0 : nodes.SetCapacity(mForwardArcs.EntryCount());
1561 :
1562 : // Get all of our entries into an nsCOMArray
1563 0 : for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
1564 0 : auto entry = static_cast<Entry*>(iter.Get());
1565 0 : nodes.AppendObject(entry->mNode);
1566 : }
1567 0 : return NS_NewArrayEnumerator(aResult, nodes);
1568 : }
1569 :
1570 : NS_IMETHODIMP
1571 0 : InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
1572 : nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
1573 : {
1574 0 : return(NS_NewEmptyEnumerator(commands));
1575 : }
1576 :
1577 : NS_IMETHODIMP
1578 0 : InMemoryDataSource::IsCommandEnabled(nsISupports* aSources,
1579 : nsIRDFResource* aCommand,
1580 : nsISupports* aArguments,
1581 : bool* aResult)
1582 : {
1583 0 : return NS_ERROR_NOT_IMPLEMENTED;
1584 : }
1585 :
1586 : NS_IMETHODIMP
1587 0 : InMemoryDataSource::DoCommand(nsISupports* aSources,
1588 : nsIRDFResource* aCommand,
1589 : nsISupports* aArguments)
1590 : {
1591 0 : return NS_ERROR_NOT_IMPLEMENTED;
1592 : }
1593 :
1594 : NS_IMETHODIMP
1595 0 : InMemoryDataSource::BeginUpdateBatch()
1596 : {
1597 0 : for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1598 0 : nsIRDFObserver* obs = mObservers[i];
1599 0 : obs->OnBeginUpdateBatch(this);
1600 : }
1601 0 : return NS_OK;
1602 : }
1603 :
1604 : NS_IMETHODIMP
1605 0 : InMemoryDataSource::EndUpdateBatch()
1606 : {
1607 0 : for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1608 0 : nsIRDFObserver* obs = mObservers[i];
1609 0 : obs->OnEndUpdateBatch(this);
1610 : }
1611 0 : return NS_OK;
1612 : }
1613 :
1614 :
1615 :
1616 : ////////////////////////////////////////////////////////////////////////
1617 : // nsIRDFInMemoryDataSource methods
1618 :
1619 : NS_IMETHODIMP
1620 0 : InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
1621 : {
1622 0 : Assertion *as = GetForwardArcs(aSource);
1623 0 : bool haveHash = (as) ? as->mHashEntry : false;
1624 :
1625 : // if its already a hash, then nothing to do
1626 0 : if (haveHash) return(NS_OK);
1627 :
1628 : // convert aSource in forward hash into a hash
1629 0 : Assertion *hashAssertion = new Assertion(aSource);
1630 0 : NS_ASSERTION(hashAssertion, "unable to create Assertion");
1631 0 : if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY);
1632 :
1633 : // Add the datasource's owning reference.
1634 0 : hashAssertion->AddRef();
1635 :
1636 0 : Assertion *first = GetForwardArcs(aSource);
1637 0 : SetForwardArcs(aSource, hashAssertion);
1638 :
1639 : // mutate references of existing forward assertions into this hash
1640 0 : PLDHashTable *table = hashAssertion->u.hash.mPropertyHash;
1641 : Assertion *nextRef;
1642 0 : while(first) {
1643 0 : nextRef = first->mNext;
1644 0 : nsIRDFResource *prop = first->u.as.mProperty;
1645 :
1646 0 : PLDHashEntryHdr* hdr = table->Search(prop);
1647 0 : Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
1648 0 : if (val) {
1649 0 : first->mNext = val->mNext;
1650 0 : val->mNext = first;
1651 : }
1652 : else {
1653 0 : PLDHashEntryHdr* hdr = table->Add(prop, mozilla::fallible);
1654 0 : if (hdr) {
1655 0 : Entry* entry = static_cast<Entry*>(hdr);
1656 0 : entry->mNode = prop;
1657 0 : entry->mAssertions = first;
1658 0 : first->mNext = nullptr;
1659 : }
1660 : }
1661 0 : first = nextRef;
1662 : }
1663 0 : return(NS_OK);
1664 : }
1665 :
1666 :
1667 : ////////////////////////////////////////////////////////////////////////
1668 : // nsIRDFPropagatableDataSource methods
1669 : NS_IMETHODIMP
1670 0 : InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
1671 : {
1672 0 : *aPropagateChanges = mPropagateChanges;
1673 0 : return NS_OK;
1674 : }
1675 :
1676 : NS_IMETHODIMP
1677 0 : InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
1678 : {
1679 0 : mPropagateChanges = aPropagateChanges;
1680 0 : return NS_OK;
1681 : }
1682 :
1683 :
1684 : ////////////////////////////////////////////////////////////////////////
1685 : // nsIRDFPurgeableDataSource methods
1686 :
1687 : NS_IMETHODIMP
1688 0 : InMemoryDataSource::Mark(nsIRDFResource* aSource,
1689 : nsIRDFResource* aProperty,
1690 : nsIRDFNode* aTarget,
1691 : bool aTruthValue,
1692 : bool* aDidMark)
1693 : {
1694 0 : NS_PRECONDITION(aSource != nullptr, "null ptr");
1695 0 : if (! aSource)
1696 0 : return NS_ERROR_NULL_POINTER;
1697 :
1698 0 : NS_PRECONDITION(aProperty != nullptr, "null ptr");
1699 0 : if (! aProperty)
1700 0 : return NS_ERROR_NULL_POINTER;
1701 :
1702 0 : NS_PRECONDITION(aTarget != nullptr, "null ptr");
1703 0 : if (! aTarget)
1704 0 : return NS_ERROR_NULL_POINTER;
1705 :
1706 0 : Assertion *as = GetForwardArcs(aSource);
1707 0 : if (as && as->mHashEntry) {
1708 0 : PLDHashEntryHdr* hdr = as->u.hash.mPropertyHash->Search(aProperty);
1709 0 : Assertion* val = hdr ? static_cast<Entry*>(hdr)->mAssertions : nullptr;
1710 0 : while (val) {
1711 0 : if ((val->u.as.mTarget == aTarget) &&
1712 0 : (aTruthValue == (val->u.as.mTruthValue))) {
1713 :
1714 : // found it! so mark it.
1715 0 : as->Mark();
1716 0 : *aDidMark = true;
1717 :
1718 0 : LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
1719 :
1720 0 : return NS_OK;
1721 : }
1722 0 : val = val->mNext;
1723 0 : }
1724 : }
1725 0 : else for (; as != nullptr; as = as->mNext) {
1726 : // check target first as its most unique
1727 0 : if (aTarget != as->u.as.mTarget)
1728 0 : continue;
1729 :
1730 0 : if (aProperty != as->u.as.mProperty)
1731 0 : continue;
1732 :
1733 0 : if (aTruthValue != (as->u.as.mTruthValue))
1734 0 : continue;
1735 :
1736 : // found it! so mark it.
1737 0 : as->Mark();
1738 0 : *aDidMark = true;
1739 :
1740 0 : LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
1741 :
1742 0 : return NS_OK;
1743 : }
1744 :
1745 : // If we get here, we couldn't find the assertion
1746 0 : *aDidMark = false;
1747 0 : return NS_OK;
1748 : }
1749 :
1750 : NS_IMETHODIMP
1751 0 : InMemoryDataSource::Sweep()
1752 : {
1753 0 : SweepInfo info = { nullptr, &mReverseArcs };
1754 :
1755 : // Remove all the assertions, but don't notify anyone.
1756 0 : SweepForwardArcsEntries(&mForwardArcs, &info);
1757 :
1758 : // Now do the notification.
1759 0 : Assertion* as = info.mUnassertList;
1760 0 : while (as) {
1761 0 : LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue);
1762 0 : if (!(as->mHashEntry))
1763 : {
1764 0 : for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
1765 0 : nsIRDFObserver* obs = mObservers[i];
1766 : // XXXbz other loops over mObservers null-check |obs| here!
1767 0 : obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);
1768 : // XXX ignore return value?
1769 : }
1770 : }
1771 :
1772 0 : Assertion* doomed = as;
1773 0 : as = as->mNext;
1774 :
1775 : // Unlink, and release the datasource's reference
1776 0 : doomed->mNext = doomed->u.as.mInvNext = nullptr;
1777 0 : doomed->Release();
1778 : }
1779 :
1780 0 : return NS_OK;
1781 : }
1782 :
1783 :
1784 : void
1785 0 : InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
1786 : SweepInfo* aInfo)
1787 : {
1788 0 : for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
1789 0 : auto entry = static_cast<Entry*>(iter.Get());
1790 :
1791 0 : Assertion* as = entry->mAssertions;
1792 0 : if (as && (as->mHashEntry)) {
1793 : // Stuff in sub-hashes must be swept recursively (max depth: 1)
1794 0 : SweepForwardArcsEntries(as->u.hash.mPropertyHash, aInfo);
1795 :
1796 : // If the sub-hash is now empty, clean it up.
1797 0 : if (!as->u.hash.mPropertyHash->EntryCount()) {
1798 0 : as->Release();
1799 0 : iter.Remove();
1800 : }
1801 0 : continue;
1802 : }
1803 :
1804 0 : Assertion* prev = nullptr;
1805 0 : while (as) {
1806 0 : if (as->IsMarked()) {
1807 0 : prev = as;
1808 0 : as->Unmark();
1809 0 : as = as->mNext;
1810 : }
1811 : else {
1812 : // remove from the list of assertions in the datasource
1813 0 : Assertion* next = as->mNext;
1814 0 : if (prev) {
1815 0 : prev->mNext = next;
1816 : }
1817 : else {
1818 : // it's the first one. update the hashtable entry.
1819 0 : entry->mAssertions = next;
1820 : }
1821 :
1822 : // remove from the reverse arcs
1823 : PLDHashEntryHdr* hdr =
1824 0 : aInfo->mReverseArcs->Search(as->u.as.mTarget);
1825 0 : NS_ASSERTION(hdr, "no assertion in reverse arcs");
1826 :
1827 0 : Entry* rentry = static_cast<Entry*>(hdr);
1828 0 : Assertion* ras = rentry->mAssertions;
1829 0 : Assertion* rprev = nullptr;
1830 0 : while (ras) {
1831 0 : if (ras == as) {
1832 0 : if (rprev) {
1833 0 : rprev->u.as.mInvNext = ras->u.as.mInvNext;
1834 : }
1835 : else {
1836 : // it's the first one. update the hashtable entry.
1837 0 : rentry->mAssertions = ras->u.as.mInvNext;
1838 : }
1839 0 : as->u.as.mInvNext = nullptr; // for my sanity.
1840 0 : break;
1841 : }
1842 0 : rprev = ras;
1843 0 : ras = ras->u.as.mInvNext;
1844 : }
1845 :
1846 : // Wow, it was the _only_ one. Unhash it.
1847 0 : if (! rentry->mAssertions) {
1848 0 : aInfo->mReverseArcs->RawRemove(hdr);
1849 : }
1850 :
1851 : // add to the list of assertions to unassert
1852 0 : as->mNext = aInfo->mUnassertList;
1853 0 : aInfo->mUnassertList = as;
1854 :
1855 : // Advance to the next assertion
1856 0 : as = next;
1857 : }
1858 : }
1859 :
1860 : // if no more assertions exist for this resource, then unhash it.
1861 0 : if (! entry->mAssertions) {
1862 0 : iter.Remove();
1863 : }
1864 : }
1865 0 : }
1866 :
1867 : ////////////////////////////////////////////////////////////////////////
1868 : // rdfIDataSource methods
1869 :
1870 : NS_IMETHODIMP
1871 0 : InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
1872 : {
1873 : // Lock datasource against writes
1874 0 : ++mReadCount;
1875 :
1876 : // Enumerate all of our entries.
1877 0 : nsresult rv = NS_OK;
1878 0 : for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
1879 0 : auto entry = static_cast<Entry*>(iter.Get());
1880 : nsresult rv2;
1881 0 : nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv2);
1882 0 : if (NS_FAILED(rv2)) {
1883 0 : NS_WARNING("QI to nsIRDFNode failed");
1884 0 : continue;
1885 : }
1886 0 : rv = aVisitor->Visit(subject, nullptr, nullptr, true);
1887 0 : if (NS_FAILED(rv) || rv == NS_RDF_STOP_VISIT) {
1888 0 : break;
1889 : }
1890 : }
1891 :
1892 : // Unlock datasource
1893 0 : --mReadCount;
1894 :
1895 0 : return rv;
1896 : }
1897 :
1898 : NS_IMETHODIMP
1899 0 : InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor)
1900 : {
1901 : // Lock datasource against writes
1902 0 : ++mReadCount;
1903 :
1904 : // Enumerate all of our entries.
1905 0 : nsresult rv = NS_OK;
1906 0 : for (auto iter = mForwardArcs.Iter(); !iter.Done(); iter.Next()) {
1907 0 : auto entry = static_cast<Entry*>(iter.Get());
1908 :
1909 : nsresult rv2;
1910 0 : nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv2);
1911 0 : if (NS_FAILED(rv2)) {
1912 0 : NS_WARNING("QI to nsIRDFNode failed");
1913 :
1914 0 : } else if (entry->mAssertions->mHashEntry) {
1915 0 : for (auto iter = entry->mAssertions->u.hash.mPropertyHash->Iter();
1916 0 : !iter.Done();
1917 0 : iter.Next()) {
1918 0 : auto entry = static_cast<Entry*>(iter.Get());
1919 0 : Assertion* assertion = entry->mAssertions;
1920 0 : while (assertion) {
1921 0 : NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
1922 0 : rv = aVisitor->Visit(subject, assertion->u.as.mProperty,
1923 : assertion->u.as.mTarget,
1924 0 : assertion->u.as.mTruthValue);
1925 0 : if (NS_FAILED(rv)) {
1926 0 : goto end;
1927 : }
1928 0 : if (rv == NS_RDF_STOP_VISIT) {
1929 0 : goto inner_end;
1930 : }
1931 0 : assertion = assertion->mNext;
1932 : }
1933 : }
1934 :
1935 : } else {
1936 0 : Assertion* assertion = entry->mAssertions;
1937 0 : while (assertion) {
1938 0 : NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
1939 0 : rv = aVisitor->Visit(subject, assertion->u.as.mProperty,
1940 : assertion->u.as.mTarget,
1941 0 : assertion->u.as.mTruthValue);
1942 0 : if (NS_FAILED(rv) || rv == NS_RDF_STOP_VISIT) {
1943 0 : goto end;
1944 : }
1945 0 : assertion = assertion->mNext;
1946 : }
1947 : }
1948 :
1949 : inner_end:
1950 : (void) 0;
1951 : }
1952 :
1953 : end:
1954 : // Unlock datasource
1955 0 : --mReadCount;
1956 :
1957 0 : return rv;
1958 : }
1959 :
1960 : ////////////////////////////////////////////////////////////////////////
1961 :
|