LCOV - code coverage report
Current view: top level - rdf/base - nsInMemoryDataSource.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 182 848 21.5 %
Date: 2017-07-14 16:53:18 Functions: 27 84 32.1 %
Legend: Lines: hit not hit

          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             : 

Generated by: LCOV version 1.13